7std::vector<std::string> Model::paths = {
"./"};
13 view_matrix =
nullptr;
14 projection_matrix =
nullptr;
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";
25 model_matrix_buf = -1;
26 normal_matrix_buf = -1;
28 bounding_box = {glm::vec3(0, 0, 0), glm::vec3(0, 0, 0)};
39bool Model::load(
const std::string& filename) {
40 unsigned int flags = aiProcess_GenSmoothNormals |
41 aiProcess_Triangulate |
42 aiProcess_CalcTangentSpace |
45 if((filename.length() > 1 && filename[0] ==
'/') ||
46 (filename.length() > 2 && filename[1] ==
':')) {
47 scene = importer.ReadFile(filename.c_str(), flags);
49 for(
unsigned int i = 0; i < paths.size(); i++) {
50 scene = importer.ReadFile((paths[i] + filename).c_str(), flags);
57 std::string error = std::string(
"No shader specified before"
60 throw std::runtime_error(error);
66 if(scene->mFlags==AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) {
68 filename + std::string(
": ") +
69 importer.GetErrorString());
73 glob_inv_transf = glm::inverse(ai_to_glm_mat4(scene->mRootNode->mTransformation));
75 traverse_scene_nodes(scene->mRootNode,
nullptr);
76 compute_bounding_box();
77 set_animation_speed(1.0);
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;
101bool Model::setup_camera(glm::mat4 *view_matrix,
102 glm::mat4 *projection_matrix) {
104 for(
auto& mesh : meshes) {
105 ret = mesh->setup_camera(view_matrix, projection_matrix);
109 this->view_matrix = view_matrix;
110 this->projection_matrix = projection_matrix;
114bool Model::setup_camera(
Camera *camera) {
116 for(
auto& mesh : meshes) {
117 ret = mesh->setup_camera(camera);
126void Model::set_position_name(
const std::string& name) {
127 if(name.length() == 0)
128 position_name =
"pos_in";
130 position_name = name;
133void Model::set_normal_name(
const std::string& name) {
134 if(name.length() == 0)
135 normal_name =
"norm_in";
140void Model::set_tangent_name(
const std::string& name) {
141 if(name.length() == 0)
142 tangent_name =
"tang_in";
147void Model::set_color_name(
const std::string& name) {
148 if(name.length() == 0)
149 color_name =
"col_in";
154void Model::set_texture_coordinates_name(
const std::string& name) {
155 if(name.length() == 0)
156 texture_coordinates_name =
"tex_coord_in";
158 texture_coordinates_name = name;
161void Model::set_bone_ids_name(
const std::string& name) {
162 if(name.length() == 0)
163 bone_ids_name =
"bone_ids_in";
165 bone_ids_name = name;
168void Model::set_bone_weights_name(
const std::string& name) {
169 if(name.length() == 0)
170 bone_weights_name =
"bone_weights_in";
172 bone_weights_name = name;
175void sgltk::Model::set_bone_array_name(
const std::string& name) {
176 if(name.length() == 0)
177 bone_array_name =
"bone_array";
179 bone_array_name = name;
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);
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);
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));
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));
215void Model::traverse_scene_nodes(aiNode *start_node, aiMatrix4x4 *parent_trafo) {
216 aiMatrix4x4 trafo = start_node->mTransformation;;
218 trafo = *parent_trafo * trafo;
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);
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);
229 mesh_map[mesh_name.c_str()] = meshes.size();
230 meshes.push_back(std::move(mesh_tmp));
233 for(
unsigned int i = 0; i < start_node->mNumChildren; i++) {
234 traverse_scene_nodes(start_node->mChildren[i], &trafo);
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;
254 for(
unsigned int i = 0; i < mesh->mNumVertices; i++) {
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;
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;
271 for(
unsigned int j = 0; j < num_uv; j++) {
272 if(!mesh->HasTextureCoords(j))
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;
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;
288 for(
unsigned int j = 0; j < num_col; j++) {
289 if(!mesh->HasVertexColors(j))
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;
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);
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));
313 index = bone_map[bone_name];
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;
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]);
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);
345 mesh_tmp->attach_vertex_buffer(bone_ids.data(),
347 mesh_tmp->attach_vertex_buffer(bone_weights.data(),
348 bone_weights.size());
351 mesh_tmp->attach_vertex_buffer(tex_coord[0].data(), mesh->mNumVertices * num_uv);
354 mesh_tmp->attach_vertex_buffer(col[0].data(), mesh->mNumVertices * num_col);
356 mesh_tmp->compute_bounding_box(position, 0);
357 mesh_tmp->attach_index_buffer(indices);
359 mesh_tmp->setup_shader(shader);
360 set_vertex_attribute(mesh_tmp);
362 if(view_matrix && projection_matrix)
363 mesh_tmp->setup_camera(view_matrix, projection_matrix);
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];
373 mesh_tmp->wireframe =
false;
374 mat->Get(AI_MATKEY_ENABLE_WIREFRAME, mesh_tmp->wireframe);
377 mesh_tmp->twosided =
true;
378 mat->Get(AI_MATKEY_TWOSIDED, mesh_tmp->twosided);
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];
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];
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];
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);
408 num_textures = mat->GetTextureCount(aiTextureType_AMBIENT);
409 for(
unsigned int i = 0; i < num_textures; i++) {
410 mat->GetTexture(aiTextureType_AMBIENT, i, &str);
413 texture = std::make_shared<Texture_2d>(str.C_Str());
416 mesh_tmp->auto_textures.push_back({
"texture_ambient", *texture, i});
420 num_textures = mat->GetTextureCount(aiTextureType_DIFFUSE);
421 for(
unsigned int i = 0; i < num_textures; i++) {
422 mat->GetTexture(aiTextureType_DIFFUSE, i, &str);
425 texture = std::make_shared<Texture_2d>(str.C_Str());
428 mesh_tmp->auto_textures.push_back({
"texture_diffuse", *texture, i});
432 num_textures = mat->GetTextureCount(aiTextureType_SPECULAR);
433 for(
unsigned int i = 0; i < num_textures; i++) {
434 mat->GetTexture(aiTextureType_SPECULAR, i, &str);
437 texture = std::make_shared<Texture_2d>(str.C_Str());
440 mesh_tmp->auto_textures.push_back({
"texture_specular", *texture, i});
444 num_textures = mat->GetTextureCount(aiTextureType_SHININESS);
445 for(
unsigned int i = 0; i < num_textures; i++) {
446 mat->GetTexture(aiTextureType_SHININESS, i, &str);
449 texture = std::make_shared<Texture_2d>(str.C_Str());
452 mesh_tmp->auto_textures.push_back({
"texture_shininess", *texture, i});
456 num_textures = mat->GetTextureCount(aiTextureType_EMISSIVE);
457 for(
unsigned int i = 0; i < num_textures; i++) {
458 mat->GetTexture(aiTextureType_EMISSIVE, i, &str);
461 texture = std::make_shared<Texture_2d>(str.C_Str());
464 mesh_tmp->auto_textures.push_back({
"texture_emissive", *texture, i});
468 num_textures = mat->GetTextureCount(aiTextureType_NORMALS);
469 for(
unsigned int i = 0; i < num_textures; i++) {
470 mat->GetTexture(aiTextureType_NORMALS, i, &str);
473 texture = std::make_shared<Texture_2d>(str.C_Str());
476 mesh_tmp->auto_textures.push_back({
"texture_normals", *texture, i});
480 num_textures = mat->GetTextureCount(aiTextureType_DISPLACEMENT);
481 for(
unsigned int i = 0; i < num_textures; i++) {
482 mat->GetTexture(aiTextureType_DISPLACEMENT, i, &str);
485 texture = std::make_shared<Texture_2d>(str.C_Str());
488 mesh_tmp->auto_textures.push_back({
"texture_displacement", *texture, i});
492 num_textures = mat->GetTextureCount(aiTextureType_OPACITY);
493 for(
unsigned int i = 0; i < num_textures; i++) {
494 mat->GetTexture(aiTextureType_OPACITY, i, &str);
497 texture = std::make_shared<Texture_2d>(str.C_Str());
500 mesh_tmp->auto_textures.push_back({
"texture_opacity", *texture, i});
504 num_textures = mat->GetTextureCount(aiTextureType_LIGHTMAP);
505 for(
unsigned int i = 0; i < num_textures; i++) {
506 mat->GetTexture(aiTextureType_LIGHTMAP, i, &str);
509 texture = std::make_shared<Texture_2d>(str.C_Str());
512 mesh_tmp->auto_textures.push_back({
"texture_lightmap", *texture, i});
518void Model::traverse_animation_nodes(
float time,
520 glm::mat4 parent_transformation) {
522 std::string node_name(node->mName.data);
523 glm::mat4 node_transformation = ai_to_glm_mat4(node->mTransformation);
524 aiNodeAnim *node_animation =
nullptr;
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;
536 aiVector3D s_vec = interpolate_scaling(time, node_animation);
537 aiMatrix4x4::Scaling(s_vec, scaling);
539 aiMatrix4x4 translation;
540 aiVector3D t_vec = interpolate_translation(time, node_animation);
541 aiMatrix4x4::Translation(t_vec, translation);
543 aiQuaternion rot = interpolate_rotation(time, node_animation);
544 aiMatrix4x4 rotation = aiMatrix4x4(rot.GetMatrix());
546 node_transformation = ai_to_glm_mat4(translation * rotation * scaling);
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];
554 for(
unsigned int i = 0; i < node->mNumChildren; i++)
555 traverse_animation_nodes(time, node->mChildren[i], glob_transf);
558void Model::set_animation_speed(
double speed) {
562 if(!scene->HasAnimations())
565 if(scene->mAnimations[0]->mTicksPerSecond == 0)
566 ticks_per_second = 25.0 * speed;
568 ticks_per_second = scene->mAnimations[0]->mTicksPerSecond *
572aiVector3D Model::interpolate_scaling(
float time, aiNodeAnim *node) {
574 if(node->mNumScalingKeys == 1)
575 return node->mScalingKeys[0].mValue;
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) {
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);
592aiVector3D Model::interpolate_translation(
float time, aiNodeAnim *node) {
593 if(node->mNumPositionKeys == 1)
594 return node->mPositionKeys[0].mValue;
596 unsigned int index = 0;
597 for(
unsigned int i = 0; i < node->mNumPositionKeys - 1; i++)
598 if(time < node->mPositionKeys[i + 1].mTime) {
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);
611aiQuaternion Model::interpolate_rotation(
float time, aiNodeAnim *node) {
612 if(node->mNumRotationKeys == 1)
613 return node->mRotationKeys[0].mValue;
615 unsigned int index = 0;
616 for(
unsigned int i = 0; i < node->mNumRotationKeys - 1; i++)
617 if(time < node->mRotationKeys[i + 1].mTime) {
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();
632void Model::attach_texture(
const std::string& name,
634 unsigned int index) {
636 for(
const auto& mesh : meshes) {
637 mesh->attach_texture(name, texture, index);
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);
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);
657bool Model::animate(
float time) {
661 if(!scene->HasAnimations())
664 glm::mat4 mat = glm::mat4(1);
666 double animation_time = fmod(time * ticks_per_second,
667 scene->mAnimations[0]->mDuration);
668 traverse_animation_nodes((
float)animation_time, scene->mRootNode, mat);
678void Model::setup_instanced_matrix(
const std::vector<glm::mat4>& model_matrix,
681 std::string error = std::string(
"No shader specified before a"
682 "call to the setup_instanced_matrix function");
684 throw std::runtime_error(error);
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])));
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);
696 for(
int i = 0; i < 4; i++) {
697 mesh->set_vertex_attribute(model_loc + i,
701 (GLvoid *)(i *
sizeof(glm::vec4)), 1);
704 if(normal_loc >= 0) {
705 for(
int i = 0; i < 3; i++) {
706 mesh->set_vertex_attribute(normal_loc + i,
710 (GLvoid *)(i *
sizeof(glm::vec3)), 1);
716void Model::set_instanced_matrix_attributes() {
718 std::string error = std::string(
"No shader specified before a"
719 "call to the setup_instanced_matrix function");
721 throw std::runtime_error(error);
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);
727 for(
int i = 0; i < 4; i++) {
728 mesh->set_vertex_attribute(model_loc + i,
732 (GLvoid *)(i *
sizeof(glm::vec4)), 1);
735 if(normal_loc >= 0) {
736 for(
int i = 0; i < 3; i++) {
737 mesh->set_vertex_attribute(normal_loc + i,
741 (GLvoid *)(i *
sizeof(glm::vec3)), 1);
747void Model::draw(
const glm::mat4 *model_matrix) {
748 for(
const auto& mesh : meshes) {
750 glm::mat4 matrix_tmp = *model_matrix * mesh->model_matrix;
751 mesh->draw(GL_TRIANGLES, &matrix_tmp);
754 mesh->draw(GL_TRIANGLES);
758void Model::draw_instanced(
unsigned int num_instances) {
759 if(num_instances == 0)
762 for(
const auto& mesh : meshes) {
763 mesh->draw_instanced(GL_TRIANGLES, 0, num_instances);
767void Model::add_path(std::string path) {
768 if(path[path.length() - 1] !=
'/')
771 if(std::find(Model::paths.begin(), Model::paths.end(), path) == Model::paths.end())
772 Model::paths.push_back(path);
775glm::mat4 Model::ai_to_glm_mat4(
const aiMatrix4x4& in) {
static std::vector< std::string > error_string
A list of all error strings.
glm::mat4 view_matrix
The view matrix.
glm::mat4 projection_matrix
The perspective projection matrix.
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.
static std::shared_ptr< Texture > find_texture(std::string name)
Finds a texture in the internal map using the name as key.
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)