From fe18833bc64dd25e9fc2e6a3013bdcd6b2802fd1 Mon Sep 17 00:00:00 2001 From: Relintai Date: Sun, 31 Dec 2023 01:33:19 +0100 Subject: [PATCH] Moved image loading from Texture to Image and made textures use Images. --- compile_linux.sh | 20 +- game_scene.cpp | 6 +- game_scene.h | 2 + sfw/render_core/image.cpp | 68 +++- sfw/render_core/image.h | 3 + sfw/render_core/texture.cpp | 635 ++++++++++++++++++++++++++++++------ sfw/render_core/texture.h | 35 +- 7 files changed, 642 insertions(+), 127 deletions(-) diff --git a/compile_linux.sh b/compile_linux.sh index f0913db..53262cd 100755 --- a/compile_linux.sh +++ b/compile_linux.sh @@ -54,18 +54,18 @@ ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -Isfw/object -c sfw/render_cor ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -Isfw/object -c sfw/render_core/texture.cpp -o sfw/render_core/texture.o ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -Isfw/object -c sfw/render_core/image.cpp -o sfw/render_core/image.o -ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -Isfw/render_core -Isfw/render_objects -c sfw/render_objects/camera_3d.cpp -o sfw/render_objects/camera_3d.o -ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -Isfw/render_core -Isfw/render_objects -c sfw/render_objects/object_3d.cpp -o sfw/render_objects/object_3d.o -ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -Isfw/render_core -Isfw/render_objects -c sfw/render_objects/mesh_instance_3d.cpp -o sfw/render_objects/mesh_instance_3d.o +ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -Isfw/object -Isfw/render_core -Isfw/render_objects -c sfw/render_objects/camera_3d.cpp -o sfw/render_objects/camera_3d.o +ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -Isfw/object -Isfw/render_core -Isfw/render_objects -c sfw/render_objects/object_3d.cpp -o sfw/render_objects/object_3d.o +ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -Isfw/object -Isfw/render_core -Isfw/render_objects -c sfw/render_objects/mesh_instance_3d.cpp -o sfw/render_objects/mesh_instance_3d.o -ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -Isfw/render_core -Isfw/render_objects -c sfw/render_objects/camera_2d.cpp -o sfw/render_objects/camera_2d.o -ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -Isfw/render_core -Isfw/render_objects -c sfw/render_objects/mesh_instance_2d.cpp -o sfw/render_objects/mesh_instance_2d.o -ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -Isfw/render_core -Isfw/render_objects -c sfw/render_objects/object_2d.cpp -o sfw/render_objects/object_2d.o -ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -Isfw/render_core -Isfw/render_objects -c sfw/render_objects/sprite.cpp -o sfw/render_objects/sprite.o -ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -Isfw/render_core -Isfw/render_objects -c sfw/render_objects/tile_map.cpp -o sfw/render_objects/tile_map.o +ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -Isfw/object -Isfw/render_core -Isfw/render_objects -c sfw/render_objects/camera_2d.cpp -o sfw/render_objects/camera_2d.o +ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -Isfw/object -Isfw/render_core -Isfw/render_objects -c sfw/render_objects/mesh_instance_2d.cpp -o sfw/render_objects/mesh_instance_2d.o +ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -Isfw/object -Isfw/render_core -Isfw/render_objects -c sfw/render_objects/object_2d.cpp -o sfw/render_objects/object_2d.o +ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -Isfw/object -Isfw/render_core -Isfw/render_objects -c sfw/render_objects/sprite.cpp -o sfw/render_objects/sprite.o +ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -Isfw/object -Isfw/render_core -Isfw/render_objects -c sfw/render_objects/tile_map.cpp -o sfw/render_objects/tile_map.o -ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -Isfw/render_core -Isfw/render_objects -c game_scene.cpp -o game_scene.o -ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -Isfw/render_core -Isfw/render_objects -c main.cpp -o main.o +ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -Isfw/object -Isfw/render_core -Isfw/render_objects -c game_scene.cpp -o game_scene.o +ccache g++ -Wall -D_REENTRANT -g -Isfw -Isfw/core -Isfw/object -Isfw/render_core -Isfw/render_objects -c main.cpp -o main.o ccache g++ -Wall -lm -ldl -lpthread -lX11 -D_REENTRANT -g sfw/core/aabb.o sfw/core/basis.o sfw/core/color.o \ diff --git a/game_scene.cpp b/game_scene.cpp index 99a2c44..d3e4c67 100644 --- a/game_scene.cpp +++ b/game_scene.cpp @@ -136,8 +136,12 @@ GameScene::GameScene() { //float ar = static_cast(w) / static_cast(h); //camera->width = camera->height * ar; + image.instance(); + image->load_from_file("icon.png"); + texture = new Texture(); - texture->load_image("icon.png"); + //texture->load_image("icon.png"); + texture->set_image(image); //ha a textúrának van alpha csatornája: //texture->load_image("download.bmp", GL_RGBA, GL_RGBA); diff --git a/game_scene.h b/game_scene.h index d5b906e..624e898 100644 --- a/game_scene.h +++ b/game_scene.h @@ -14,6 +14,7 @@ #include "texture.h" #include "texture_material.h" #include "texture_material_2d.h" +#include "image.h" class GameScene : public Scene { public: @@ -30,6 +31,7 @@ public: bool down; */ + Ref image; Texture *texture; TextureMaterial2D *material; diff --git a/sfw/render_core/image.cpp b/sfw/render_core/image.cpp index a0296f7..c5fdd5e 100644 --- a/sfw/render_core/image.cpp +++ b/sfw/render_core/image.cpp @@ -31,12 +31,27 @@ #include "image.h" #include "error_macros.h" +#include "hash_map.h" #include "math.h" -#include "vector3.h" #include "memory.h" +#include "vector3.h" #include #include -#include "hash_map.h" + +#define STB_IMAGE_IMPLEMENTATION // stbi +#define STB_IMAGE_WRITE_IMPLEMENTATION // stbi_write +#define STB_SPRINTF_IMPLEMENTATION // stb_sprintf +#define STB_SPRINTF_NOUNALIGNED // stb_sprintf + +#include "3rd_stb_image.h" + +//{{FILE:3rd_stb_image_write.h}} +//--- +#undef freelist +#define STBTT_malloc(x, u) ((void)(u), MALLOC(x)) +#define STBTT_free(x, u) ((void)(u), FREE(x)) +#define NK_ASSERT ASSERT +#define NK_DTOA(s, n) strcpy(s, va("%f", n)) // override cos built-in nk_dtoa() will freeze while parsing UINT_MAX otherwise const char *Image::format_names[Image::FORMAT_MAX] = { "Lum8", // luminance @@ -1689,6 +1704,55 @@ int Image::get_data_size() const { return data.size(); } +void Image::load_from_file(const String &file_name, Format p_format) { + //stbi_set_flip_vertically_on_load(flags & IMAGE_FLIP ? 1 : 0); + + int img_n = 4; + + FILE *fp = fopen(file_name.utf8().get_data(), "r"); + + //case FORMAT_RF: + //case FORMAT_RGF: + //case FORMAT_RGBF: + //case FORMAT_RGBAF: + //img.pixels = stbi_loadf_from_file((const stbi_uc *)data, size, (int *)&img.x, (int *)&img.y, (int *)&img.n, n); + + int x; + int y; + int n; + + stbi_uc *pixels = stbi_load_from_file(fp, &x, &y, &n, img_n); + fclose(fp); + + ERR_FAIL_COND_MSG(!pixels, "Couldn't load image! " + file_name); + + if (n != img_n) { + memdelete(pixels); + ERR_PRINT("Couldn't load image! n != img_n"); + return; + } + + int size = x * y * get_format_pixel_size(FORMAT_RGBA8); + + { + write_lock = true; + data.resize(size); + memcpy(data.ptrw(), pixels, size); + write_lock = false; + } + + width = x; + height = y; + mipmaps = false; + format = FORMAT_RGBA8; + + memdelete(pixels); + + if (p_format != FORMAT_RGBA8) { + convert(p_format); + } +} + void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_format) { ERR_FAIL_COND_MSG(p_width <= 0, "Image width must be greater than 0."); ERR_FAIL_COND_MSG(p_height <= 0, "Image height must be greater than 0."); diff --git a/sfw/render_core/image.h b/sfw/render_core/image.h index dd90279..c4d9ff5 100644 --- a/sfw/render_core/image.h +++ b/sfw/render_core/image.h @@ -200,10 +200,13 @@ public: /** * Create a new image of a given size and format. Current image will be lost */ + void load_from_file(const String &file_name, Format p_format = FORMAT_RGBA8); + void create(int p_width, int p_height, bool p_use_mipmaps, Format p_format); void create(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector &p_data); void create(const char **p_xpm); + /** * returns true when the image is empty (0,0) in size */ diff --git a/sfw/render_core/texture.cpp b/sfw/render_core/texture.cpp index e414a50..0ad54bb 100644 --- a/sfw/render_core/texture.cpp +++ b/sfw/render_core/texture.cpp @@ -3,80 +3,515 @@ #include "memory.h" #include -#define STB_IMAGE_IMPLEMENTATION // stbi -#define STB_IMAGE_WRITE_IMPLEMENTATION // stbi_write -#define STB_SPRINTF_IMPLEMENTATION // stb_sprintf -#define STB_SPRINTF_NOUNALIGNED // stb_sprintf +/* +Ref RasterizerStorageGLES2::_get_gl_image_and_format(const Ref &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool p_force_decompress) const { + r_gl_format = 0; + Ref image = p_image; + r_compressed = false; + r_real_format = p_format; -#include "3rd_stb_image.h" + bool need_decompress = false; -//{{FILE:3rd_stb_image_write.h}} -//--- -#undef freelist -#define STBTT_malloc(x, u) ((void)(u), MALLOC(x)) -#define STBTT_free(x, u) ((void)(u), FREE(x)) -#define NK_ASSERT ASSERT -#define NK_DTOA(s, n) strcpy(s, va("%f", n)) // override cos built-in nk_dtoa() will freeze while parsing UINT_MAX otherwise + switch (p_format) { + case Image::FORMAT_L8: { + r_gl_internal_format = GL_LUMINANCE; + r_gl_format = GL_LUMINANCE; + r_gl_type = GL_UNSIGNED_BYTE; + } break; + case Image::FORMAT_LA8: { + r_gl_internal_format = GL_LUMINANCE_ALPHA; + r_gl_format = GL_LUMINANCE_ALPHA; + r_gl_type = GL_UNSIGNED_BYTE; + } break; + case Image::FORMAT_R8: { + r_gl_internal_format = GL_ALPHA; + r_gl_format = GL_ALPHA; + r_gl_type = GL_UNSIGNED_BYTE; -void Texture::image_data_load(const char *file_name, int flags) { - //stbi_set_flip_vertically_on_load(flags & IMAGE_FLIP ? 1 : 0); + } break; + case Image::FORMAT_RG8: { + ERR_PRINT("RG texture not supported, converting to RGB8."); + if (image.is_valid()) { + image->convert(Image::FORMAT_RGB8); + } + r_real_format = Image::FORMAT_RGB8; + r_gl_internal_format = GL_RGB; + r_gl_format = GL_RGB; + r_gl_type = GL_UNSIGNED_BYTE; - int img_n = 0; - //if (flags & IMAGE_R) - // n = 1; - //if (flags & IMAGE_RG) - // n = 2; - //if (flags & IMAGE_RGB) - // n = 3; - //if (flags & IMAGE_RGBA) - img_n = 4; - //if (flags & IMAGE_FLOAT) - // img.pixels = stbi_loadf_from_file((const stbi_uc *)data, size, (int *)&img.x, (int *)&img.y, (int *)&img.n, n); - //else + } break; + case Image::FORMAT_RGB8: { + r_gl_internal_format = GL_RGB; + r_gl_format = GL_RGB; + r_gl_type = GL_UNSIGNED_BYTE; - FILE *fp = fopen(file_name, "r"); + } break; + case Image::FORMAT_RGBA8: { + r_gl_format = GL_RGBA; + r_gl_internal_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; - pixels = stbi_load_from_file(fp, &x, &y, &n, img_n); + } break; + case Image::FORMAT_RGBA4444: { + r_gl_internal_format = GL_RGBA; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_SHORT_4_4_4_4; - fclose(fp); + } break; + case Image::FORMAT_RGBA5551: { + r_gl_internal_format = GL_RGB5_A1; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_SHORT_5_5_5_1; - //if (img.pixels) { - // PRINTF("Loaded image (%dx%d %.*s->%.*s)\n", img.w, img.h, img.n, "RGBA", n ? n : img.n, "RGBA"); - //} else { - // PANIC("Error loading image (%s)\n", pathfile); - //} + } break; + case Image::FORMAT_RF: { + if (!config.float_texture_supported) { + ERR_PRINT("R float texture not supported, converting to RGB8."); + if (image.is_valid()) { + image->convert(Image::FORMAT_RGB8); + } + r_real_format = Image::FORMAT_RGB8; + r_gl_internal_format = GL_RGB; + r_gl_format = GL_RGB; + r_gl_type = GL_UNSIGNED_BYTE; + } else { + r_gl_internal_format = GL_ALPHA; + r_gl_format = GL_ALPHA; + r_gl_type = GL_FLOAT; + } + } break; + case Image::FORMAT_RGF: { + ERR_PRINT("RG float texture not supported, converting to RGB8."); + if (image.is_valid()) { + image->convert(Image::FORMAT_RGB8); + } + r_real_format = Image::FORMAT_RGB8; + r_gl_internal_format = GL_RGB; + r_gl_format = GL_RGB; + r_gl_type = GL_UNSIGNED_BYTE; + } break; + case Image::FORMAT_RGBF: { + if (!config.float_texture_supported) { + ERR_PRINT("RGB float texture not supported, converting to RGB8."); + if (image.is_valid()) { + image->convert(Image::FORMAT_RGB8); + } + r_real_format = Image::FORMAT_RGB8; + r_gl_internal_format = GL_RGB; + r_gl_format = GL_RGB; + r_gl_type = GL_UNSIGNED_BYTE; + } else { + r_gl_internal_format = GL_RGB; + r_gl_format = GL_RGB; + r_gl_type = GL_FLOAT; + } + } break; + case Image::FORMAT_RGBAF: { + if (!config.float_texture_supported) { + ERR_PRINT("RGBA float texture not supported, converting to RGBA8."); + if (image.is_valid()) { + image->convert(Image::FORMAT_RGBA8); + } + r_real_format = Image::FORMAT_RGBA8; + r_gl_internal_format = GL_RGBA; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + } else { + r_gl_internal_format = GL_RGBA; + r_gl_format = GL_RGBA; + r_gl_type = GL_FLOAT; + } + } break; + case Image::FORMAT_RH: { + need_decompress = true; + } break; + case Image::FORMAT_RGH: { + need_decompress = true; + } break; + case Image::FORMAT_RGBH: { + need_decompress = true; + } break; + case Image::FORMAT_RGBAH: { + need_decompress = true; + } break; + case Image::FORMAT_RGBE9995: { + r_gl_internal_format = GL_RGB; + r_gl_format = GL_RGB; + r_gl_type = GL_UNSIGNED_BYTE; - n = img_n ? img_n : n; -} + if (image.is_valid()) { + image = image->rgbe_to_srgb(); + } -void Texture::load_image(const char *file_name, const int format, const int internal_components) { - if (pixels) { - //TODO - //memdelete(pixels); - pixels = NULL; - glDeleteTextures(1, &texture); + return image; + + } break; + case Image::FORMAT_DXT1: { + if (config.s3tc_supported) { + r_gl_internal_format = _EXT_COMPRESSED_RGBA_S3TC_DXT1_EXT; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + } else { + need_decompress = true; + } + + } break; + case Image::FORMAT_DXT3: { + if (config.s3tc_supported) { + r_gl_internal_format = _EXT_COMPRESSED_RGBA_S3TC_DXT3_EXT; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + } else { + need_decompress = true; + } + + } break; + case Image::FORMAT_DXT5: { + if (config.s3tc_supported) { + r_gl_internal_format = _EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + } else { + need_decompress = true; + } + + } break; + case Image::FORMAT_RGTC_R: { + if (config.rgtc_supported) { + r_gl_internal_format = _EXT_COMPRESSED_RED_RGTC1_EXT; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + + } else { + need_decompress = true; + } + + } break; + case Image::FORMAT_RGTC_RG: { + if (config.rgtc_supported) { + r_gl_internal_format = _EXT_COMPRESSED_RED_GREEN_RGTC2_EXT; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + } else { + need_decompress = true; + } + + } break; + case Image::FORMAT_BPTC_RGBA: { + if (config.bptc_supported) { + r_gl_internal_format = _EXT_COMPRESSED_RGBA_BPTC_UNORM; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + + } else { + need_decompress = true; + } + } break; + case Image::FORMAT_BPTC_RGBF: { + if (config.bptc_supported) { + r_gl_internal_format = _EXT_COMPRESSED_RGB_BPTC_SIGNED_FLOAT; + r_gl_format = GL_RGB; + r_gl_type = GL_FLOAT; + r_compressed = true; + } else { + need_decompress = true; + } + } break; + case Image::FORMAT_BPTC_RGBFU: { + if (config.bptc_supported) { + r_gl_internal_format = _EXT_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT; + r_gl_format = GL_RGB; + r_gl_type = GL_FLOAT; + r_compressed = true; + } else { + need_decompress = true; + } + } break; + case Image::FORMAT_PVRTC2: { + if (config.pvrtc_supported) { + r_gl_internal_format = _EXT_COMPRESSED_RGB_PVRTC_2BPPV1_IMG; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + + } else { + need_decompress = true; + } + } break; + case Image::FORMAT_PVRTC2A: { + if (config.pvrtc_supported) { + r_gl_internal_format = _EXT_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + + } else { + need_decompress = true; + } + + } break; + case Image::FORMAT_PVRTC4: { + if (config.pvrtc_supported) { + r_gl_internal_format = _EXT_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + + } else { + need_decompress = true; + } + + } break; + case Image::FORMAT_PVRTC4A: { + if (config.pvrtc_supported) { + r_gl_internal_format = _EXT_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + + } else { + need_decompress = true; + } + + } break; + case Image::FORMAT_ETC: { + if (config.etc1_supported) { + r_gl_internal_format = _EXT_ETC1_RGB8_OES; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + } else { + need_decompress = true; + } + } break; + case Image::FORMAT_ETC2_R11: { + need_decompress = true; + } break; + case Image::FORMAT_ETC2_R11S: { + need_decompress = true; + } break; + case Image::FORMAT_ETC2_RG11: { + need_decompress = true; + } break; + case Image::FORMAT_ETC2_RG11S: { + need_decompress = true; + } break; + case Image::FORMAT_ETC2_RGB8: { + need_decompress = true; + } break; + case Image::FORMAT_ETC2_RGBA8: { + need_decompress = true; + } break; + case Image::FORMAT_ETC2_RGB8A1: { + need_decompress = true; + } break; + default: { + ERR_FAIL_V(Ref()); + } } - image_data_load(file_name, 0); + if (need_decompress || p_force_decompress) { + if (!image.is_null()) { + image = image->duplicate(); + image->decompress(); + ERR_FAIL_COND_V(image->is_compressed(), image); + switch (image->get_format()) { + case Image::FORMAT_RGB8: { + r_gl_format = GL_RGB; + r_gl_internal_format = GL_RGB; + r_gl_type = GL_UNSIGNED_BYTE; + r_real_format = Image::FORMAT_RGB8; + r_compressed = false; + } break; + case Image::FORMAT_RGBA8: { + r_gl_format = GL_RGBA; + r_gl_internal_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_real_format = Image::FORMAT_RGBA8; + r_compressed = false; + } break; + default: { + image->convert(Image::FORMAT_RGBA8); + r_gl_format = GL_RGBA; + r_gl_internal_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_real_format = Image::FORMAT_RGBA8; + r_compressed = false; - if (!pixels) { - printf("Couldn't load %s.\n", file_name); + } break; + } + } + + return image; + } + + return p_image; +} +*/ + +/* + +void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref &p_image, int p_layer) { + Texture *texture = texture_owner.getornull(p_texture); + + ERR_FAIL_COND(!texture); + if (texture->target == GL_TEXTURE_3D) { + // Target is set to a 3D texture or array texture, exit early to avoid spamming errors + return; + } + ERR_FAIL_COND(!texture->active); + ERR_FAIL_COND(texture->render_target); + ERR_FAIL_COND(texture->format != p_image->get_format()); + ERR_FAIL_COND(p_image.is_null()); + ERR_FAIL_COND(texture->type == RS::TEXTURE_TYPE_EXTERNAL); + + GLenum type; + GLenum format; + GLenum internal_format; + bool compressed = false; + + if (config.keep_original_textures && !(texture->flags & RS::TEXTURE_FLAG_USED_FOR_STREAMING)) { + texture->images.write[p_layer] = p_image; + } + + Image::Format real_format; + Ref img = _get_gl_image_and_format(p_image, p_image->get_format(), texture->flags, real_format, format, internal_format, type, compressed, texture->resize_to_po2); + + if (texture->resize_to_po2) { + if (p_image->is_compressed()) { + ERR_PRINT("Texture '" + texture->path + "' is required to be a power of 2 because it uses either mipmaps or repeat, so it was decompressed. This will hurt performance and memory usage."); + } + + if (img == p_image) { + img = img->duplicate(); + } + img->resize_to_po2(false, texture->flags & RS::TEXTURE_FLAG_FILTER ? Image::INTERPOLATE_BILINEAR : Image::INTERPOLATE_NEAREST); + } + + if (config.shrink_textures_x2 && (p_image->has_mipmaps() || !p_image->is_compressed()) && !(texture->flags & RS::TEXTURE_FLAG_USED_FOR_STREAMING)) { + texture->alloc_height = MAX(1, texture->alloc_height / 2); + texture->alloc_width = MAX(1, texture->alloc_width / 2); + + if (texture->alloc_width == img->get_width() / 2 && texture->alloc_height == img->get_height() / 2) { + img->shrink_x2(); + } else if (img->get_format() <= Image::FORMAT_RGBA8) { + img->resize(texture->alloc_width, texture->alloc_height, Image::INTERPOLATE_BILINEAR); + } + } + + GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_layer] : GL_TEXTURE_2D; + + texture->data_size = img->get_data().size(); + PoolVector::Read read = img->get_data().read(); + ERR_FAIL_COND(!read.ptr()); + + gl_wrapper.gl_active_texture(GL_TEXTURE0); + glBindTexture(texture->target, texture->tex_id); + + texture->ignore_mipmaps = compressed && !img->has_mipmaps(); + + if ((texture->flags & RS::TEXTURE_FLAG_MIPMAPS) && !texture->ignore_mipmaps) { + if (texture->flags & RS::TEXTURE_FLAG_FILTER) { + glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, config.use_fast_texture_filter ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR_MIPMAP_LINEAR); + } else { + glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, config.use_fast_texture_filter ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST_MIPMAP_LINEAR); + } } else { - //image = SDL_ConvertSurfaceFormat(img, SDL_PIXELFORMAT_RGBA32, 0); - //SDL_FreeSurface(img); - - glGenTextures(1, &texture); - - texture_update(0); - - //glBindTexture(GL_TEXTURE_2D, texture); - //glTexImage2D(GL_TEXTURE_2D, 0, format, image->w, image->h, 0, internal_components, GL_UNSIGNED_BYTE, image->pixels); - //apply_filter(); + if (texture->flags & RS::TEXTURE_FLAG_FILTER) { + glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } else { + glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } } + + if (texture->flags & RS::TEXTURE_FLAG_FILTER) { + glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Linear Filtering + + } else { + glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // raw Filtering + } + + if (((texture->flags & RS::TEXTURE_FLAG_REPEAT) || (texture->flags & RS::TEXTURE_FLAG_MIRRORED_REPEAT)) && texture->target != GL_TEXTURE_CUBE_MAP) { + if (texture->flags & RS::TEXTURE_FLAG_MIRRORED_REPEAT) { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); + } else { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + } + } else { + //glTexParameterf( texture->target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE ); + glTexParameterf(texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + + if (config.use_anisotropic_filter) { + if (texture->flags & RS::TEXTURE_FLAG_ANISOTROPIC_FILTER) { + glTexParameterf(texture->target, _GL_TEXTURE_MAX_ANISOTROPY_EXT, config.anisotropic_level); + } else { + glTexParameterf(texture->target, _GL_TEXTURE_MAX_ANISOTROPY_EXT, 1); + } + } + + int mipmaps = ((texture->flags & RS::TEXTURE_FLAG_MIPMAPS) && img->has_mipmaps()) ? img->get_mipmap_count() + 1 : 1; + + int w = img->get_width(); + int h = img->get_height(); + + int tsize = 0; + + for (int i = 0; i < mipmaps; i++) { + int size, ofs; + img->get_mipmap_offset_and_size(i, ofs, size); + + if (compressed) { + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + + int bw = w; + int bh = h; + + glCompressedTexImage2D(blit_target, i, internal_format, bw, bh, 0, size, &read[ofs]); + } else { + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + if (texture->flags & RS::TEXTURE_FLAG_USED_FOR_STREAMING) { + glTexSubImage2D(blit_target, i, 0, 0, w, h, format, type, &read[ofs]); + } else { + glTexImage2D(blit_target, i, internal_format, w, h, 0, format, type, &read[ofs]); + } + } + + tsize += size; + + w = MAX(1, w >> 1); + h = MAX(1, h >> 1); + } + + info.texture_mem -= texture->total_data_size; + texture->total_data_size = tsize; + info.texture_mem += texture->total_data_size; + + // printf("texture: %i x %i - size: %i - total: %i\n", texture->width, texture->height, tsize, info.texture_mem); + + texture->stored_cube_sides |= (1 << p_layer); + + if ((texture->flags & RS::TEXTURE_FLAG_MIPMAPS) && mipmaps == 1 && !texture->ignore_mipmaps && (texture->type != RS::TEXTURE_TYPE_CUBEMAP || texture->stored_cube_sides == (1 << 6) - 1)) { + //generate mipmaps if they were requested and the image does not contain them + glGenerateMipmap(texture->target); + } + + texture->mipmaps = mipmaps; } +*/ + void Texture::texture_update(int flags) { - if (!pixels) { + if (!_image.is_valid()) { return; } @@ -92,14 +527,15 @@ void Texture::texture_update(int flags) { //GLenum pixel_storage = flags & TEXTURE_FLOAT ? GL_FLOAT : GL_UNSIGNED_BYTE; GLenum pixel_storage = GL_UNSIGNED_BYTE; //GLuint pixel_type = pixel_types[n]; - GLuint pixel_type = GL_RGBA; + GLuint pixel_type = GL_RGBA; //GLuint texel_type = t->texel_type = pixel_types[n + 5 * !!(flags & TEXTURE_FLOAT)]; - GLuint texel_type = GL_RGBA; + GLuint texel_type = GL_RGBA; + GLenum wrap = GL_CLAMP_TO_EDGE; GLenum min_filter = GL_NEAREST, mag_filter = GL_NEAREST; // GLfloat color = (flags&7)/7.f, border_color[4] = { color, color, color, 1.f }; - /* + /* if (flags & TEXTURE_BGR) if (pixel_type == GL_RGB) pixel_type = GL_BGR; @@ -112,8 +548,8 @@ void Texture::texture_update(int flags) { if (flags & TEXTURE_SRGB) if (texel_type == GL_RGBA) texel_type = GL_SRGB_ALPHA; // GL_SRGB8_ALPHA8 ? - */ - /* + */ + /* if (flags & TEXTURE_BC1) texel_type = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; if (flags & TEXTURE_BC2) @@ -133,39 +569,26 @@ void Texture::texture_update(int flags) { min_filter = flags & TEXTURE_LINEAR ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_LINEAR; // : GL_LINEAR_MIPMAP_NEAREST; maybe? if (flags & TEXTURE_MIPMAPS) mag_filter = flags & TEXTURE_LINEAR ? GL_LINEAR : GL_NEAREST; - */ - -#if 0 - if( 0 ) { // flags & TEXTURE_PREMULTIPLY_ALPHA ) - uint8_t *p = pixels; - if(n == 2) for( unsigned i = 0; i < 2*w*h; i += 2 ) { - p[i] = (p[i] * p[i+1] + 128) >> 8; - } - if(n == 4) for( unsigned i = 0; i < 4*w*h; i += 4 ) { - p[i+0] = (p[i+0] * p[i+3] + 128) >> 8; - p[i+1] = (p[i+1] * p[i+3] + 128) >> 8; - p[i+2] = (p[i+2] * p[i+3] + 128) >> 8; - } - } -#endif + */ //GLenum texture_type = t->flags & TEXTURE_ARRAY ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D; // @fixme: test GL_TEXTURE_2D_ARRAY - GLenum texture_type = GL_TEXTURE_2D; // @fixme: test GL_TEXTURE_2D_ARRAY + GLenum texture_type = GL_TEXTURE_2D; // @fixme: test GL_TEXTURE_2D_ARRAY //glPixelStorei( GL_UNPACK_ALIGNMENT, n < 4 ? 1 : 4 ); // for framebuffer reading //glActiveTexture(GL_TEXTURE0 + (flags&7)); glBindTexture(texture_type, texture); - glTexImage2D(texture_type, 0, texel_type, w, h, 0, pixel_type, pixel_storage, pixels); + //glTexImage2D(texture_type, 0, texel_type, w, h, 0, pixel_type, pixel_storage, pixels); + glTexParameteri(texture_type, GL_TEXTURE_WRAP_S, wrap); glTexParameteri(texture_type, GL_TEXTURE_WRAP_T, wrap); glTexParameteri(texture_type, GL_TEXTURE_MIN_FILTER, min_filter); glTexParameteri(texture_type, GL_TEXTURE_MAG_FILTER, mag_filter); -#if 0 // only for sampler2DShadow - if( flags & TEXTURE_DEPTH ) glTexParameteri(texture_type, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - if( flags & TEXTURE_DEPTH ) glTexParameteri(texture_type, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); -#endif + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexImage2D(texture_type, 0, texel_type, _image_width, _image_height, 0, pixel_type, pixel_storage, _image_data.ptr()); + // if( flags & TEXTURE_BORDER ) glTexParameterfv(texture_type, GL_TEXTURE_BORDER_COLOR, border_color); - /* + /* if (flags & TEXTURE_MIPMAPS) glGenerateMipmap(texture_type); @@ -176,19 +599,23 @@ void Texture::texture_update(int flags) { // glTexParameterf(texture_type, GL_TEXTURE_MAX_ANISOTROPY, max_aniso); } - */ + */ // glBindTexture(texture_type, 0); // do not unbind. current code expects texture to be bound at function exit - /* + /* t->w = w; t->h = h; t->n = n; t->flags = flags; t->filename = t->filename ? t->filename : ""; - */ + */ } void Texture::apply_filter() { + if (!texture) { + return; + } + GLint params = GL_NEAREST; if (filter == TEXTURE_FILTER_LINEAR) { @@ -200,17 +627,43 @@ void Texture::apply_filter() { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, params); } +void Texture::set_image(const Ref &img) { + _image = img; + + if (texture) { + glDeleteTextures(1, &texture); + } + + if (!_image.is_valid()) { + return; + } + + _image_data = _image->get_data(); + _image_format = _image->get_format(); + _image_width = _image->get_width(); + _image_height = _image->get_height(); + _image_mip_maps = _image->has_mipmaps(); + + if (_image_data.size() == 0) { + return; + } + + glGenTextures(1, &texture); + + texture_update(0); +} + Texture::Texture() { filter = TEXTURE_FILTER_NEAREST; texture = 0; - pixels = NULL; + _image_width = 0; + _image_height = 0; + _image_format = Image::FORMAT_RGBA8; + _image_mip_maps = false; } Texture::~Texture() { - if (pixels) { - //todo - //delete (pixels); - + if (texture) { glDeleteTextures(1, &texture); } } diff --git a/sfw/render_core/texture.h b/sfw/render_core/texture.h index 899446f..98fb2da 100644 --- a/sfw/render_core/texture.h +++ b/sfw/render_core/texture.h @@ -2,6 +2,7 @@ #define TEXTURE_H #include "3rd_glad.h" +#include "image.h" class Texture { public: @@ -10,36 +11,24 @@ public: TEXTURE_FILTER_LINEAR, }; - void load_image(const char *file_name, const int format = GL_RGBA, const int internal_components = GL_RGBA); - void apply_filter(); - TextureFilter filter; GLuint texture; - // from fwk, temporary - union { - int x, w; - }; - union { - int y, h; - }; - union { - int n, comps; - }; - union { - void *pixels; - uint8_t *pixels8; - uint16_t *pixels16; - uint32_t *pixels32; - float *pixelsf; - }; - - // From FWK - void image_data_load(const char *file_name, int flags); + void apply_filter(); void texture_update(int flags); + void set_image(const Ref &img); + Texture(); virtual ~Texture(); + +protected: + int _image_width; + int _image_height; + Ref _image; + Vector _image_data; + Image::Format _image_format; + bool _image_mip_maps; }; #endif // TEXTURE_H