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 this->path = conf.path;
33
34 this->init();
35 DEBUG("model: initialized");
36}
37
38model::~model()
39{
40 DEBUG("model: destroyed");
41}
42
43void model::init()
44{
45 // Load with assimp
46 Assimp::Importer importer;
47 const aiScene *scene =
48 importer.ReadFile(this->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 = this->path.substr(0, this->path.find_last_of('/'));
57
58 process_node(scene->mRootNode, scene);
59}
60
61void model::draw(shader::name_t shader) const
62{
63 for (unsigned int i = 0; i < meshes.size(); i++)
64 {
65 meshes[i].draw(shader);
66 }
67}
68
69void model::process_node(aiNode *node, const aiScene *scene)
70{
71 for (unsigned int i = 0; i < node->mNumMeshes; i++)
72 {
73 aiMesh *m = scene->mMeshes[node->mMeshes[i]];
74 process_mesh(m, scene);
75 }
76 for (unsigned int i = 0; i < node->mNumChildren; i++)
77 {
78 process_node(node->mChildren[i], scene);
79 }
80}
81
82void model::process_mesh(aiMesh *m, const aiScene *scene)
83{
84 std::vector<types::vertex> vertices;
85 std::vector<unsigned int> indices;
86 std::vector<std::shared_ptr<texture>> textures;
87
88 for (unsigned int i = 0; i < m->mNumVertices; i++)
89 {
90 types::vertex vertex;
91 glm::vec3 vector;
92 vector.x = m->mVertices[i].x;
93 vector.y = m->mVertices[i].y;
94 vector.z = m->mVertices[i].z;
95 vertex.position = vector;
96
97 vector.x = m->mNormals[i].x;
98 vector.y = m->mNormals[i].y;
99 vector.z = m->mNormals[i].z;
100 vertex.normal = vector;
101
102 if (m->mTextureCoords[0])
103 {
104 glm::vec2 vec;
105 vec.x = m->mTextureCoords[0][i].x;
106 vec.y = m->mTextureCoords[0][i].y;
107 vertex.tex_coords = vec;
108 }
109 else
110 vertex.tex_coords = glm::vec2(0.0f, 0.0f);
111
112 vertices.push_back(vertex);
113 }
114
115 for (unsigned int i = 0; i < m->mNumFaces; i++)
116 {
117 aiFace face = m->mFaces[i];
118 for (unsigned int j = 0; j < face.mNumIndices; j++)
119 indices.push_back(face.mIndices[j]);
120 }
121
122 aiMaterial *material = scene->mMaterials[m->mMaterialIndex];
123 std::vector<std::shared_ptr<texture>> diffuse =
124 load_material_textures(material,
125 aiTextureType_DIFFUSE,
126 "texture_diffuse");
127 textures.insert(textures.end(),
128 diffuse.begin(),
129 diffuse.end());
130
131 std::vector<std::shared_ptr<texture>> specular =
132 load_material_textures(material,
133 aiTextureType_SPECULAR,
134 "texture_specular");
135 textures.insert(textures.end(),
136 specular.begin(),
137 specular.end());
138
139 mesh me = mesh({vertices, indices, textures, this->wrapping,
140 this->filtering_min, this->filtering_mag, this->has_mipmap,
141 this->mipmap_min, this->mipmap_mag});
142 meshes.push_back(std::move(me));
143}
144
145std::vector<std::shared_ptr<texture>> model::load_material_textures(aiMaterial *mat,
146 aiTextureType type,
147 const std::string &typeName)
148{
149 std::vector<std::shared_ptr<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 std::string path = directory + "/" + std::string(str.C_Str());
156
157 for (unsigned int j = 0; j < textures_loaded.size(); j++)
158 {
159 // Do not load the same texture again
160 if (textures_loaded[j]->path == path)
161 {
162 textures.push_back(textures_loaded[j]);
163 skip = true;
164 break;
165 }
166 }
167 if (!skip)
168 {
169 texture t = texture(path, this->flip, typeName);
170 std::shared_ptr<texture> t_ptr = std::make_shared<texture>(std::move(t));
171 textures_loaded.push_back(t_ptr);
172 textures.push_back(t_ptr);
173 }
174 }
175 return textures;
176}
177
178//
179// Builder functions
180//
181
182model::builder &model::builder::path(std::string path)
183{
184 this->conf.path = path;
185 return *this;
186}
187
188model::builder &model::builder::wrapping(GLint wrapping)
189{
190 this->conf.wrapping = wrapping;
191 return *this;
192}
193
194model::builder &model::builder::filtering_min(GLint filtering_min)
195{
196 this->conf.filtering_min = filtering_min;
197 return *this;
198}
199
200model::builder &model::builder::filtering_mag(GLint filtering_mag)
201{
202 this->conf.filtering_mag = filtering_mag;
203 return *this;
204}
205
206model::builder &model::builder::has_mipmap(GLboolean has_mipmap)
207{
208 this->conf.has_mipmap = has_mipmap;
209 return *this;
210}
211
212model::builder &model::builder::mipmap_min(GLint mipmap_min)
213{
214 this->conf.mipmap_min = mipmap_min;
215 return *this;
216}
217
218model::builder &model::builder::mipmap_mag(GLint mipmap_mag)
219{
220 this->conf.mipmap_mag = mipmap_mag;
221 return *this;
222}
223
224model::builder &model::builder::flip(bool flip)
225{
226 this->conf.flip = flip;
227 return *this;
228}
229
230model model::builder::build()
231{
232 return model(this->conf);
233}
The Mesh class represents a 3D model.
Definition mesh.hpp:51
Builder class for Model.
Definition model.hpp:97
Model class.
Definition model.hpp:29
model()
Empty constructor.
Definition model.hpp:51
Shader class.
Definition shader.hpp:36
Texture class.
Definition texture.hpp:20
The Vertex struct represents a vertex of a 3D model.
Definition mesh.hpp:35