6#include <brenta/renderer/model.hpp>
7#include <brenta/logger.hpp>
9#include <tenno/std_interop.hpp>
11using namespace brenta;
13Model::Model(Config &conf)
15 this->path = conf.model_path.string();
16 this->transform = conf.transform;
17 this->material = conf.material;
19 if (conf.model_path !=
"")
20 this->load(conf.texture_props);
22 for (
size_t i = 0; i < conf.meshes.size(); ++i)
24 this->meshes.push_back(tenno::move(conf.meshes[i].build()));
26 for (
auto& t : this->meshes.back().value()->textures)
27 this->textures_loaded.push_back(t);
30 EVENT(Logger::Event::Lifetime,
"model: initialized {}",
35Model::Model(Builder& builder)
37 *
this = builder.build();
42 if (this->path.string() ==
"")
return;
44 EVENT(Logger::Event::Lifetime,
"model: destroyed {}",
49void Model::draw()
const
52 this->material->apply();
54 for (
unsigned int i = 0; i < meshes.size(); i++)
63 tinyobj::ObjReaderConfig reader_config;
64 std::string path_str = path.string();
65 this->directory = path_str.substr(0, path_str.find_last_of(
'/'));
66 reader_config.mtl_search_path = this->directory;
68 tinyobj::ObjReader reader;
70 if (!reader.ParseFromFile(this->path.string(), reader_config))
72 if (!reader.Error().empty())
74 std::cerr <<
"TinyObjReader: " << reader.Error();
79 auto& attrib = reader.GetAttrib();
80 auto& shapes = reader.GetShapes();
81 auto& materials = reader.GetMaterials();
84 for (
size_t s = 0; s < shapes.size(); s++)
86 process_shape(attrib, shapes[s], tenno::from_std(materials), props);
90void Model::process_shape(
const tinyobj::attrib_t& attrib,
91 const tinyobj::shape_t& shape,
92 const tenno::vector<tinyobj::material_t>& materials,
96 std::map<int, tenno::vector<Mesh::Vertex>> per_mat_vertices;
97 std::map<int, tenno::vector<unsigned int>> per_mat_indices;
99 size_t index_offset = 0;
101 for (
size_t f = 0; f < shape.mesh.num_face_vertices.size(); f++)
103 size_t fv = size_t(shape.mesh.num_face_vertices[f]);
104 int mat_id = shape.mesh.material_ids[f];
106 for (
size_t v = 0; v < fv; v++)
108 tinyobj::index_t idx = shape.mesh.indices[index_offset + v];
113 attrib.vertices[3 * idx.vertex_index + 0],
114 attrib.vertices[3 * idx.vertex_index + 1],
115 attrib.vertices[3 * idx.vertex_index + 2]
119 if (idx.normal_index >= 0)
122 attrib.normals[3 * idx.normal_index + 0],
123 attrib.normals[3 * idx.normal_index + 1],
124 attrib.normals[3 * idx.normal_index + 2]
129 if (idx.texcoord_index >= 0)
131 vertex.tex_coords = {
132 attrib.texcoords[2 * idx.texcoord_index + 0],
133 1.0f - attrib.texcoords[2 * idx.texcoord_index + 1]
137 per_mat_vertices[mat_id].push_back(vertex);
138 per_mat_indices[mat_id].push_back(per_mat_indices[mat_id].size());
144 for (
auto const& [mat_id, verts] : per_mat_vertices)
146 tenno::vector<tenno::shared_ptr<Texture>> textures;
149 textures = load_tiny_material(materials[mat_id], props);
153 meshes.push_back(
Mesh({verts, per_mat_indices[mat_id], textures}));
157tenno::vector<tenno::shared_ptr<Texture>>
158Model::load_tiny_material(
const tinyobj::material_t& mat,
161 tenno::vector<tenno::shared_ptr<Texture>> textures;
163 auto load_tex = [&](std::string tex_name, Texture::Type type)
165 if (tex_name.empty())
return;
167 std::string full_path = this->directory +
"/" + tex_name;
170 for (
auto& loaded : textures_loaded)
172 if (loaded->get_path() == full_path)
174 textures.push_back(loaded);
183 .target(Texture::Target::Texture2D)
188 textures_loaded.push_back(t);
189 textures.push_back(t);
192 load_tex(mat.diffuse_texname, Texture::Type::Diffuse);
193 load_tex(mat.specular_texname, Texture::Type::Specular);
204 this->conf.transform = transform;
208Model::Builder &Model::Builder::material(tenno::shared_ptr<Material> material)
210 this->conf.material = material;
216 this->conf.material = tenno::make_shared<Material>(tenno::move(material));
220Model::Builder &Model::Builder::path(
const std::filesystem::path &path)
222 this->conf.model_path = path;
223 this->watch_paths.push_back(path);
229 this->conf.texture_props = props;
235 this->conf.meshes.push_back(mesh);
241 this->conf.meshes.push_back(tenno::move(mesh));
245Model::Builder &Model::Builder::meshes(
const tenno::vector<Mesh::Builder> &meshes)
247 for (
size_t i = 0; i < meshes.size(); ++i)
248 this->conf.meshes.push_back(tenno::move(meshes[i]));
252Model::Builder &Model::Builder::meshes(tenno::vector<Mesh::Builder> &&meshes)
254 for (
size_t i = 0; i < meshes.size(); ++i)
255 this->conf.meshes.push_back(meshes[i]);
259Model::Builder &Model::Builder::watch(
const std::filesystem::path& path)
261 this->watch_paths.push_back(path);
265Model Model::Builder::build()
267 return Model(this->conf);
270tenno::vector<std::filesystem::path> Model::Builder::get_watch_paths()
const
272 return this->watch_paths;