30 #ifdef E3D_BACKEND_OPENGL
33 #elif defined E3D_BACKEND_GLES
34 # include <GLES3/gl3.h>
37 #include "eng3d/texture.hpp"
38 #include "eng3d/framebuffer.hpp"
39 #include "eng3d/utils.hpp"
40 #include "eng3d/state.hpp"
41 #include "eng3d/log.hpp"
47 #if defined E3D_BACKEND_OPENGL || defined E3D_BACKEND_GLES
53 const std::scoped_lock lock(s.tex_man.unuploaded_lock);
54 auto it = std::find_if(s.tex_man.unuploaded_textures.begin(), s.tex_man.unuploaded_textures.end(), [
this](
const auto& e) {
55 return e.texture == this;
57 if(it != s.tex_man.unuploaded_textures.end())
58 s.tex_man.unuploaded_textures.erase(it);
67 buffer = std::make_unique<uint32_t[]>(width * height);
68 if(buffer.get() ==
nullptr)
73 for(
size_t i = 0; i < width * height; i++)
74 buffer.get()[i] = ((i * 8) << 16) | (i * 16);
78 #if defined E3D_BACKEND_OPENGL || defined E3D_BACKEND_GLES
79 if(
id) delete_gputex();
81 glGenTextures(1, &
id);
82 glBindTexture(GL_TEXTURE_2D,
id);
84 const auto texture_options_to_gl = [](
const auto x) {
86 case Eng3D::TextureOptions::Format::RGBA:
88 case Eng3D::TextureOptions::Format::RED:
90 case Eng3D::TextureOptions::Format::SRGB:
92 case Eng3D::TextureOptions::Format::RGB32F:
94 case Eng3D::TextureOptions::Format::SRGB_ALPHA:
95 #ifdef E3D_BACKEND_GLES
106 GLuint internal_format = texture_options_to_gl(options.
internal_format);
108 #ifndef E3D_BACKEND_GLES
112 switch(internal_format) {
114 internal_format = GL_COMPRESSED_ALPHA;
117 internal_format = GL_COMPRESSED_LUMINANCE;
119 case GL_LUMINANCE_ALPHA:
120 internal_format = GL_COMPRESSED_LUMINANCE_ALPHA;
123 internal_format = GL_COMPRESSED_INTENSITY;
126 internal_format = GL_COMPRESSED_RED;
129 internal_format = GL_COMPRESSED_RGB;
132 internal_format = GL_COMPRESSED_RGBA;
135 internal_format = GL_COMPRESSED_SRGB;
138 internal_format = GL_COMPRESSED_SRGB_ALPHA;
141 internal_format = GL_COMPRESSED_RG;
148 GLuint format = texture_options_to_gl(options.
format);
151 switch(options.
type) {
152 case Eng3D::TextureOptions::Type::UNSIGNED_BYTE:
153 type = GL_UNSIGNED_BYTE;
161 case Eng3D::TextureOptions::Wrap::REPEAT:
164 case Eng3D::TextureOptions::Wrap::CLAMP_TO_EDGE:
165 wrap_s = GL_CLAMP_TO_EDGE;
173 case Eng3D::TextureOptions::Wrap::REPEAT:
176 case Eng3D::TextureOptions::Wrap::CLAMP_TO_EDGE:
177 wrap_t = GL_CLAMP_TO_EDGE;
183 GLuint min_filter = 0;
185 case Eng3D::TextureOptions::Filter::NEAREST:
186 min_filter = GL_NEAREST;
188 case Eng3D::TextureOptions::Filter::LINEAR:
189 min_filter = GL_LINEAR;
191 case Eng3D::TextureOptions::Filter::LINEAR_MIPMAP:
192 min_filter = GL_LINEAR_MIPMAP_LINEAR;
194 case Eng3D::TextureOptions::Filter::NEAREST_MIPMAP:
195 min_filter = GL_NEAREST_MIPMAP_NEAREST;
197 case Eng3D::TextureOptions::Filter::NEAREST_LINEAR_MIPMAP:
198 min_filter = GL_NEAREST_MIPMAP_LINEAR;
200 case Eng3D::TextureOptions::Filter::LINEAR_NEAREST_MIPMAP:
201 min_filter = GL_LINEAR_MIPMAP_NEAREST;
207 GLuint mag_filter = 0;
209 case Eng3D::TextureOptions::Filter::NEAREST:
210 mag_filter = GL_NEAREST;
212 case Eng3D::TextureOptions::Filter::LINEAR:
213 mag_filter = GL_LINEAR;
215 case Eng3D::TextureOptions::Filter::LINEAR_MIPMAP:
216 mag_filter = GL_LINEAR_MIPMAP_LINEAR;
218 case Eng3D::TextureOptions::Filter::NEAREST_MIPMAP:
219 mag_filter = GL_NEAREST_MIPMAP_NEAREST;
221 case Eng3D::TextureOptions::Filter::NEAREST_LINEAR_MIPMAP:
222 mag_filter = GL_NEAREST_MIPMAP_LINEAR;
224 case Eng3D::TextureOptions::Filter::LINEAR_NEAREST_MIPMAP:
225 mag_filter = GL_LINEAR_MIPMAP_NEAREST;
231 glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, format, type, buffer.get());
232 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s);
233 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t);
234 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
235 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
240 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED, &result);
252 case Eng3D::TextureOptions::Filter::LINEAR_MIPMAP:
253 case Eng3D::TextureOptions::Filter::NEAREST_MIPMAP:
254 case Eng3D::TextureOptions::Filter::NEAREST_LINEAR_MIPMAP:
255 case Eng3D::TextureOptions::Filter::LINEAR_NEAREST_MIPMAP:
264 void Eng3D::Texture::_upload(SDL_Surface* surface) {
265 if(surface->w == 0 || surface->h == 0)
return;
266 assert(surface->format !=
nullptr);
268 this->buffer.reset();
269 this->width =
static_cast<size_t>(surface->w);
270 this->height =
static_cast<size_t>(surface->h);
272 int colors = surface->format->BytesPerPixel;
273 #if defined E3D_BACKEND_OPENGL || defined E3D_BACKEND_GLES
274 GLuint texture_format;
277 if(surface->format->Rmask == 0x000000ff) {
278 texture_format = GL_RGBA;
281 texture_format = GL_BGRA;
283 texture_format = GL_RGBA;
288 if(surface->format->Rmask == 0x000000ff) {
289 texture_format = GL_RGB;
292 texture_format = GL_BGR;
294 texture_format = GL_RGB;
300 while(surface->pitch % alignment)
302 glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
304 int expected_pitch = (surface->w * surface->format->BytesPerPixel + alignment - 1) / alignment * alignment;
305 if(surface->pitch - expected_pitch >= alignment) {
307 glPixelStorei(GL_UNPACK_ROW_LENGTH, surface->pitch / surface->format->BytesPerPixel);
309 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
312 glGenTextures(1, &
id);
313 glBindTexture(GL_TEXTURE_2D,
id);
314 glTexImage2D(GL_TEXTURE_2D, 0, colors, surface->w, surface->h, 0, texture_format, GL_UNSIGNED_BYTE, surface->pixels);
315 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
316 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
317 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
318 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
321 SDL_FreeSurface(surface);
325 #if defined E3D_BACKEND_OPENGL || defined E3D_BACKEND_GLES
326 glBindTexture(GL_TEXTURE_2D,
id);
327 glGenerateMipmap(GL_TEXTURE_2D);
333 #if defined E3D_BACKEND_OPENGL || defined E3D_BACKEND_GLES
334 glBindTexture(GL_TEXTURE_2D,
id);
340 #if defined E3D_BACKEND_OPENGL || defined E3D_BACKEND_GLES
341 glDeleteTextures(1, &
id);
345 #define STB_IMAGE_WRITE_STATIC 1
346 #define STB_IMAGE_WRITE_IMPLEMENTATION 1
348 #include "eng3d/stb_image_write.h"
351 int channel_count = 4;
352 int stride = channel_count * width;
353 int data_size = stride * height;
355 #if defined E3D_BACKEND_OPENGL
356 glActiveTexture(GL_TEXTURE0);
357 glBindTexture(GL_TEXTURE_2D,
id);
359 uint8_t* data = (uint8_t*)malloc(data_size);
360 #if defined E3D_BACKEND_OPENGL
361 glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
363 stbi_write_png(filename.c_str(), width, height, channel_count, data, stride);
371 #if defined E3D_BACKEND_OPENGL || defined E3D_BACKEND_GLES
372 glGenTextures(1, &
id);
373 glBindTexture(GL_TEXTURE_2D_ARRAY,
id);
378 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
379 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
380 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT);
381 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT);
383 size_t p_dx = width / tiles_x;
384 size_t p_dy = height / tiles_y;
385 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, p_dx, p_dy, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
387 glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
388 glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, height);
390 for(
size_t x = 0; x < tiles_x; x++)
391 for(
size_t y = 0; y < tiles_y; y++)
392 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, x * tiles_x + y, p_dx, p_dy, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer.get() + (x * p_dy * width + y * p_dx));
396 glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
397 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
398 glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
407 const std::scoped_lock lock(this->unuploaded_lock);
409 for(
auto& request : this->unuploaded_textures) {
410 if(request.surface !=
nullptr) {
411 SDL_FreeSurface(request.surface);
412 request.surface =
nullptr;
418 if(white.get() ==
nullptr) {
419 white = std::make_shared<Eng3D::Texture>(1, 1);
420 white->buffer.get()[0] = 0xFFFFFFFF;
423 return std::shared_ptr<Eng3D::Texture>(white);
434 auto key = std::make_pair(path, options);
435 auto it = textures.find(key);
436 if(it != textures.end())
return (*it).second;
441 std::shared_ptr<Eng3D::Texture> tex;
443 tex = std::make_shared<Eng3D::Texture>(path);
445 tex = std::make_shared<Eng3D::Texture>();
449 tex->upload(options);
451 return textures[key];
455 return this->
load(asset.get() !=
nullptr ? asset->get_abs_path() :
"", options);
459 if(msg.empty())
return this->get_white();
462 auto it = text_textures.find(msg);
463 if(it != text_textures.end())
return it->second;
468 auto tex = std::make_shared<Eng3D::Texture>();
470 const SDL_Color white_color{
471 static_cast<Uint8
>(color.
r * 255.f),
static_cast<Uint8
>(color.
g * 255.f),
472 static_cast<Uint8
>(color.
b * 255.f), 0 };
473 auto* surface = TTF_RenderUTF8_Blended(
static_cast<TTF_Font*
>(font.
sdl_font), msg.c_str(), white_color);
474 if(surface ==
nullptr)
479 tex->width = surface->w;
480 tex->height = surface->h;
481 tex->upload(surface);
483 text_textures[msg] = tex;
484 return text_textures[msg];
static State & get_instance()
void upload()
Uploads the TextureArray to the driver.
void bind() const
Binds the texture to the current OpenGL context.
void to_file(const std::string &filename) override
void create_dummy()
This dummy texture helps to avoid crashes due to missing buffers or so, and also gives visual aid of ...
void delete_gputex()
Deletes the OpenGL representation of this texture.
std::shared_ptr< Eng3D::Texture > load(const std::string &path, TextureOptions options=default_options)
Finds a texture in the list of a texture manager if the texture is already in the list we load the sa...
std::shared_ptr< Eng3D::Texture > get_white()
std::shared_ptr< Eng3D::Texture > gen_text(Eng3D::TrueType::Font &font, Eng3D::Color color, const std::string &msg)
enum Eng3D::TextureOptions::Filter min_filter
enum Eng3D::TextureOptions::Wrap wrap_s
enum Eng3D::TextureOptions::Type type
enum Eng3D::TextureOptions::Format format
void debug(const std::string_view category, const std::string_view msg)
std::string translate_format(const std::string_view format, Args &&... args)
String formatter, with translation.
void load(GameState &gs, const std::string &savefile_path)
STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes)
Primitive color type used through the engine.
#define CXX_THROW(class,...)