Browse Source

Merge pull request #8590 from tagcup/s3tc_stuff

Use libsquish to decompress DXT textures.
Juan Linietsky 8 years ago
parent
commit
7c89e00d46

+ 3 - 326
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<uint8_t> newdata;
-	newdata.resize(size);
-
-	PoolVector<uint8_t>::Write w = newdata.write();
-	PoolVector<uint8_t>::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<uint8_t>::Write();
-	r = PoolVector<uint8_t>::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)

+ 1 - 1
core/image.h

@@ -227,7 +227,7 @@ public:
 	PoolVector<uint8_t> 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

+ 41 - 1
modules/squish/image_compress_squish.cpp

@@ -39,6 +39,46 @@
 
 #include <squish.h>
 
+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<uint8_t> 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<uint8_t>::Read rb = p_image->get_data().read();
+	PoolVector<uint8_t>::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) {

+ 1 - 0
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

+ 1 - 0
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() {}