Skip to content

Commit d1b7c60

Browse files
committed
Merge pull request #77712 from nklbdev/Fix_lossless_formats_in_PortableCompressedTexture2D
Fix lossless formats in PortableCompressedTexture2D
2 parents 85e999d + 47d9916 commit d1b7c60

7 files changed

Lines changed: 47 additions & 10 deletions

File tree

core/io/image.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3013,6 +3013,7 @@ void Image::fill_rect(const Rect2i &p_rect, const Color &p_color) {
30133013
}
30143014

30153015
ImageMemLoadFunc Image::_png_mem_loader_func = nullptr;
3016+
ImageMemLoadFunc Image::_png_mem_unpacker_func = nullptr;
30163017
ImageMemLoadFunc Image::_jpg_mem_loader_func = nullptr;
30173018
ImageMemLoadFunc Image::_webp_mem_loader_func = nullptr;
30183019
ImageMemLoadFunc Image::_tga_mem_loader_func = nullptr;

core/io/image.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ class Image : public Resource {
145145
};
146146

147147
static ImageMemLoadFunc _png_mem_loader_func;
148+
static ImageMemLoadFunc _png_mem_unpacker_func;
148149
static ImageMemLoadFunc _jpg_mem_loader_func;
149150
static ImageMemLoadFunc _webp_mem_loader_func;
150151
static ImageMemLoadFunc _tga_mem_loader_func;

drivers/png/image_loader_png.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,14 @@ Ref<Image> ImageLoaderPNG::load_mem_png(const uint8_t *p_png, int p_size) {
6666
return img;
6767
}
6868

69+
Ref<Image> ImageLoaderPNG::unpack_mem_png(const uint8_t *p_png, int p_size) {
70+
ERR_FAIL_COND_V(p_size < 4, Ref<Image>());
71+
ERR_FAIL_COND_V(p_png[0] != 'P' || p_png[1] != 'N' || p_png[2] != 'G' || p_png[3] != ' ', Ref<Image>());
72+
return load_mem_png(&p_png[4], p_size - 4);
73+
}
74+
6975
Ref<Image> ImageLoaderPNG::lossless_unpack_png(const Vector<uint8_t> &p_data) {
70-
const int len = p_data.size();
71-
ERR_FAIL_COND_V(len < 4, Ref<Image>());
72-
const uint8_t *r = p_data.ptr();
73-
ERR_FAIL_COND_V(r[0] != 'P' || r[1] != 'N' || r[2] != 'G' || r[3] != ' ', Ref<Image>());
74-
return load_mem_png(&r[4], len - 4);
76+
return unpack_mem_png(p_data.ptr(), p_data.size());
7577
}
7678

7779
Vector<uint8_t> ImageLoaderPNG::lossless_pack_png(const Ref<Image> &p_image) {
@@ -99,6 +101,7 @@ Vector<uint8_t> ImageLoaderPNG::lossless_pack_png(const Ref<Image> &p_image) {
99101

100102
ImageLoaderPNG::ImageLoaderPNG() {
101103
Image::_png_mem_loader_func = load_mem_png;
104+
Image::_png_mem_unpacker_func = unpack_mem_png;
102105
Image::png_unpacker = lossless_unpack_png;
103106
Image::png_packer = lossless_pack_png;
104107
}

drivers/png/image_loader_png.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class ImageLoaderPNG : public ImageFormatLoader {
3737
private:
3838
static Vector<uint8_t> lossless_pack_png(const Ref<Image> &p_image);
3939
static Ref<Image> lossless_unpack_png(const Vector<uint8_t> &p_data);
40+
static Ref<Image> unpack_mem_png(const uint8_t *p_png, int p_size);
4041
static Ref<Image> load_mem_png(const uint8_t *p_png, int p_size);
4142

4243
public:

editor/plugins/texture_editor_plugin.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "scene/resources/atlas_texture.h"
3939
#include "scene/resources/compressed_texture.h"
4040
#include "scene/resources/image_texture.h"
41+
#include "scene/resources/portable_compressed_texture.h"
4142

4243
TextureRect *TexturePreview::get_texture_display() {
4344
return texture_display;
@@ -158,7 +159,7 @@ TexturePreview::TexturePreview(Ref<Texture2D> p_texture, bool p_show_metadata) {
158159
}
159160

160161
bool EditorInspectorPluginTexture::can_handle(Object *p_object) {
161-
return Object::cast_to<ImageTexture>(p_object) != nullptr || Object::cast_to<AtlasTexture>(p_object) != nullptr || Object::cast_to<CompressedTexture2D>(p_object) != nullptr || Object::cast_to<AnimatedTexture>(p_object) != nullptr || Object::cast_to<Image>(p_object) != nullptr;
162+
return Object::cast_to<ImageTexture>(p_object) != nullptr || Object::cast_to<AtlasTexture>(p_object) != nullptr || Object::cast_to<CompressedTexture2D>(p_object) != nullptr || Object::cast_to<PortableCompressedTexture2D>(p_object) != nullptr || Object::cast_to<AnimatedTexture>(p_object) != nullptr || Object::cast_to<Image>(p_object) != nullptr;
162163
}
163164

164165
void EditorInspectorPluginTexture::parse_begin(Object *p_object) {

scene/resources/compressed_texture.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ class CompressedTexture2D : public Texture2D {
4040

4141
public:
4242
enum DataFormat {
43+
DATA_FORMAT_UNDEFINED,
4344
DATA_FORMAT_IMAGE,
4445
DATA_FORMAT_PNG,
4546
DATA_FORMAT_WEBP,

scene/resources/portable_compressed_texture.cpp

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@
3030

3131
#include "portable_compressed_texture.h"
3232

33+
#include "core/config/project_settings.h"
3334
#include "core/io/marshalls.h"
3435
#include "scene/resources/bit_map.h"
36+
#include "scene/resources/compressed_texture.h"
3537

3638
void PortableCompressedTexture2D::_set_data(const Vector<uint8_t> &p_data) {
3739
if (p_data.size() == 0) {
@@ -41,7 +43,8 @@ void PortableCompressedTexture2D::_set_data(const Vector<uint8_t> &p_data) {
4143
const uint8_t *data = p_data.ptr();
4244
uint32_t data_size = p_data.size();
4345
ERR_FAIL_COND(data_size < 20);
44-
compression_mode = CompressionMode(decode_uint32(data + 0));
46+
compression_mode = CompressionMode(decode_uint16(data));
47+
CompressedTexture2D::DataFormat data_format = CompressedTexture2D::DataFormat(decode_uint16(data + 2));
4548
format = Image::Format(decode_uint32(data + 4));
4649
uint32_t mipmap_count = decode_uint32(data + 8);
4750
size.width = decode_uint32(data + 12);
@@ -56,6 +59,16 @@ void PortableCompressedTexture2D::_set_data(const Vector<uint8_t> &p_data) {
5659
switch (compression_mode) {
5760
case COMPRESSION_MODE_LOSSLESS:
5861
case COMPRESSION_MODE_LOSSY: {
62+
ImageMemLoadFunc loader_func;
63+
if (data_format == CompressedTexture2D::DATA_FORMAT_UNDEFINED) {
64+
loader_func = nullptr;
65+
} else if (data_format == CompressedTexture2D::DATA_FORMAT_PNG) {
66+
loader_func = Image::_png_mem_unpacker_func;
67+
} else if (data_format == CompressedTexture2D::DATA_FORMAT_WEBP) {
68+
loader_func = Image::_webp_mem_loader_func;
69+
} else {
70+
ERR_FAIL();
71+
}
5972
Vector<uint8_t> image_data;
6073

6174
ERR_FAIL_COND(data_size < 4);
@@ -64,7 +77,9 @@ void PortableCompressedTexture2D::_set_data(const Vector<uint8_t> &p_data) {
6477
data += 4;
6578
data_size -= 4;
6679
ERR_FAIL_COND(mipsize < data_size);
67-
Ref<Image> img = memnew(Image(data, data_size));
80+
Ref<Image> img = loader_func == nullptr
81+
? memnew(Image(data, data_size))
82+
: Ref<Image>(loader_func(data, data_size));
6883
ERR_FAIL_COND(img->is_empty());
6984
if (img->get_format() != format) { // May happen due to webp/png in the tiny mipmaps.
7085
img->convert(format);
@@ -99,6 +114,7 @@ void PortableCompressedTexture2D::_set_data(const Vector<uint8_t> &p_data) {
99114
}
100115

101116
image_stored = true;
117+
size_override = size;
102118
RenderingServer::get_singleton()->texture_set_size_override(texture, size_override.width, size_override.height);
103119
alpha_cache.unref();
104120

@@ -122,7 +138,8 @@ void PortableCompressedTexture2D::create_from_image(const Ref<Image> &p_image, C
122138
Vector<uint8_t> buffer;
123139

124140
buffer.resize(20);
125-
encode_uint32(p_compression_mode, buffer.ptrw());
141+
encode_uint16(p_compression_mode, buffer.ptrw());
142+
encode_uint16(CompressedTexture2D::DATA_FORMAT_UNDEFINED, buffer.ptrw() + 2);
126143
encode_uint32(p_image->get_format(), buffer.ptrw() + 4);
127144
encode_uint32(p_image->get_mipmap_count() + 1, buffer.ptrw() + 8);
128145
encode_uint32(p_image->get_width(), buffer.ptrw() + 12);
@@ -131,12 +148,22 @@ void PortableCompressedTexture2D::create_from_image(const Ref<Image> &p_image, C
131148
switch (p_compression_mode) {
132149
case COMPRESSION_MODE_LOSSLESS:
133150
case COMPRESSION_MODE_LOSSY: {
151+
bool lossless_force_png = GLOBAL_GET("rendering/textures/lossless_compression/force_png") ||
152+
!Image::_webp_mem_loader_func; // WebP module disabled.
153+
bool use_webp = !lossless_force_png && p_image->get_width() <= 16383 && p_image->get_height() <= 16383; // WebP has a size limit.
134154
for (int i = 0; i < p_image->get_mipmap_count() + 1; i++) {
135155
Vector<uint8_t> data;
136156
if (p_compression_mode == COMPRESSION_MODE_LOSSY) {
137157
data = Image::webp_lossy_packer(p_image->get_image_from_mipmap(i), p_lossy_quality);
158+
encode_uint16(CompressedTexture2D::DATA_FORMAT_WEBP, buffer.ptrw() + 2);
138159
} else {
139-
data = Image::webp_lossless_packer(p_image->get_image_from_mipmap(i));
160+
if (use_webp) {
161+
data = Image::webp_lossless_packer(p_image->get_image_from_mipmap(i));
162+
encode_uint16(CompressedTexture2D::DATA_FORMAT_WEBP, buffer.ptrw() + 2);
163+
} else {
164+
data = Image::png_packer(p_image->get_image_from_mipmap(i));
165+
encode_uint16(CompressedTexture2D::DATA_FORMAT_PNG, buffer.ptrw() + 2);
166+
}
140167
}
141168
int data_len = data.size();
142169
buffer.resize(buffer.size() + 4);
@@ -145,6 +172,7 @@ void PortableCompressedTexture2D::create_from_image(const Ref<Image> &p_image, C
145172
}
146173
} break;
147174
case COMPRESSION_MODE_BASIS_UNIVERSAL: {
175+
encode_uint16(CompressedTexture2D::DATA_FORMAT_BASIS_UNIVERSAL, buffer.ptrw() + 2);
148176
Image::UsedChannels uc = p_image->detect_used_channels(p_normal_map ? Image::COMPRESS_SOURCE_NORMAL : Image::COMPRESS_SOURCE_GENERIC);
149177
Vector<uint8_t> budata = Image::basis_universal_packer(p_image, uc);
150178
buffer.append_array(budata);
@@ -153,6 +181,7 @@ void PortableCompressedTexture2D::create_from_image(const Ref<Image> &p_image, C
153181
case COMPRESSION_MODE_S3TC:
154182
case COMPRESSION_MODE_ETC2:
155183
case COMPRESSION_MODE_BPTC: {
184+
encode_uint16(CompressedTexture2D::DATA_FORMAT_IMAGE, buffer.ptrw() + 2);
156185
Ref<Image> copy = p_image->duplicate();
157186
switch (p_compression_mode) {
158187
case COMPRESSION_MODE_S3TC:

0 commit comments

Comments
 (0)