sgltk 0.6
Simple OpenGL Tool Kit
Loading...
Searching...
No Matches
model.cpp
1#include "model.h"
2
3#ifdef HAVE_ASSIMP_H
4
5using namespace sgltk;
6
7std::vector<std::string> Model::paths = {"./"};
8
9Model::Model() {
10 scene = nullptr;
11 shader = nullptr;
12
13 view_matrix = nullptr;
14 projection_matrix = nullptr;
15
16 position_name = "pos_in";
17 normal_name = "norm_in";
18 tangent_name = "tang_in";
19 color_name = "col_in";
20 texture_coordinates_name = "tex_coord_in";
21 bone_ids_name = "bone_ids_in";
22 bone_weights_name = "bone_weights_in";
23 bone_array_name = "bone_array";
24
25 model_matrix_buf = -1;
26 normal_matrix_buf = -1;
27
28 bounding_box = {glm::vec3(0, 0, 0), glm::vec3(0, 0, 0)};
29}
30
31Model::~Model() {
32 bounding_box.clear();
33 bone_offsets.clear();
34 bones.clear();
35 bone_map.clear();
36 importer.FreeScene();
37}
38
39bool Model::load(const std::string& filename) {
40 unsigned int flags = aiProcess_GenSmoothNormals |
41 aiProcess_Triangulate |
42 aiProcess_CalcTangentSpace |
43 aiProcess_FlipUVs;
44
45 if((filename.length() > 1 && filename[0] == '/') ||
46 (filename.length() > 2 && filename[1] == ':')) {
47 scene = importer.ReadFile(filename.c_str(), flags);
48 } else {
49 for(unsigned int i = 0; i < paths.size(); i++) {
50 scene = importer.ReadFile((paths[i] + filename).c_str(), flags);
51 if(scene)
52 break;
53 }
54 }
55
56 if(!shader) {
57 std::string error = std::string("No shader specified before"
58 "loading a scene");
59 App::error_string.push_back(error);
60 throw std::runtime_error(error);
61 }
62
63 if (!scene)
64 App::error_string.push_back(std::string("Error importing ") + filename);
65
66 if(scene->mFlags==AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) {
67 App::error_string.push_back(std::string("Error importing ") +
68 filename + std::string(": ") +
69 importer.GetErrorString());
70 return false;
71 }
72
73 glob_inv_transf = glm::inverse(ai_to_glm_mat4(scene->mRootNode->mTransformation));
74
75 traverse_scene_nodes(scene->mRootNode, nullptr);
76 compute_bounding_box();
77 set_animation_speed(1.0);
78 animate(0.0f);
79 return true;
80}
81
82void Model::compute_bounding_box() {
83 for(unsigned int i = 0; i < meshes.size(); i++) {
84 glm::vec3 min = meshes[i]->bounding_box[0];
85 glm::vec3 max = meshes[i]->bounding_box[1];
86 if(min.x < bounding_box[0].x)
87 bounding_box[0].x = min.x;
88 if(min.y < bounding_box[0].y)
89 bounding_box[0].y = min.y;
90 if(min.z < bounding_box[0].z)
91 bounding_box[0].z = min.z;
92 if(max.x > bounding_box[1].x)
93 bounding_box[1].x = max.x;
94 if(max.y > bounding_box[1].y)
95 bounding_box[1].y = max.y;
96 if(max.z > bounding_box[1].z)
97 bounding_box[1].z = max.z;
98 }
99}
100
101bool Model::setup_camera(glm::mat4 *view_matrix,
102 glm::mat4 *projection_matrix) {
103 bool ret;
104 for(auto& mesh : meshes) {
105 ret = mesh->setup_camera(view_matrix, projection_matrix);
106 if(!ret)
107 return false;
108 }
109 this->view_matrix = view_matrix;
110 this->projection_matrix = projection_matrix;
111 return true;
112}
113
114bool Model::setup_camera(Camera *camera) {
115 bool ret;
116 for(auto& mesh : meshes) {
117 ret = mesh->setup_camera(camera);
118 if(!ret)
119 return false;
120 }
121 view_matrix = &camera->view_matrix;
122 projection_matrix = &camera->projection_matrix;
123 return true;
124}
125
126void Model::set_position_name(const std::string& name) {
127 if(name.length() == 0)
128 position_name = "pos_in";
129
130 position_name = name;
131}
132
133void Model::set_normal_name(const std::string& name) {
134 if(name.length() == 0)
135 normal_name = "norm_in";
136
137 normal_name = name;
138}
139
140void Model::set_tangent_name(const std::string& name) {
141 if(name.length() == 0)
142 tangent_name = "tang_in";
143
144 tangent_name = name;
145}
146
147void Model::set_color_name(const std::string& name) {
148 if(name.length() == 0)
149 color_name = "col_in";
150
151 color_name = name;
152}
153
154void Model::set_texture_coordinates_name(const std::string& name) {
155 if(name.length() == 0)
156 texture_coordinates_name = "tex_coord_in";
157
158 texture_coordinates_name = name;
159}
160
161void Model::set_bone_ids_name(const std::string& name) {
162 if(name.length() == 0)
163 bone_ids_name = "bone_ids_in";
164
165 bone_ids_name = name;
166}
167
168void Model::set_bone_weights_name(const std::string& name) {
169 if(name.length() == 0)
170 bone_weights_name = "bone_weights_in";
171
172 bone_weights_name = name;
173}
174
175void sgltk::Model::set_bone_array_name(const std::string& name) {
176 if(name.length() == 0)
177 bone_array_name = "bone_array";
178
179 bone_array_name = name;
180}
181
182void Model::setup_shader(Shader *shader) {
183 this->shader = shader;
184 for(std::unique_ptr<Mesh>& mesh : meshes) {
185 mesh->setup_shader(shader);
186 set_vertex_attribute(mesh);
187 }
188}
189
190void Model::set_vertex_attribute(std::unique_ptr<Mesh>& mesh) {
191 unsigned int buf = 0;
192 mesh->set_vertex_attribute(position_name, buf++, 4, GL_FLOAT, 0, 0);
193 mesh->set_vertex_attribute(normal_name, buf++, 3, GL_FLOAT, 0, 0);
194 mesh->set_vertex_attribute(tangent_name, buf++, 4, GL_FLOAT, 0, 0);
195 mesh->set_vertex_attribute(bone_ids_name, buf++, BONES_PER_VERTEX, GL_INT, 0, 0);
196 mesh->set_vertex_attribute(bone_weights_name, buf++, BONES_PER_VERTEX, GL_FLOAT, 0, 0);
197
198 if(mesh->num_uv) {
199 for(unsigned int i = 0; i < mesh->num_uv; i++) {
200 mesh->set_vertex_attribute(
201 texture_coordinates_name + std::to_string(i),
202 buf++, 3, GL_FLOAT, 0,
203 (void *)(long)(i * mesh->num_vertices));
204 }
205 }
206 if(mesh->num_col) {
207 for(unsigned int i = 0; i < mesh->num_col; i++) {
208 mesh->set_vertex_attribute(
209 color_name + std::to_string(i), buf++, 4, GL_FLOAT, 0,
210 (void *)(long)(i * mesh->num_vertices));
211 }
212 }
213}
214
215void Model::traverse_scene_nodes(aiNode *start_node, aiMatrix4x4 *parent_trafo) {
216 aiMatrix4x4 trafo = start_node->mTransformation;;
217 if(parent_trafo)
218 trafo = *parent_trafo * trafo;
219
220 for(unsigned int i = 0; i < start_node->mNumMeshes; i++) {
221 auto mesh_tmp = create_mesh(start_node->mMeshes[i]);
222 mesh_tmp->model_matrix = ai_to_glm_mat4(trafo);
223
224 //if the mesh has no name, name it
225 std::string mesh_name = scene->mMeshes[start_node->mMeshes[i]]->mName.C_Str();
226 if(mesh_name.length() == 0) {
227 mesh_name = "sgltk_mesh_" + std::to_string(i);
228 }
229 mesh_map[mesh_name.c_str()] = meshes.size();
230 meshes.push_back(std::move(mesh_tmp));
231 }
232
233 for(unsigned int i = 0; i < start_node->mNumChildren; i++) {
234 traverse_scene_nodes(start_node->mChildren[i], &trafo);
235 }
236}
237
238std::unique_ptr<Mesh> Model::create_mesh(unsigned int index) {
239 aiMesh *mesh = scene->mMeshes[index];
240 unsigned int num_uv = mesh->GetNumUVChannels();
241 unsigned int num_col = mesh->GetNumColorChannels();
242 std::vector<glm::vec4> position(mesh->mNumVertices);
243 std::vector<glm::vec3> normal(mesh->mNumVertices);
244 std::vector<glm::vec4> tangent(mesh->mNumVertices);
245 std::vector<int> bone_ids(mesh->mNumVertices * BONES_PER_VERTEX);
246 std::vector<float> bone_weights(mesh->mNumVertices * BONES_PER_VERTEX, 0.0);
247 std::vector<std::vector<glm::vec3> > tex_coord(num_uv,
248 std::vector<glm::vec3>(mesh->mNumVertices));
249 std::vector<std::vector<glm::vec4> > col(num_col,
250 std::vector<glm::vec4>(mesh->mNumVertices));
251 std::vector<unsigned int> indices;
252
253 // Vertices
254 for(unsigned int i = 0; i < mesh->mNumVertices; i++) {
255 //position
256 if(mesh->HasPositions()) {
257 position[i][0] = mesh->mVertices[i].x;
258 position[i][1] = mesh->mVertices[i].y;
259 position[i][2] = mesh->mVertices[i].z;
260 position[i][3] = 1;
261 }
262
263 //normals
264 if(mesh->HasNormals()) {
265 normal[i][0] = mesh->mNormals[i].x;
266 normal[i][1] = mesh->mNormals[i].y;
267 normal[i][2] = mesh->mNormals[i].z;
268 }
269
270 //texture coordinates
271 for(unsigned int j = 0; j < num_uv; j++) {
272 if(!mesh->HasTextureCoords(j))
273 continue;
274 tex_coord[j][i][0] = mesh->mTextureCoords[j][i].x;
275 tex_coord[j][i][1] = mesh->mTextureCoords[j][i].y;
276 tex_coord[j][i][2] = mesh->mTextureCoords[j][i].z;
277 }
278
279 //tangents
280 if(mesh->HasTangentsAndBitangents()) {
281 tangent[i][0] = mesh->mTangents[i].x;
282 tangent[i][1] = mesh->mTangents[i].y;
283 tangent[i][2] = mesh->mTangents[i].z;
284 tangent[i][3] = 1;
285 }
286
287 //color
288 for(unsigned int j = 0; j < num_col; j++) {
289 if(!mesh->HasVertexColors(j))
290 continue;
291 col[j][i][0] = mesh->mColors[j][i].r;
292 col[j][i][1] = mesh->mColors[j][i].g;
293 col[j][i][2] = mesh->mColors[j][i].b;
294 col[j][i][3] = mesh->mColors[j][i].a;
295 }
296
297 }
298
299 // Bones
300 for(unsigned int i = 0; i < mesh->mNumBones; i++) {
301 unsigned int index = 0;
302 std::string bone_name(mesh->mBones[i]->mName.data);
303 if(bone_name.length() == 0) {
304 bone_name = "sgltk_bone_" + std::to_string(i);
305 }
306
307 if(bone_map.find(bone_name) == bone_map.end()) {
308 index = bones.size();
309 bone_map[bone_name] = index;
310 bone_offsets.push_back(ai_to_glm_mat4(mesh->mBones[i]->mOffsetMatrix));
311 bones.push_back(glm::mat4(1));
312 } else {
313 index = bone_map[bone_name];
314 }
315
316 for(unsigned int j = 0; j < mesh->mBones[i]->mNumWeights; j++) {
317 unsigned int vertex_id = mesh->mBones[i]->mWeights[j].mVertexId;
318 float weight = mesh->mBones[i]->mWeights[j].mWeight;
319 for(unsigned int k = 0; k < BONES_PER_VERTEX; k++) {
320 if(bone_weights[vertex_id * BONES_PER_VERTEX + k] == 0.0) {
321 bone_ids[vertex_id * BONES_PER_VERTEX + k] = index;
322 bone_weights[vertex_id * BONES_PER_VERTEX + k] = weight;
323 break;
324 }
325 }
326 }
327 }
328
329 // Faces
330 for(unsigned int i = 0; i < mesh->mNumFaces; i++) {
331 aiFace face = mesh->mFaces[i];
332 for(unsigned int j = 0; j < face.mNumIndices; j++) {
333 indices.push_back(face.mIndices[j]);
334 }
335 }
336
337 // Mesh
338 std::unique_ptr<Mesh> mesh_tmp = std::make_unique<Mesh>();
339 mesh_tmp->num_uv = num_uv;
340 mesh_tmp->num_col = num_col;
341 mesh_tmp->attach_vertex_buffer(position);
342 mesh_tmp->attach_vertex_buffer(normal);
343 mesh_tmp->attach_vertex_buffer(tangent);
344
345 mesh_tmp->attach_vertex_buffer(bone_ids.data(),
346 bone_ids.size());
347 mesh_tmp->attach_vertex_buffer(bone_weights.data(),
348 bone_weights.size());
349
350 if(num_uv) {
351 mesh_tmp->attach_vertex_buffer(tex_coord[0].data(), mesh->mNumVertices * num_uv);
352 }
353 if(num_col) {
354 mesh_tmp->attach_vertex_buffer(col[0].data(), mesh->mNumVertices * num_col);
355 }
356 mesh_tmp->compute_bounding_box(position, 0);
357 mesh_tmp->attach_index_buffer(indices);
358 if(shader) {
359 mesh_tmp->setup_shader(shader);
360 set_vertex_attribute(mesh_tmp);
361 }
362 if(view_matrix && projection_matrix)
363 mesh_tmp->setup_camera(view_matrix, projection_matrix);
364
365 // Materials
366 aiString str;
367 std::shared_ptr<Texture> texture;
368 unsigned int num_textures;
369 aiColor4D color(0.0f, 0.0f, 0.0f, 0.0f);
370 aiMaterial* mat = scene->mMaterials[mesh->mMaterialIndex];
371
372 //wireframe or solid?
373 mesh_tmp->wireframe = false;
374 mat->Get(AI_MATKEY_ENABLE_WIREFRAME, mesh_tmp->wireframe);
375
376 //can we use back face culling?
377 mesh_tmp->twosided = true;
378 mat->Get(AI_MATKEY_TWOSIDED, mesh_tmp->twosided);
379
380 //ambient color
381 mat->Get(AI_MATKEY_COLOR_AMBIENT, color);
382 mesh_tmp->color_ambient.x = color[0];
383 mesh_tmp->color_ambient.y = color[1];
384 mesh_tmp->color_ambient.z = color[2];
385 mesh_tmp->color_ambient.w = color[3];
386
387 //diffuse color
388 mat->Get(AI_MATKEY_COLOR_DIFFUSE, color);
389 mesh_tmp->color_diffuse.x = color[0];
390 mesh_tmp->color_diffuse.y = color[1];
391 mesh_tmp->color_diffuse.z = color[2];
392 mesh_tmp->color_diffuse.w = color[3];
393
394 //specular color
395 mat->Get(AI_MATKEY_COLOR_SPECULAR, color);
396 mesh_tmp->color_specular.x = color[0];
397 mesh_tmp->color_specular.y = color[1];
398 mesh_tmp->color_specular.z = color[2];
399 mesh_tmp->color_specular.w = color[3];
400
401 mesh_tmp->shininess = 0.0;
402 mat->Get(AI_MATKEY_SHININESS, mesh_tmp->shininess);
403 mesh_tmp->shininess_strength = 1.0;
404 mat->Get(AI_MATKEY_SHININESS_STRENGTH,
405 mesh_tmp->shininess_strength);
406
407 //ambient textures
408 num_textures = mat->GetTextureCount(aiTextureType_AMBIENT);
409 for(unsigned int i = 0; i < num_textures; i++) {
410 mat->GetTexture(aiTextureType_AMBIENT, i, &str);
411 texture = Texture::find_texture(str.C_Str());
412 if(!texture) {
413 texture = std::make_shared<Texture_2d>(str.C_Str());
414 Texture::store_texture(str.C_Str(), texture);
415 }
416 mesh_tmp->auto_textures.push_back({"texture_ambient", *texture, i});
417 }
418
419 //diffuse textures
420 num_textures = mat->GetTextureCount(aiTextureType_DIFFUSE);
421 for(unsigned int i = 0; i < num_textures; i++) {
422 mat->GetTexture(aiTextureType_DIFFUSE, i, &str);
423 texture = Texture::find_texture(str.C_Str());
424 if(!texture) {
425 texture = std::make_shared<Texture_2d>(str.C_Str());
426 Texture::store_texture(str.C_Str(), texture);
427 }
428 mesh_tmp->auto_textures.push_back({"texture_diffuse", *texture, i});
429 }
430
431 //specular textures
432 num_textures = mat->GetTextureCount(aiTextureType_SPECULAR);
433 for(unsigned int i = 0; i < num_textures; i++) {
434 mat->GetTexture(aiTextureType_SPECULAR, i, &str);
435 texture = Texture::find_texture(str.C_Str());
436 if(!texture) {
437 texture = std::make_shared<Texture_2d>(str.C_Str());
438 Texture::store_texture(str.C_Str(), texture);
439 }
440 mesh_tmp->auto_textures.push_back({"texture_specular", *texture, i});
441 }
442
443 //shininess textures
444 num_textures = mat->GetTextureCount(aiTextureType_SHININESS);
445 for(unsigned int i = 0; i < num_textures; i++) {
446 mat->GetTexture(aiTextureType_SHININESS, i, &str);
447 texture = Texture::find_texture(str.C_Str());
448 if(!texture) {
449 texture = std::make_shared<Texture_2d>(str.C_Str());
450 Texture::store_texture(str.C_Str(), texture);
451 }
452 mesh_tmp->auto_textures.push_back({"texture_shininess", *texture, i});
453 }
454
455 //emissive textures
456 num_textures = mat->GetTextureCount(aiTextureType_EMISSIVE);
457 for(unsigned int i = 0; i < num_textures; i++) {
458 mat->GetTexture(aiTextureType_EMISSIVE, i, &str);
459 texture = Texture::find_texture(str.C_Str());
460 if(!texture) {
461 texture = std::make_shared<Texture_2d>(str.C_Str());
462 Texture::store_texture(str.C_Str(), texture);
463 }
464 mesh_tmp->auto_textures.push_back({"texture_emissive", *texture, i});
465 }
466
467 //normals textures
468 num_textures = mat->GetTextureCount(aiTextureType_NORMALS);
469 for(unsigned int i = 0; i < num_textures; i++) {
470 mat->GetTexture(aiTextureType_NORMALS, i, &str);
471 texture = Texture::find_texture(str.C_Str());
472 if(!texture) {
473 texture = std::make_shared<Texture_2d>(str.C_Str());
474 Texture::store_texture(str.C_Str(), texture);
475 }
476 mesh_tmp->auto_textures.push_back({"texture_normals", *texture, i});
477 }
478
479 //displacement textures
480 num_textures = mat->GetTextureCount(aiTextureType_DISPLACEMENT);
481 for(unsigned int i = 0; i < num_textures; i++) {
482 mat->GetTexture(aiTextureType_DISPLACEMENT, i, &str);
483 texture = Texture::find_texture(str.C_Str());
484 if(!texture) {
485 texture = std::make_shared<Texture_2d>(str.C_Str());
486 Texture::store_texture(str.C_Str(), texture);
487 }
488 mesh_tmp->auto_textures.push_back({"texture_displacement", *texture, i});
489 }
490
491 //opacity textures
492 num_textures = mat->GetTextureCount(aiTextureType_OPACITY);
493 for(unsigned int i = 0; i < num_textures; i++) {
494 mat->GetTexture(aiTextureType_OPACITY, i, &str);
495 texture = Texture::find_texture(str.C_Str());
496 if(!texture) {
497 texture = std::make_shared<Texture_2d>(str.C_Str());
498 Texture::store_texture(str.C_Str(), texture);
499 }
500 mesh_tmp->auto_textures.push_back({"texture_opacity", *texture, i});
501 }
502
503 //lightmap textures
504 num_textures = mat->GetTextureCount(aiTextureType_LIGHTMAP);
505 for(unsigned int i = 0; i < num_textures; i++) {
506 mat->GetTexture(aiTextureType_LIGHTMAP, i, &str);
507 texture = Texture::find_texture(str.C_Str());
508 if(!texture) {
509 texture = std::make_shared<Texture_2d>(str.C_Str());
510 Texture::store_texture(str.C_Str(), texture);
511 }
512 mesh_tmp->auto_textures.push_back({"texture_lightmap", *texture, i});
513 }
514
515 return mesh_tmp;
516}
517
518void Model::traverse_animation_nodes(float time,
519 aiNode *node,
520 glm::mat4 parent_transformation) {
521
522 std::string node_name(node->mName.data);
523 glm::mat4 node_transformation = ai_to_glm_mat4(node->mTransformation);
524 aiNodeAnim *node_animation = nullptr;
525
526 for(unsigned int i = 0; i < scene->mAnimations[0]->mNumChannels; i++) {
527 aiNodeAnim *node_anim = scene->mAnimations[0]->mChannels[i];
528 if(std::string(node_anim->mNodeName.data) == node_name) {
529 node_animation = node_anim;
530 break;
531 }
532 }
533
534 if(node_animation) {
535 aiMatrix4x4 scaling;
536 aiVector3D s_vec = interpolate_scaling(time, node_animation);
537 aiMatrix4x4::Scaling(s_vec, scaling);
538
539 aiMatrix4x4 translation;
540 aiVector3D t_vec = interpolate_translation(time, node_animation);
541 aiMatrix4x4::Translation(t_vec, translation);
542
543 aiQuaternion rot = interpolate_rotation(time, node_animation);
544 aiMatrix4x4 rotation = aiMatrix4x4(rot.GetMatrix());
545
546 node_transformation = ai_to_glm_mat4(translation * rotation * scaling);
547 }
548
549 glm::mat4 glob_transf = parent_transformation * node_transformation;
550 if(bone_map.find(node_name) != bone_map.end()) {
551 unsigned int index = bone_map[node_name];
552 bones[index] = glob_inv_transf * glob_transf * bone_offsets[index];
553 }
554 for(unsigned int i = 0; i < node->mNumChildren; i++)
555 traverse_animation_nodes(time, node->mChildren[i], glob_transf);
556}
557
558void Model::set_animation_speed(double speed) {
559 if(!scene)
560 return;
561
562 if(!scene->HasAnimations())
563 return;
564
565 if(scene->mAnimations[0]->mTicksPerSecond == 0)
566 ticks_per_second = 25.0 * speed;
567 else
568 ticks_per_second = scene->mAnimations[0]->mTicksPerSecond *
569 speed;
570}
571
572aiVector3D Model::interpolate_scaling(float time, aiNodeAnim *node) {
573
574 if(node->mNumScalingKeys == 1)
575 return node->mScalingKeys[0].mValue;
576
577 unsigned int index = 0;
578 for(unsigned int i = 0; i < node->mNumScalingKeys - 1; i++)
579 if(time < (float)node->mScalingKeys[i + 1].mTime) {
580 index = i;
581 break;
582 }
583
584 float dt = (float)(node->mScalingKeys[index + 1].mTime -
585 node->mScalingKeys[index].mTime);
586 float factor = (float)(time - node->mScalingKeys[index].mTime) / dt;
587 aiVector3D start = node->mScalingKeys[index].mValue;
588 aiVector3D end = node->mScalingKeys[index + 1].mValue;
589 return start + factor * (end - start);
590}
591
592aiVector3D Model::interpolate_translation(float time, aiNodeAnim *node) {
593 if(node->mNumPositionKeys == 1)
594 return node->mPositionKeys[0].mValue;
595
596 unsigned int index = 0;
597 for(unsigned int i = 0; i < node->mNumPositionKeys - 1; i++)
598 if(time < node->mPositionKeys[i + 1].mTime) {
599 index = i;
600 break;
601 }
602
603 float dt = (float)(node->mPositionKeys[index + 1].mTime -
604 node->mPositionKeys[index].mTime);
605 float factor = (float)(time - node->mPositionKeys[index].mTime) / dt;
606 aiVector3D start = node->mPositionKeys[index].mValue;
607 aiVector3D end = node->mPositionKeys[index + 1].mValue;
608 return start + factor * (end - start);
609}
610
611aiQuaternion Model::interpolate_rotation(float time, aiNodeAnim *node) {
612 if(node->mNumRotationKeys == 1)
613 return node->mRotationKeys[0].mValue;
614
615 unsigned int index = 0;
616 for(unsigned int i = 0; i < node->mNumRotationKeys - 1; i++)
617 if(time < node->mRotationKeys[i + 1].mTime) {
618 index = i;
619 break;
620 }
621
622 aiQuaternion rot;
623 float dt = (float)(node->mRotationKeys[index + 1].mTime -
624 node->mRotationKeys[index].mTime);
625 float factor = (float)(time - node->mRotationKeys[index].mTime) / dt;
626 aiQuaternion start = node->mRotationKeys[index].mValue;
627 aiQuaternion end = node->mRotationKeys[index + 1].mValue;
628 aiQuaternion::Interpolate(rot, start, end, factor);
629 return rot.Normalize();
630}
631
632void Model::attach_texture(const std::string& name,
633 const Texture& texture,
634 unsigned int index) {
635
636 for(const auto& mesh : meshes) {
637 mesh->attach_texture(name, texture, index);
638 }
639}
640
641void Model::set_texture_parameter(GLenum name, int parameter) {
642 for(const auto& mesh : meshes) {
643 for(const auto& tex : mesh->auto_textures) {
644 const_cast<Texture&>(std::get<1>(tex)).set_parameter(name, parameter);
645 }
646 }
647}
648
649void Model::set_texture_parameter(GLenum name, float parameter) {
650 for(const auto& mesh : meshes) {
651 for(const auto& tex : mesh->auto_textures) {
652 const_cast<Texture&>(std::get<1>(tex)).set_parameter(name, parameter);
653 }
654 }
655}
656
657bool Model::animate(float time) {
658 if(!scene)
659 return false;
660
661 if(!scene->HasAnimations())
662 return false;
663
664 glm::mat4 mat = glm::mat4(1);
665
666 double animation_time = fmod(time * ticks_per_second,
667 scene->mAnimations[0]->mDuration);
668 traverse_animation_nodes((float)animation_time, scene->mRootNode, mat);
669 int loc = shader->get_uniform_location(bone_array_name);
670 if(loc >= 0) {
671 shader->set_uniform(loc, false, bones);
672 } else {
673 return false;
674 }
675 return true;
676}
677
678void Model::setup_instanced_matrix(const std::vector<glm::mat4>& model_matrix,
679 GLenum usage) {
680 if(!shader) {
681 std::string error = std::string("No shader specified before a"
682 "call to the setup_instanced_matrix function");
683 App::error_string.push_back(error);
684 throw std::runtime_error(error);
685 }
686 for(const auto& mesh : meshes) {
687 std::vector<glm::mat3> normal_matrix(model_matrix.size());
688 for(unsigned int i = 0; i < normal_matrix.size(); i++) {
689 normal_matrix[i] = glm::mat3(glm::transpose(glm::inverse(model_matrix[i])));
690 }
691 model_matrix_buf = mesh->attach_vertex_buffer(model_matrix, usage);
692 normal_matrix_buf = mesh->attach_vertex_buffer(normal_matrix, usage);
693 int model_loc = mesh->shader->get_attribute_location(mesh->model_matrix_name);
694 int normal_loc = mesh->shader->get_attribute_location(mesh->normal_matrix_name);
695 if(model_loc >= 0) {
696 for(int i = 0; i < 4; i++) {
697 mesh->set_vertex_attribute(model_loc + i,
698 model_matrix_buf,
699 4, GL_FLOAT,
700 sizeof(glm::mat4),
701 (GLvoid *)(i * sizeof(glm::vec4)), 1);
702 }
703 }
704 if(normal_loc >= 0) {
705 for(int i = 0; i < 3; i++) {
706 mesh->set_vertex_attribute(normal_loc + i,
707 normal_matrix_buf,
708 3, GL_FLOAT,
709 sizeof(glm::mat3),
710 (GLvoid *)(i * sizeof(glm::vec3)), 1);
711 }
712 }
713 }
714}
715
716void Model::set_instanced_matrix_attributes() {
717 if(!shader) {
718 std::string error = std::string("No shader specified before a"
719 "call to the setup_instanced_matrix function");
720 App::error_string.push_back(error);
721 throw std::runtime_error(error);
722 }
723 for(const auto& mesh : meshes) {
724 int model_loc = mesh->shader->get_attribute_location(mesh->model_matrix_name);
725 int normal_loc = mesh->shader->get_attribute_location(mesh->normal_matrix_name);
726 if(model_loc >= 0) {
727 for(int i = 0; i < 4; i++) {
728 mesh->set_vertex_attribute(model_loc + i,
729 model_matrix_buf,
730 4, GL_FLOAT,
731 sizeof(glm::mat4),
732 (GLvoid *)(i * sizeof(glm::vec4)), 1);
733 }
734 }
735 if(normal_loc >= 0) {
736 for(int i = 0; i < 3; i++) {
737 mesh->set_vertex_attribute(normal_loc + i,
738 normal_matrix_buf,
739 3, GL_FLOAT,
740 sizeof(glm::mat3),
741 (GLvoid *)(i * sizeof(glm::vec3)), 1);
742 }
743 }
744 }
745}
746
747void Model::draw(const glm::mat4 *model_matrix) {
748 for(const auto& mesh : meshes) {
749 if(model_matrix) {
750 glm::mat4 matrix_tmp = *model_matrix * mesh->model_matrix;
751 mesh->draw(GL_TRIANGLES, &matrix_tmp);
752 }
753 else
754 mesh->draw(GL_TRIANGLES);
755 }
756}
757
758void Model::draw_instanced(unsigned int num_instances) {
759 if(num_instances == 0)
760 return;
761
762 for(const auto& mesh : meshes) {
763 mesh->draw_instanced(GL_TRIANGLES, 0, num_instances);
764 }
765}
766
767void Model::add_path(std::string path) {
768 if(path[path.length() - 1] != '/')
769 path += '/';
770
771 if(std::find(Model::paths.begin(), Model::paths.end(), path) == Model::paths.end())
772 Model::paths.push_back(path);
773}
774
775glm::mat4 Model::ai_to_glm_mat4(const aiMatrix4x4& in) {
776 glm::mat4 ret;
777
778 ret[0][0] = in.a1;
779 ret[0][1] = in.b1;
780 ret[0][2] = in.c1;
781 ret[0][3] = in.d1;
782
783 ret[1][0] = in.a2;
784 ret[1][1] = in.b2;
785 ret[1][2] = in.c2;
786 ret[1][3] = in.d2;
787
788 ret[2][0] = in.a3;
789 ret[2][1] = in.b3;
790 ret[2][2] = in.c3;
791 ret[2][3] = in.d3;
792
793 ret[3][0] = in.a4;
794 ret[3][1] = in.b4;
795 ret[3][2] = in.c4;
796 ret[3][3] = in.d4;
797
798 return ret;
799}
800
801#endif //HAVE_ASSIMP_H
static std::vector< std::string > error_string
A list of all error strings.
Definition app.h:151
Manages cameras.
Definition camera.h:12
glm::mat4 view_matrix
The view matrix.
Definition camera.h:17
glm::mat4 projection_matrix
The perspective projection matrix.
Definition camera.h:21
Manager shaders.
Definition shader.h:12
void set_uniform(int location, T v0)
Sets the uniform.
int get_uniform_location(const std::string &name)
Returns the location of a uniform variable.
Definition shader.cpp:199
Manages textures.
Definition texture.h:13
static std::shared_ptr< Texture > find_texture(std::string name)
Finds a texture in the internal map using the name as key.
Definition texture.cpp:40
static bool store_texture(std::string name, std::shared_ptr< Texture > texture)
Stores a texture object in an internal map using the name parameter as key (no duplicates)
Definition texture.cpp:36