Brenta Engine 1.2
Loading...
Searching...
No Matches
texture.cpp
1// SPDX-License-Identifier: MIT
2// Author: Giovanni Santini
3// Mail: giovanni.santini@proton.me
4// Github: @San7o
5
6#include <brenta/renderer/opengl/texture.hpp>
7#include <brenta/logger.hpp>
8
9#include <glad/glad.h>
10
11#include <iostream>
12#include <stb_image.h>
13#include <string>
14#include <cmath>
15
16using namespace brenta;
17
18int Texture::tot_memory = 0;
19
20Texture::Texture(const Config &conf)
21{
22 this->type = conf.type;
23 this->target = conf.target;
24 this->properties = conf.properties;
25
26 if (conf.color)
27 {
28 this->id = this->load_solid_color(conf.color.value());
29
30 // Update memory for profiling
31 this->memory = 4;
32 Texture::tot_memory += this->memory;
33
34 EVENT(Logger::Event::Lifetime,
35 "texture: created {} from color r={},g={},b={},a={}",
36 this->id, conf.color->r, conf.color->g,
37 conf.color->b, conf.color->a);
38 }
39 else
40 {
41 this->path = conf.path;
42 if (this->path == "")
43 return;
44
45 int loaded_memory = 0;
46 this->id = this->load(this->path, loaded_memory, conf.properties.flipped);
47
48 // Update memory for profiling
49 this->memory = loaded_memory;
50 Texture::tot_memory += this->memory;
51
52
53 EVENT(Logger::Event::Lifetime, "texture: created {} from path {}",
54 this->id, this->path.string());
55 }
56
57 return;
58}
59
60Texture::~Texture()
61{
62 if (this->id == 0) return;
63
64 glDeleteTextures(1, &this->id);
65
66 // Update memory for profiling
67 Texture::tot_memory -= this->memory;
68 this->memory = 0;
69
70 EVENT(Logger::Event::Lifetime, "texture: deleted {}", this->id);
71 this->id = 0;
72 return;
73}
74
75Texture::Id Texture::get_id() const
76{
77 return this->id;
78}
79
80std::filesystem::path Texture::get_path() const
81{
82 return this->path;
83}
84
85Texture::Type Texture::get_type() const
86{
87 return this->type;
88}
89
90Texture::Target Texture::get_target() const
91{
92 return this->target;
93}
94
95
96Texture::Properties &Texture::get_properties()
97{
98 return this->properties;
99}
100
101void Texture::active_texture(int texture)
102{
103 glActiveTexture(GL_TEXTURE0 + texture);
104 check_error();
105 return;
106}
107
108unsigned int Texture::load_solid_color(Color color)
109{
110 // save state
111 GLint old_active_texture, old_texture_2d;
112 glGetIntegerv(GL_ACTIVE_TEXTURE, &old_active_texture);
113 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_texture_2d);
114
115 Texture::Id texture;
116 glGenTextures(1, &texture);
117 glBindTexture(GL_TEXTURE_2D, texture);
118
119 unsigned char color_rgba[4] = {
120 (unsigned char)(color.r * 255.0f),
121 (unsigned char)(color.g * 255.0f),
122 (unsigned char)(color.b * 255.0f),
123 (unsigned char)(color.a * 255.0f)
124 };
125
126 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
127 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA,
128 GL_UNSIGNED_BYTE, &color_rgba[0]);
129 check_error();
130
131 // restore state
132 glBindTexture(GL_TEXTURE_2D, old_texture_2d);
133 glActiveTexture(old_active_texture);
134 check_error();
135
136 return texture;
137}
138
139unsigned int Texture::load(const std::filesystem::path &path,
140 int &loaded_bytes, bool flipped)
141{
142 // save state
143 GLint old_active_texture, old_texture_2d;
144 glGetIntegerv(GL_ACTIVE_TEXTURE, &old_active_texture);
145 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_texture_2d);
146
147 Texture::Id texture;
148 glGenTextures(1, &texture);
149 glBindTexture(GL_TEXTURE_2D, texture);
150 loaded_bytes = read_image(path, flipped);
151
152 // restore state
153 glBindTexture(GL_TEXTURE_2D, old_texture_2d);
154 glActiveTexture(old_active_texture);
155 check_error();
156 return texture;
157}
158
159void Texture::bind_id(Texture::Target target, Texture::Id id)
160{
161 Texture::bind_id(target, id, Texture::Properties{});
162}
163
164void Texture::bind_id(Texture::Target target, Texture::Id id,
165 const Texture::Properties &prop)
166{
167 glBindTexture(target, id);
168 check_error();
169
170 // Wrapping
171 glTexParameteri(target, GL_TEXTURE_WRAP_S, prop.wrapping);
172 glTexParameteri(target, GL_TEXTURE_WRAP_T, prop.wrapping);
173 glTexParameteri(target, GL_TEXTURE_WRAP_R, prop.wrapping);
174
175 // Filtering
176 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, prop.filtering_min);
177 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, prop.filtering_mag);
178
179 // Mipmap
180 if (!prop.has_mipmap) return;
181
182 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, prop.mipmap_min);
183 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, prop.mipmap_mag);
184
185 check_error();
186 return;
187}
188
189void Texture::bind()
190{
191 Texture::bind_id(this->target, this->id, this->properties);
192 return;
193}
194
195int Texture::read_image(const std::filesystem::path &path, bool flip)
196{
197 int width, height, nrChannels;
198 int tot_memory = 0;
199 stbi_set_flip_vertically_on_load(flip);
200 unsigned char *data = stbi_load(path.string().c_str(), &width,
201 &height, &nrChannels, 0);
202 if (data)
203 {
204 GLenum format = GL_RGB;
205 if (nrChannels == 1)
206 format = GL_RED;
207 else if (nrChannels == 3)
208 format = GL_RGB;
209 else if (nrChannels == 4)
210 format = GL_RGBA;
211
212 glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format,
213 GL_UNSIGNED_BYTE, data);
214 glGenerateMipmap(GL_TEXTURE_2D);
215 check_error();
216
217 // Update memory for profiling
218 tot_memory += nrChannels * width * height;
219 }
220 else
221 {
222 ERROR("Texture::read_image: failed to load texture at location: {}",
223 path.string());
224 }
225 stbi_image_free(data);
226
227 return tot_memory;
228}
229
230//
231// Properties
232//
233
234
235Texture::Properties &Texture::Properties::set_wrapping(Texture::Wrapping wrapping)
236{
237 this->wrapping = wrapping;
238 return *this;
239}
240
241Texture::Properties &Texture::Properties::set_filtering_min(Texture::Filtering filtering)
242{
243 this->filtering_min = filtering;
244 return *this;
245}
246
247Texture::Properties &Texture::Properties::set_filtering_mag(Texture::Filtering filtering)
248{
249 this->filtering_mag = filtering;
250 return *this;
251}
252
253Texture::Properties &Texture::Properties::set_has_mipmap(GLboolean mipmap)
254{
255 this->has_mipmap = mipmap;
256 return *this;
257}
258
259Texture::Properties &Texture::Properties::set_mipmap_min(Texture::Filtering filtering)
260{
261 this->mipmap_min = filtering;
262 return *this;
263}
264
265Texture::Properties &Texture::Properties::set_mipmap_mag(Texture::Filtering filtering)
266{
267 this->mipmap_mag = filtering;
268 return *this;
269}
270
271Texture::Properties &Texture::Properties::set_flipped(GLboolean flipped)
272{
273 this->flipped = flipped;
274 return *this;
275}
276
277//
278// Builder
279//
280
281// Texture
282
283Texture::Builder& Texture::Builder::type(Texture::Type type)
284{
285 this->conf.type = type;
286 return *this;
287}
288
289Texture::Builder& Texture::Builder::target(Texture::Target target)
290{
291 this->conf.target = target;
292 return *this;
293}
294
295Texture::Builder& Texture::Builder::path(const std::filesystem::path& path)
296{
297 this->conf.path = path;
298 return *this;
299}
300
301Texture::Builder& Texture::Builder::properties(const Texture::Properties& prop)
302{
303 this->conf.properties = prop;
304 return *this;
305}
306
307Texture::Builder& Texture::Builder::color(Color color)
308{
309 this->conf.color = color;
310 return *this;
311}
312
313Texture::Builder& Texture::Builder::watch(const std::filesystem::path& path)
314{
315 this->watch_paths.push_back(path);
316 return *this;
317}
318
319Texture Texture::Builder::build()
320{
321 return Texture(this->conf);
322}
323
324tenno::vector<std::filesystem::path> Texture::Builder::get_watch_paths() const
325{
326 return this->watch_paths;
327}