Brenta Engine 1.2
Loading...
Searching...
No Matches
model.cpp
1// SPDX-License-Identifier: MIT
2// Author: Giovanni Santini
3// Mail: giovanni.santini@proton.me
4// Github: @San7o
5
6#include <brenta/logger.hpp>
7#include <brenta/model.hpp>
8#include <iostream>
9
10using namespace brenta;
11
12const model::config model::default_config = {
13 "",
14 GL_REPEAT,
15 GL_NEAREST,
16 GL_LINEAR,
17 GL_TRUE,
18 GL_LINEAR_MIPMAP_LINEAR,
19 GL_LINEAR,
20 true,
21};
22
23model::model(config conf)
24{
25 this->wrapping = conf.wrapping;
26 this->filtering_min = conf.filtering_min;
27 this->filtering_mag = conf.filtering_mag;
28 this->has_mipmap = conf.has_mipmap;
29 this->mipmap_min = conf.mipmap_min;
30 this->mipmap_mag = conf.mipmap_mag;
31 this->flip = conf.flip;
32 load_model(conf.path);
33}
34
35void model::draw(types::shader_name_t shader)
36{
37 for (unsigned int i = 0; i < meshes.size(); i++)
38 {
39 meshes[i].draw(shader);
40 }
41}
42
43void model::load_model(std::string path)
44{
45 // Load with assimp
46 Assimp::Importer importer;
47 const aiScene *scene =
48 importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs);
49
50 if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
51 {
52 ERROR("model::load_model: Could not load model with assimp: {}",
53 importer.GetErrorString());
54 return;
55 }
56 directory = path.substr(0, path.find_last_of('/'));
57
58 process_node(scene->mRootNode, scene);
59}
60
61void model::process_node(aiNode *node, const aiScene *scene)
62{
63 for (unsigned int i = 0; i < node->mNumMeshes; i++)
64 {
65 aiMesh *m = scene->mMeshes[node->mMeshes[i]];
66 meshes.push_back(process_mesh(m, scene));
67 }
68 for (unsigned int i = 0; i < node->mNumChildren; i++)
69 {
70 process_node(node->mChildren[i], scene);
71 }
72}
73
74mesh model::process_mesh(aiMesh *m, const aiScene *scene)
75{
76 std::vector<types::vertex> vertices;
77 std::vector<unsigned int> indices;
78 std::vector<types::texture> textures;
79
80 for (unsigned int i = 0; i < m->mNumVertices; i++)
81 {
82 types::vertex vertex;
83 glm::vec3 vector;
84 vector.x = m->mVertices[i].x;
85 vector.y = m->mVertices[i].y;
86 vector.z = m->mVertices[i].z;
87 vertex.position = vector;
88
89 vector.x = m->mNormals[i].x;
90 vector.y = m->mNormals[i].y;
91 vector.z = m->mNormals[i].z;
92 vertex.normal = vector;
93
94 if (m->mTextureCoords[0])
95 {
96 glm::vec2 vec;
97 vec.x = m->mTextureCoords[0][i].x;
98 vec.y = m->mTextureCoords[0][i].y;
99 vertex.tex_coords = vec;
100 }
101 else
102 vertex.tex_coords = glm::vec2(0.0f, 0.0f);
103
104 vertices.push_back(vertex);
105 }
106
107 for (unsigned int i = 0; i < m->mNumFaces; i++)
108 {
109 aiFace face = m->mFaces[i];
110 for (unsigned int j = 0; j < face.mNumIndices; j++)
111 indices.push_back(face.mIndices[j]);
112 }
113
114 aiMaterial *material = scene->mMaterials[m->mMaterialIndex];
115 std::vector<types::texture> diffuseMaps =
116 load_material_textures(material, aiTextureType_DIFFUSE, "texture_diffuse");
117 textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
118 std::vector<types::texture> specularMaps = load_material_textures(
119 material, aiTextureType_SPECULAR, "texture_specular");
120 textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());
121
122 return mesh({vertices, indices, textures, this->wrapping, this->filtering_min,
123 this->filtering_mag, this->has_mipmap, this->mipmap_min,
124 this->mipmap_mag});
125}
126
127std::vector<types::texture> model::load_material_textures(aiMaterial *mat,
128 aiTextureType type,
129 std::string typeName)
130{
131 std::vector<types::texture> textures;
132 for (unsigned int i = 0; i < mat->GetTextureCount(type); i++)
133 {
134 aiString str;
135 mat->GetTexture(type, i, &str);
136 bool skip = false;
137 for (unsigned int j = 0; j < textures_loaded.size(); j++)
138 {
139 if (std::strcmp(textures_loaded[j].path.c_str(), str.C_Str()) == 0)
140 {
141 textures.push_back(textures_loaded[j]);
142 skip = true;
143 break;
144 }
145 }
146 if (!skip)
147 {
149 std::string path = directory + "/" + std::string(str.C_Str());
150 texture.id = texture::load_texture(path, this->flip);
151 texture.type = typeName;
152 texture.path = str.C_Str();
153 textures.push_back(texture);
154 textures_loaded.push_back(texture);
155 }
156 }
157 return textures;
158}
159
160//
161// Builder functions
162//
163
164model::builder &model::builder::path(std::string path)
165{
166 this->conf.path = path;
167 return *this;
168}
169
170model::builder &model::builder::wrapping(GLint wrapping)
171{
172 this->conf.wrapping = wrapping;
173 return *this;
174}
175
176model::builder &model::builder::filtering_min(GLint filtering_min)
177{
178 this->conf.filtering_min = filtering_min;
179 return *this;
180}
181
182model::builder &model::builder::filtering_mag(GLint filtering_mag)
183{
184 this->conf.filtering_mag = filtering_mag;
185 return *this;
186}
187
188model::builder &model::builder::has_mipmap(GLboolean has_mipmap)
189{
190 this->conf.has_mipmap = has_mipmap;
191 return *this;
192}
193
194model::builder &model::builder::mipmap_min(GLint mipmap_min)
195{
196 this->conf.mipmap_min = mipmap_min;
197 return *this;
198}
199
200model::builder &model::builder::mipmap_mag(GLint mipmap_mag)
201{
202 this->conf.mipmap_mag = mipmap_mag;
203 return *this;
204}
205
206model::builder &model::builder::flip(bool flip)
207{
208 this->conf.flip = flip;
209 return *this;
210}
211
212model model::builder::build()
213{
214 return model(this->conf);
215}
The Mesh class represents a 3D model.
Definition mesh.hpp:62
Builder class for Model.
Definition model.hpp:85
Model class.
Definition model.hpp:26
model()
Empty constructor.
Definition model.hpp:47
Shader class.
Definition shader.hpp:43
Texture class.
Definition texture.hpp:20
static unsigned int load_texture(std::string path, bool flip=true)
Load a texture from a file.
Definition texture.cpp:15
The Texture struct represents a texture of a 3D model.
Definition mesh.hpp:46
The Vertex struct represents a vertex of a 3D model.
Definition mesh.hpp:32