From 3c175115ebf54bcf5f53ab7a2d4926c6773665db Mon Sep 17 00:00:00 2001 From: Ferenc Arn Date: Sat, 29 Apr 2017 20:14:14 -0500 Subject: [PATCH] Use libsquish to decompress DXT textures. --- core/image.cpp | 329 +---------------------- core/image.h | 2 +- modules/squish/image_compress_squish.cpp | 42 ++- modules/squish/image_compress_squish.h | 1 + modules/squish/register_types.cpp | 1 + 5 files changed, 47 insertions(+), 328 deletions(-) diff --git a/core/image.cpp b/core/image.cpp index 85ca63be5ed..316faf954ef 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -1370,7 +1370,7 @@ Error Image::load(const String &p_path) { return ImageLoader::load_image(p_path, this); } -Error Image::save_png(const String &p_path) { +Error Image::save_png(const String &p_path) const { if (save_png_func == NULL) return ERR_UNAVAILABLE; @@ -1391,337 +1391,14 @@ int Image::get_image_required_mipmaps(int p_width, int p_height, Format p_format return mm; } -Error Image::_decompress_bc() { - - int wd = width, ht = height; - if (wd % 4 != 0) { - wd += 4 - (wd % 4); - } - if (ht % 4 != 0) { - ht += 4 - (ht % 4); - } - - int mm; - int size = _get_dst_image_size(wd, ht, FORMAT_RGBA8, mm); - - PoolVector newdata; - newdata.resize(size); - - PoolVector::Write w = newdata.write(); - PoolVector::Read r = data.read(); - - int rofs = 0; - int wofs = 0; - - //print_line("width: "+itos(wd)+" height: "+itos(ht)); - - for (int i = 0; i <= mm; i++) { - - switch (format) { - - case FORMAT_DXT1: { - - int len = (wd * ht) / 16; - uint8_t *dst = &w[wofs]; - - uint32_t ofs_table[16]; - for (int x = 0; x < 4; x++) { - - for (int y = 0; y < 4; y++) { - - ofs_table[15 - (y * 4 + (3 - x))] = (x + y * wd) * 4; - } - } - - for (int j = 0; j < len; j++) { - - const uint8_t *src = &r[rofs + j * 8]; - uint16_t col_a = src[1]; - col_a <<= 8; - col_a |= src[0]; - uint16_t col_b = src[3]; - col_b <<= 8; - col_b |= src[2]; - - uint8_t table[4][4] = { - { uint8_t((col_a >> 11) << 3), uint8_t(((col_a >> 5) & 0x3f) << 2), uint8_t(((col_a)&0x1f) << 3), 255 }, - { uint8_t((col_b >> 11) << 3), uint8_t(((col_b >> 5) & 0x3f) << 2), uint8_t(((col_b)&0x1f) << 3), 255 }, - { 0, 0, 0, 255 }, - { 0, 0, 0, 255 } - }; - - if (col_a < col_b) { - //punchrough - table[2][0] = (int(table[0][0]) + int(table[1][0])) >> 1; - table[2][1] = (int(table[0][1]) + int(table[1][1])) >> 1; - table[2][2] = (int(table[0][2]) + int(table[1][2])) >> 1; - table[3][3] = 0; //premul alpha black - } else { - //gradient - table[2][0] = (int(table[0][0]) * 2 + int(table[1][0])) / 3; - table[2][1] = (int(table[0][1]) * 2 + int(table[1][1])) / 3; - table[2][2] = (int(table[0][2]) * 2 + int(table[1][2])) / 3; - table[3][0] = (int(table[0][0]) + int(table[1][0]) * 2) / 3; - table[3][1] = (int(table[0][1]) + int(table[1][1]) * 2) / 3; - table[3][2] = (int(table[0][2]) + int(table[1][2]) * 2) / 3; - } - - uint32_t block = src[4]; - block <<= 8; - block |= src[5]; - block <<= 8; - block |= src[6]; - block <<= 8; - block |= src[7]; - - int y = (j / (wd / 4)) * 4; - int x = (j % (wd / 4)) * 4; - int pixofs = (y * wd + x) * 4; - - for (int k = 0; k < 16; k++) { - int idx = pixofs + ofs_table[k]; - dst[idx + 0] = table[block & 0x3][0]; - dst[idx + 1] = table[block & 0x3][1]; - dst[idx + 2] = table[block & 0x3][2]; - dst[idx + 3] = table[block & 0x3][3]; - block >>= 2; - } - } - - rofs += len * 8; - wofs += wd * ht * 4; - - wd /= 2; - ht /= 2; - - } break; - case FORMAT_DXT3: { - - int len = (wd * ht) / 16; - uint8_t *dst = &w[wofs]; - - uint32_t ofs_table[16]; - for (int x = 0; x < 4; x++) { - - for (int y = 0; y < 4; y++) { - - ofs_table[15 - (y * 4 + (3 - x))] = (x + y * wd) * 4; - } - } - - for (int j = 0; j < len; j++) { - - const uint8_t *src = &r[rofs + j * 16]; - - uint64_t ablock = src[1]; - ablock <<= 8; - ablock |= src[0]; - ablock <<= 8; - ablock |= src[3]; - ablock <<= 8; - ablock |= src[2]; - ablock <<= 8; - ablock |= src[5]; - ablock <<= 8; - ablock |= src[4]; - ablock <<= 8; - ablock |= src[7]; - ablock <<= 8; - ablock |= src[6]; - - uint16_t col_a = src[8 + 1]; - col_a <<= 8; - col_a |= src[8 + 0]; - uint16_t col_b = src[8 + 3]; - col_b <<= 8; - col_b |= src[8 + 2]; - - uint8_t table[4][4] = { - { uint8_t((col_a >> 11) << 3), uint8_t(((col_a >> 5) & 0x3f) << 2), uint8_t(((col_a)&0x1f) << 3), 255 }, - { uint8_t((col_b >> 11) << 3), uint8_t(((col_b >> 5) & 0x3f) << 2), uint8_t(((col_b)&0x1f) << 3), 255 }, - - { 0, 0, 0, 255 }, - { 0, 0, 0, 255 } - }; - - //always gradient - table[2][0] = (int(table[0][0]) * 2 + int(table[1][0])) / 3; - table[2][1] = (int(table[0][1]) * 2 + int(table[1][1])) / 3; - table[2][2] = (int(table[0][2]) * 2 + int(table[1][2])) / 3; - table[3][0] = (int(table[0][0]) + int(table[1][0]) * 2) / 3; - table[3][1] = (int(table[0][1]) + int(table[1][1]) * 2) / 3; - table[3][2] = (int(table[0][2]) + int(table[1][2]) * 2) / 3; - - uint32_t block = src[4 + 8]; - block <<= 8; - block |= src[5 + 8]; - block <<= 8; - block |= src[6 + 8]; - block <<= 8; - block |= src[7 + 8]; - - int y = (j / (wd / 4)) * 4; - int x = (j % (wd / 4)) * 4; - int pixofs = (y * wd + x) * 4; - - for (int k = 0; k < 16; k++) { - uint8_t alpha = ablock & 0xf; - alpha = int(alpha) * 255 / 15; //right way for alpha - int idx = pixofs + ofs_table[k]; - dst[idx + 0] = table[block & 0x3][0]; - dst[idx + 1] = table[block & 0x3][1]; - dst[idx + 2] = table[block & 0x3][2]; - dst[idx + 3] = alpha; - block >>= 2; - ablock >>= 4; - } - } - - rofs += len * 16; - wofs += wd * ht * 4; - - wd /= 2; - ht /= 2; - - } break; - case FORMAT_DXT5: { - - int len = (wd * ht) / 16; - uint8_t *dst = &w[wofs]; - - uint32_t ofs_table[16]; - for (int x = 0; x < 4; x++) { - - for (int y = 0; y < 4; y++) { - - ofs_table[15 - (y * 4 + (3 - x))] = (x + y * wd) * 4; - } - } - - for (int j = 0; j < len; j++) { - - const uint8_t *src = &r[rofs + j * 16]; - - uint8_t a_start = src[1]; - uint8_t a_end = src[0]; - - uint64_t ablock = src[3]; - ablock <<= 8; - ablock |= src[2]; - ablock <<= 8; - ablock |= src[5]; - ablock <<= 8; - ablock |= src[4]; - ablock <<= 8; - ablock |= src[7]; - ablock <<= 8; - ablock |= src[6]; - - uint8_t atable[8]; - - if (a_start > a_end) { - - atable[0] = (int(a_start) * 7 + int(a_end) * 0) / 7; - atable[1] = (int(a_start) * 6 + int(a_end) * 1) / 7; - atable[2] = (int(a_start) * 5 + int(a_end) * 2) / 7; - atable[3] = (int(a_start) * 4 + int(a_end) * 3) / 7; - atable[4] = (int(a_start) * 3 + int(a_end) * 4) / 7; - atable[5] = (int(a_start) * 2 + int(a_end) * 5) / 7; - atable[6] = (int(a_start) * 1 + int(a_end) * 6) / 7; - atable[7] = (int(a_start) * 0 + int(a_end) * 7) / 7; - } else { - - atable[0] = (int(a_start) * 5 + int(a_end) * 0) / 5; - atable[1] = (int(a_start) * 4 + int(a_end) * 1) / 5; - atable[2] = (int(a_start) * 3 + int(a_end) * 2) / 5; - atable[3] = (int(a_start) * 2 + int(a_end) * 3) / 5; - atable[4] = (int(a_start) * 1 + int(a_end) * 4) / 5; - atable[5] = (int(a_start) * 0 + int(a_end) * 5) / 5; - atable[6] = 0; - atable[7] = 255; - } - - uint16_t col_a = src[8 + 1]; - col_a <<= 8; - col_a |= src[8 + 0]; - uint16_t col_b = src[8 + 3]; - col_b <<= 8; - col_b |= src[8 + 2]; - - uint8_t table[4][4] = { - { uint8_t((col_a >> 11) << 3), uint8_t(((col_a >> 5) & 0x3f) << 2), uint8_t(((col_a)&0x1f) << 3), 255 }, - { uint8_t((col_b >> 11) << 3), uint8_t(((col_b >> 5) & 0x3f) << 2), uint8_t(((col_b)&0x1f) << 3), 255 }, - - { 0, 0, 0, 255 }, - { 0, 0, 0, 255 } - }; - - //always gradient - table[2][0] = (int(table[0][0]) * 2 + int(table[1][0])) / 3; - table[2][1] = (int(table[0][1]) * 2 + int(table[1][1])) / 3; - table[2][2] = (int(table[0][2]) * 2 + int(table[1][2])) / 3; - table[3][0] = (int(table[0][0]) + int(table[1][0]) * 2) / 3; - table[3][1] = (int(table[0][1]) + int(table[1][1]) * 2) / 3; - table[3][2] = (int(table[0][2]) + int(table[1][2]) * 2) / 3; - - uint32_t block = src[4 + 8]; - block <<= 8; - block |= src[5 + 8]; - block <<= 8; - block |= src[6 + 8]; - block <<= 8; - block |= src[7 + 8]; - - int y = (j / (wd / 4)) * 4; - int x = (j % (wd / 4)) * 4; - int pixofs = (y * wd + x) * 4; - - for (int k = 0; k < 16; k++) { - uint8_t alpha = ablock & 0x7; - int idx = pixofs + ofs_table[k]; - dst[idx + 0] = table[block & 0x3][0]; - dst[idx + 1] = table[block & 0x3][1]; - dst[idx + 2] = table[block & 0x3][2]; - dst[idx + 3] = atable[alpha]; - block >>= 2; - ablock >>= 3; - } - } - - rofs += len * 16; - wofs += wd * ht * 4; - - wd /= 2; - ht /= 2; - - } break; - default: {} - } - } - - w = PoolVector::Write(); - r = PoolVector::Read(); - - data = newdata; - format = FORMAT_RGBA8; - if (wd != width || ht != height) { - - SWAP(width, wd); - SWAP(height, ht); - crop(wd, ht); - } - - return OK; -} - bool Image::is_compressed() const { return format >= FORMAT_RGB565; } Error Image::decompress() { - if (format >= FORMAT_DXT1 && format <= FORMAT_ATI2) - _decompress_bc(); //_image_decompress_bc(this); + if (format >= FORMAT_DXT1 && format <= FORMAT_ATI2 && _image_decompress_bc) + _image_decompress_bc(this); else if (format >= FORMAT_PVRTC2 && format <= FORMAT_PVRTC4A && _image_decompress_pvrtc) _image_decompress_pvrtc(this); else if (format == FORMAT_ETC && _image_decompress_etc) diff --git a/core/image.h b/core/image.h index 4decaa34369..273e2d0ab7e 100644 --- a/core/image.h +++ b/core/image.h @@ -227,7 +227,7 @@ public: PoolVector get_data() const; Error load(const String &p_path); - Error save_png(const String &p_path); + Error save_png(const String &p_path) const; /** * create an empty image diff --git a/modules/squish/image_compress_squish.cpp b/modules/squish/image_compress_squish.cpp index 3f7ad8b2c2b..5c534920341 100644 --- a/modules/squish/image_compress_squish.cpp +++ b/modules/squish/image_compress_squish.cpp @@ -39,6 +39,46 @@ #include +void image_decompress_squish(Image *p_image) { + int w = p_image->get_width(); + int h = p_image->get_height(); + + Image::Format target_format = Image::FORMAT_RGBA8; + PoolVector data; + int target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps() ? -1 : 0); + int mm_count = p_image->get_mipmap_count(); + data.resize(target_size); + + PoolVector::Read rb = p_image->get_data().read(); + PoolVector::Write wb = data.write(); + + int squish_flags = Image::FORMAT_MAX; + if (p_image->get_format() == Image::FORMAT_DXT1) { + squish_flags = squish::kDxt1; + } else if (p_image->get_format() == Image::FORMAT_DXT3) { + squish_flags = squish::kDxt3; + } else if (p_image->get_format() == Image::FORMAT_DXT5) { + squish_flags = squish::kDxt5; + } else if (p_image->get_format() == Image::FORMAT_ATI1) { + squish_flags = squish::kBc4; + } else if (p_image->get_format() == Image::FORMAT_ATI2) { + squish_flags = squish::kBc5; + } else { + ERR_FAIL_COND(true); + return; + } + + int dst_ofs = 0; + + for (int i = 0; i <= mm_count; i++) { + int src_ofs = 0, mipmap_size = 0, mipmap_w = 0, mipmap_h = 0; + p_image->get_mipmap_offset_size_and_dimensions(i, src_ofs, mipmap_size, mipmap_w, mipmap_h); + squish::DecompressImage(&wb[dst_ofs], mipmap_w, mipmap_h, &rb[src_ofs], squish_flags); + } + + p_image->create(p_image->get_width(), p_image->get_height(), p_image->has_mipmaps(), target_format, data); +} + void image_compress_squish(Image *p_image) { int w = p_image->get_width(); @@ -56,7 +96,7 @@ void image_compress_squish(Image *p_image) { return; //do not compress, already compressed int shift = 0; - int squish_comp = squish::kColourRangeFit; + int squish_comp = squish::kColourRangeFit; // TODO: use lossy quality setting to determine the quality Image::Format target_format; if (p_image->get_format() == Image::FORMAT_LA8) { diff --git a/modules/squish/image_compress_squish.h b/modules/squish/image_compress_squish.h index 81f57c68220..519e3537ef1 100644 --- a/modules/squish/image_compress_squish.h +++ b/modules/squish/image_compress_squish.h @@ -33,5 +33,6 @@ #include "image.h" void image_compress_squish(Image *p_image); +void image_decompress_squish(Image *p_image); #endif // IMAGE_COMPRESS_SQUISH_H diff --git a/modules/squish/register_types.cpp b/modules/squish/register_types.cpp index 41341db93b3..2eeea598368 100644 --- a/modules/squish/register_types.cpp +++ b/modules/squish/register_types.cpp @@ -36,6 +36,7 @@ void register_squish_types() { Image::set_compress_bc_func(image_compress_squish); + Image::_image_decompress_bc = image_decompress_squish; } void unregister_squish_types() {}