Brenta Engine 1.1
Loading...
Searching...
No Matches
model.cpp
1/*
2 * MIT License
3 *
4 * Copyright (c) 2024 Giovanni Santini
5
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 all
15 * copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 *
25 */
26
27#include "model.hpp"
28
29#include "engine_logger.hpp"
30
31#include <iostream>
32
33using namespace brenta;
34
35model::model(std::string const &path, GLint wrapping, GLint filtering_min,
36 GLint filtering_mag, GLboolean has_mipmap, GLint mipmap_min,
37 GLint mipmap_mag, bool flip)
38{
39 this->wrapping = wrapping;
40 this->filtering_min = filtering_min;
41 this->filtering_mag = filtering_mag;
42 this->has_mipmap = has_mipmap;
43 this->mipmap_min = mipmap_min;
44 this->mipmap_mag = mipmap_mag;
45 this->flip = flip;
46 load_model(path);
47}
48
49void model::draw(types::shader_name_t shader)
50{
51 for (unsigned int i = 0; i < meshes.size(); i++)
52 {
53 meshes[i].draw(shader);
54 }
55}
56
57void model::load_model(std::string path)
58{
59 /* Load with assimp */
60 Assimp::Importer importer;
61 const aiScene *scene =
62 importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs);
63
64 if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE
65 || !scene->mRootNode)
66 {
67 ERROR("Could not load model with assimp: {}", importer.GetErrorString());
68 return;
69 }
70 directory = path.substr(0, path.find_last_of('/'));
71
72 process_node(scene->mRootNode, scene);
73}
74
75void model::process_node(aiNode *node, const aiScene *scene)
76{
77 for (unsigned int i = 0; i < node->mNumMeshes; i++)
78 {
79 aiMesh *m = scene->mMeshes[node->mMeshes[i]];
80 meshes.push_back(process_mesh(m, scene));
81 }
82 for (unsigned int i = 0; i < node->mNumChildren; i++)
83 {
84 process_node(node->mChildren[i], scene);
85 }
86}
87
88mesh model::process_mesh(aiMesh *m, const aiScene *scene)
89{
90 std::vector<types::vertex> vertices;
91 std::vector<unsigned int> indices;
92 std::vector<types::texture> textures;
93
94 for (unsigned int i = 0; i < m->mNumVertices; i++)
95 {
96 types::vertex vertex;
97 glm::vec3 vector;
98 vector.x = m->mVertices[i].x;
99 vector.y = m->mVertices[i].y;
100 vector.z = m->mVertices[i].z;
101 vertex.position = vector;
102
103 vector.x = m->mNormals[i].x;
104 vector.y = m->mNormals[i].y;
105 vector.z = m->mNormals[i].z;
106 vertex.normal = vector;
107
108 if (m->mTextureCoords[0])
109 {
110 glm::vec2 vec;
111 vec.x = m->mTextureCoords[0][i].x;
112 vec.y = m->mTextureCoords[0][i].y;
113 vertex.tex_coords = vec;
114 }
115 else
116 vertex.tex_coords = glm::vec2(0.0f, 0.0f);
117
118 vertices.push_back(vertex);
119 }
120
121 for (unsigned int i = 0; i < m->mNumFaces; i++)
122 {
123 aiFace face = m->mFaces[i];
124 for (unsigned int j = 0; j < face.mNumIndices; j++)
125 indices.push_back(face.mIndices[j]);
126 }
127
128 if (m->mMaterialIndex >= 0)
129 {
130 aiMaterial *material = scene->mMaterials[m->mMaterialIndex];
131 std::vector<types::texture> diffuseMaps = load_material_textures(
132 material, aiTextureType_DIFFUSE, "texture_diffuse");
133 textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
134 std::vector<types::texture> specularMaps = load_material_textures(
135 material, aiTextureType_SPECULAR, "texture_specular");
136 textures.insert(textures.end(), specularMaps.begin(),
137 specularMaps.end());
138 }
139
140 return mesh(vertices, indices, textures, this->wrapping,
141 this->filtering_min, this->filtering_mag, this->has_mipmap,
142 this->mipmap_min, this->mipmap_mag);
143}
144
145std::vector<types::texture> model::load_material_textures(aiMaterial *mat,
146 aiTextureType type,
147 std::string typeName)
148{
149 std::vector<types::texture> textures;
150 for (unsigned int i = 0; i < mat->GetTextureCount(type); i++)
151 {
152 aiString str;
153 mat->GetTexture(type, i, &str);
154 bool skip = false;
155 for (unsigned int j = 0; j < textures_loaded.size(); j++)
156 {
157 if (std::strcmp(textures_loaded[j].path.c_str(), str.C_Str()) == 0)
158 {
159 textures.push_back(textures_loaded[j]);
160 skip = true;
161 break;
162 }
163 }
164 if (!skip)
165 {
167 std::string path = directory + "/" + std::string(str.C_Str());
169 path, this->wrapping, this->filtering_min, this->filtering_mag,
170 this->has_mipmap, this->mipmap_min, this->mipmap_mag,
171 this->flip);
172 texture.type = typeName;
173 texture.path = str.C_Str();
174 textures.push_back(texture);
175 textures_loaded.push_back(texture);
176 }
177 }
178 return textures;
179}
180
181model::builder &model::builder::set_path(std::string path)
182{
183 this->path = path;
184 return *this;
185}
186
187model::builder &model::builder::set_wrapping(GLint wrapping)
188{
189 this->wrapping = wrapping;
190 return *this;
191}
192
193model::builder &model::builder::set_filtering_min(GLint filtering_min)
194{
195 this->filtering_min = filtering_min;
196 return *this;
197}
198
199model::builder &model::builder::set_filtering_mag(GLint filtering_mag)
200{
201 this->filtering_mag = filtering_mag;
202 return *this;
203}
204
205model::builder &model::builder::set_has_mipmap(GLboolean has_hipmap)
206{
207 this->has_mipmap = has_mipmap;
208 return *this;
209}
210
211model::builder &model::builder::set_mipmap_min(GLint mipmap_min)
212{
213 this->mipmap_min = mipmap_min;
214 return *this;
215}
216
217model::builder &model::builder::set_mipmap_mag(GLint mipmap_mag)
218{
219 this->mipmap_mag = mipmap_mag;
220 return *this;
221}
222
223model::builder &model::builder::set_flip(bool flip)
224{
225 this->flip = flip;
226 return *this;
227}
228
229model model::builder::build()
230{
231 return model(this->path, this->wrapping, this->filtering_min,
232 this->filtering_mag, this->has_mipmap, this->mipmap_min,
233 this->mipmap_mag, this->flip);
234}
The Mesh class represents a 3D model.
Definition mesh.hpp:84
Builder class for Model.
Definition model.hpp:147
Model class.
Definition model.hpp:48
model()
Empty constructor.
Definition model.hpp:96
void draw(types::shader_name_t shader)
Draw the model.
Definition model.cpp:49
bool flip
If the texture should be flipped.
Definition model.hpp:89
GLint filtering_mag
Texture filtering mode.
Definition model.hpp:67
GLboolean has_mipmap
If the texture has a mipmap.
Definition model.hpp:73
GLint wrapping
Texture wrapping mode.
Definition model.hpp:55
GLint mipmap_mag
Mipmap filtering mode.
Definition model.hpp:85
GLint filtering_min
Texture filtering mode.
Definition model.hpp:61
GLint mipmap_min
Mipmap filtering mode.
Definition model.hpp:79
Shader class.
Definition shader.hpp:66
Texture class.
Definition texture.hpp:41
static unsigned int load_texture(std::string path, GLint wrapping=GL_REPEAT, GLint filtering_min=GL_NEAREST, GLint filtering_mag=GL_NEAREST, GLboolean has_mipmap=GL_TRUE, GLint mipmap_min=GL_LINEAR_MIPMAP_LINEAR, GLint mipmap_mag=GL_LINEAR, bool flip=true)
Load a texture from a file.
Definition texture.cpp:37
The Texture struct represents a texture of a 3D model.
Definition mesh.hpp:68
The Vertex struct represents a vertex of a 3D model.
Definition mesh.hpp:54