jpeg pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=68a8063f9ada4c77d16d10960f66778c6df1956c
commit 68a8063f9ada4c77d16d10960f66778c6df1956c Author: Jean-Philippe Andre <[email protected]> Date: Fri Jul 11 15:15:52 2014 +0900 Eet: Add support for ETC1+Alpha The TGV file format and GL engine now support ETC1 encoding with alpha using an extra texture. This commit adds similar support to the Eet encoder/decoder. @feature --- src/lib/eet/Eet.h | 6 +- src/lib/eet/eet_image.c | 648 ++++++++++++++++++++++++++++++++---------------- 2 files changed, 435 insertions(+), 219 deletions(-) diff --git a/src/lib/eet/Eet.h b/src/lib/eet/Eet.h index 95be2e5..0fdad39 100644 --- a/src/lib/eet/Eet.h +++ b/src/lib/eet/Eet.h @@ -479,7 +479,8 @@ typedef enum _Eet_Image_Encoding EET_IMAGE_JPEG = 1, EET_IMAGE_ETC1 = 2, EET_IMAGE_ETC2_RGB = 3, - EET_IMAGE_ETC2_RGBA = 4 + EET_IMAGE_ETC2_RGBA = 4, + EET_IMAGE_ETC1_ALPHA = 5, } Eet_Image_Encoding; typedef enum _Eet_Colorspace @@ -488,7 +489,8 @@ typedef enum _Eet_Colorspace /* The number between are reserved to preserve compatibility with evas */ EET_COLORSPACE_ETC1 = 9, EET_COLORSPACE_RGB8_ETC2 = 10, - EET_COLORSPACE_RGBA8_ETC2_EAC = 11 + EET_COLORSPACE_RGBA8_ETC2_EAC = 11, + EET_COLORSPACE_ETC1_ALPHA = 12 } Eet_Colorspace; /** diff --git a/src/lib/eet/eet_image.c b/src/lib/eet/eet_image.c index 3d6b953..efe7108 100644 --- a/src/lib/eet/eet_image.c +++ b/src/lib/eet/eet_image.c @@ -30,6 +30,27 @@ #include "rg_etc1.h" +#ifdef BUILD_NEON +#include <arm_neon.h> +#endif + +#ifndef WORDS_BIGENDIAN +/* x86 */ +#define A_VAL(p) (((uint8_t *)(p))[3]) +#define R_VAL(p) (((uint8_t *)(p))[2]) +#define G_VAL(p) (((uint8_t *)(p))[1]) +#define B_VAL(p) (((uint8_t *)(p))[0]) +#else +/* ppc */ +#define A_VAL(p) (((uint8_t *)(p))[0]) +#define R_VAL(p) (((uint8_t *)(p))[1]) +#define G_VAL(p) (((uint8_t *)(p))[2]) +#define B_VAL(p) (((uint8_t *)(p))[3]) +#endif + +#define ARGB_JOIN(a,r,g,b) \ + (((a) << 24) + ((r) << 16) + ((g) << 8) + (b)) + #define OFFSET_BLOCK_SIZE 4 #define OFFSET_ALGORITHM 5 #define OFFSET_OPTIONS 6 @@ -677,6 +698,50 @@ eet_data_image_jpeg_alpha_decode(const void *data, return 1; } +// FIXME: Importing two functions from evas here: premul & unpremul +static void +_eet_argb_premul(unsigned int *data, unsigned int len) +{ + unsigned int *de = data + len; + + while (data < de) + { + unsigned int a = 1 + (*data >> 24); + + *data = (*data & 0xff000000) + + (((((*data) >> 8) & 0xff) * a) & 0xff00) + + (((((*data) & 0x00ff00ff) * a) >> 8) & 0x00ff00ff); + data++; + } +} + +static void +_eet_argb_unpremul(unsigned int *data, unsigned int len) +{ + unsigned int *de = data + len; + unsigned int p_val = 0x00000000, p_res = 0x00000000; + + while (data < de) + { + unsigned int a = (*data >> 24) + 1; + + if (p_val == *data) *data = p_res; + else + { + p_val = *data; + if ((a > 1) && (a < 256)) + *data = ARGB_JOIN(a, + (R_VAL(data) * 255) / a, + (G_VAL(data) * 255) / a, + (B_VAL(data) * 255) / a); + else if (a == 1) + *data = 0x00000000; + p_res = *data; + } + data++; + } +} + static inline unsigned int _tgv_length_get(const char *m, unsigned int length, unsigned int *offset) { @@ -722,7 +787,7 @@ eet_data_image_etc2_decode(const void *data, const char *m = NULL; unsigned int bwidth, bheight; unsigned char *p_etc; - char *buffer; + char *buffer = NULL; Eina_Rectangle master; unsigned int block_length; unsigned int offset; @@ -730,8 +795,9 @@ eet_data_image_etc2_decode(const void *data, unsigned int block_count; unsigned int etc_width = 0; unsigned int etc_block_size; + unsigned int num_planes = 1, plane, alpha_offset = 0; Eet_Colorspace file_cspace; - Eina_Bool compress, blockless; + Eina_Bool compress, blockless, unpremul; m = data; @@ -740,6 +806,7 @@ eet_data_image_etc2_decode(const void *data, compress = m[OFFSET_OPTIONS] & 0x1; blockless = (m[OFFSET_OPTIONS] & 0x2) != 0; + unpremul = (m[OFFSET_OPTIONS] & 0x4) != 0; w = ntohl(*((unsigned int*) &(m[OFFSET_WIDTH]))); h = ntohl(*((unsigned int*) &(m[OFFSET_HEIGHT]))); @@ -750,25 +817,31 @@ eet_data_image_etc2_decode(const void *data, file_cspace = EET_COLORSPACE_ETC1; if (alpha != EINA_FALSE) return 0; etc_block_size = 8; - etc_width = ((w + 2) / 4 + ((w + 2) % 4 ? 1 : 0)) * 8; break; case 1: if (lossy != EET_IMAGE_ETC2_RGB) return 0; file_cspace = EET_COLORSPACE_RGB8_ETC2; if (alpha != EINA_FALSE) return 0; etc_block_size = 8; - etc_width = ((w + 2) / 4 + ((w + 2) % 4 ? 1 : 0)) * 8; break; case 2: if (lossy != EET_IMAGE_ETC2_RGBA) return 0; file_cspace = EET_COLORSPACE_RGBA8_ETC2_EAC; if (alpha != EINA_TRUE) return 0; etc_block_size = 16; - etc_width = ((w + 2) / 4 + ((w + 2) % 4 ? 1 : 0)) * 16; + break; + case 3: + if (lossy != EET_IMAGE_ETC1_ALPHA) return 0; + file_cspace = EET_COLORSPACE_ETC1_ALPHA; + if (alpha != EINA_TRUE) return 0; + etc_block_size = 8; + num_planes = 2; + alpha_offset = ((w + 2 + 3) / 4) * ((h + 2 + 3) / 4) * 8 / sizeof(*p_etc); break; default: return 0; } + etc_width = ((w + 2 + 3) / 4) * etc_block_size; if (cspace != EET_COLORSPACE_ARGB8888 && cspace != file_cspace) { @@ -795,6 +868,7 @@ eet_data_image_etc2_decode(const void *data, case EET_COLORSPACE_ETC1: case EET_COLORSPACE_RGB8_ETC2: case EET_COLORSPACE_RGBA8_ETC2_EAC: + case EET_COLORSPACE_ETC1_ALPHA: if (master.x % 4 || master.y % 4) abort(); break; @@ -813,107 +887,159 @@ eet_data_image_etc2_decode(const void *data, block_count = bwidth * bheight / (4 * 4); if (compress) buffer = alloca(etc_block_size * block_count); - else - buffer = NULL; - - for (y = 0; y < h + 2; y += bheight) - for (x = 0; x < w + 2; x += bwidth) - { - Eina_Rectangle current; - const char *data_start; - const char *it; - unsigned int expand_length; - unsigned int i, j; - - block_length = _tgv_length_get(m + offset, length, &offset); - - if (block_length == 0) return 0; - - data_start = m + offset; - offset += block_length; - - EINA_RECTANGLE_SET(¤t, x, y, - bwidth, bheight); - - if (!eina_rectangle_intersection(¤t, &master)) - continue ; - - if (compress) - { - expand_length = LZ4_uncompress(data_start, buffer, - block_count * etc_block_size); - // That's an overhead for now, need to be fixed - if (expand_length != block_length) - return 0; - } - else - { - buffer = (void*) data_start; - if (block_count * etc_block_size != block_length) - return 0; - } - it = buffer; - - for (i = 0; i < bheight; i += 4) - for (j = 0; j < bwidth; j += 4, it += etc_block_size) + + for (plane = 0; plane < num_planes; plane++) + for (y = 0; y < h + 2; y += bheight) + for (x = 0; x < w + 2; x += bwidth) + { + Eina_Rectangle current; + const char *data_start; + const char *it; + unsigned int expand_length; + unsigned int i, j; + + block_length = _tgv_length_get(m + offset, length, &offset); + + if (block_length == 0) goto on_error; + + data_start = m + offset; + offset += block_length; + + EINA_RECTANGLE_SET(¤t, x, y, + bwidth, bheight); + + if (!eina_rectangle_intersection(¤t, &master)) + continue; + + if (compress) { - Eina_Rectangle current_etc; - unsigned int temporary[4 * 4] = { 0 }; - unsigned int offset_x, offset_y; - int k; - - EINA_RECTANGLE_SET(¤t_etc, x + j, y + i, 4, 4); - - if (!eina_rectangle_intersection(¤t_etc, ¤t)) - continue; - - switch (cspace) - { - case EET_COLORSPACE_ARGB8888: - switch (file_cspace) - { - case EET_COLORSPACE_ETC1: - if (!rg_etc1_unpack_block(it, temporary, 0)) - { - // TODO: Should we decode as RGB8_ETC2? - fprintf(stderr, "ETC1: Block starting at {%i, %i} is corrupted!\n", x + j, y + i); - continue; - } - break; - case EET_COLORSPACE_RGB8_ETC2: - rg_etc2_rgb8_decode_block((uint8_t *) it, temporary); - break; - case EET_COLORSPACE_RGBA8_ETC2_EAC: - rg_etc2_rgba8_decode_block((uint8_t *) it, temporary); - break; - default: abort(); - } - - offset_x = current_etc.x - x - j; - offset_y = current_etc.y - y - i; - // FIXME: Import NEON optimizations from Evas. - for (k = 0; k < current_etc.h; k++) - { - memcpy(&p[current_etc.x - 1 + - (current_etc.y - 1 + k) * master.w], - &temporary[offset_x + (offset_y + k) * 4], - current_etc.w * sizeof (unsigned int)); - } - break; - case EET_COLORSPACE_ETC1: - case EET_COLORSPACE_RGB8_ETC2: - case EET_COLORSPACE_RGBA8_ETC2_EAC: - memcpy(&p_etc[(current_etc.x / 4) * etc_block_size + - (current_etc.y / 4) * etc_width], - it, etc_block_size); - break; - default: - abort(); - } + expand_length = LZ4_uncompress(data_start, buffer, + block_count * etc_block_size); + // That's an overhead for now, need to be fixed + if (expand_length != block_length) + goto on_error; } - } + else + { + buffer = (void*) data_start; + if (block_count * etc_block_size != block_length) + goto on_error; + } + it = buffer; + + for (i = 0; i < bheight; i += 4) + for (j = 0; j < bwidth; j += 4, it += etc_block_size) + { + Eina_Rectangle current_etc; + unsigned int temporary[4 * 4]; + unsigned int offset_x, offset_y; + int k, l; + + EINA_RECTANGLE_SET(¤t_etc, x + j, y + i, 4, 4); + + if (!eina_rectangle_intersection(¤t_etc, ¤t)) + continue; + + switch (cspace) + { + case EET_COLORSPACE_ARGB8888: + switch (file_cspace) + { + case EET_COLORSPACE_ETC1: + case EET_COLORSPACE_ETC1_ALPHA: + if (!rg_etc1_unpack_block(it, temporary, 0)) + { + // TODO: Should we decode as RGB8_ETC2? + fprintf(stderr, "ETC1: Block starting at {%i, %i} is corrupted!\n", x + j, y + i); + continue; + } + break; + case EET_COLORSPACE_RGB8_ETC2: + rg_etc2_rgb8_decode_block((uint8_t *) it, temporary); + break; + case EET_COLORSPACE_RGBA8_ETC2_EAC: + rg_etc2_rgba8_decode_block((uint8_t *) it, temporary); + break; + default: abort(); + } + + offset_x = current_etc.x - x - j; + offset_y = current_etc.y - y - i; + + if (!plane) + { +#ifdef BUILD_NEON + if (eina_cpu_features_get() & EINA_CPU_NEON) + { + uint32_t *dst = &p[current_etc.x - 1 + (current_etc.y - 1) * master.w]; + uint32_t *src = &temporary[offset_x + offset_y * 4]; + for (k = 0; k < current_etc.h; k++) + { + if (current_etc.w == 4) + vst1q_u32(dst, vld1q_u32(src)); + else if (current_etc.w == 3) + { + vst1_u32(dst, vld1_u32(src)); + *(dst + 2) = *(src + 2); + } + else if (current_etc.w == 2) + vst1_u32(dst, vld1_u32(src)); + else + *dst = *src; + dst += master.w; + src += 4; + } + } + else +#endif + for (k = 0; k < current_etc.h; k++) + { + memcpy(&p[current_etc.x - 1 + (current_etc.y - 1 + k) * master.w], + &temporary[offset_x + (offset_y + k) * 4], + current_etc.w * sizeof (unsigned int)); + } + } + else + { + for (k = 0; k < current_etc.h; k++) + for (l = 0; l < current_etc.w; l++) + { + unsigned int *rgbdata = + &p[current_etc.x - 1 + (current_etc.y - 1 + k) * master.w + l]; + unsigned int *adata = + &temporary[offset_x + (offset_y + k) * 4 + l]; + A_VAL(rgbdata) = G_VAL(adata); + } + } + break; + case EET_COLORSPACE_ETC1: + case EET_COLORSPACE_RGB8_ETC2: + case EET_COLORSPACE_RGBA8_ETC2_EAC: + memcpy(&p_etc[(current_etc.x / 4) * etc_block_size + + (current_etc.y / 4) * etc_width], + it, etc_block_size); + break; + case EET_COLORSPACE_ETC1_ALPHA: + memcpy(&p_etc[(current_etc.x / 4) * etc_block_size + + (current_etc.y / 4) * etc_width + + plane * alpha_offset], + it, etc_block_size); + break; + default: + abort(); + } + } // bx,by inside blocks + } // x,y macroblocks + + // TODO: Add support for more unpremultiplied modes (ETC2) + if ((cspace == EET_COLORSPACE_ARGB8888) && unpremul) + _eet_argb_premul(p, w * h); return 1; + +on_error: + ERR("ETC image data is corrupted in this EET file"); + return 0; } static void * @@ -1083,6 +1209,16 @@ _block_size_get(int size) return MIN(k, MAX_BLOCK); } +static inline void +_alpha_to_greyscale_convert(uint32_t *data, int len) +{ + for (int k = 0; k < len; k++) + { + int alpha = A_VAL(data); + *data++ = ARGB_JOIN(alpha, alpha, alpha, alpha); + } +} + static void * eet_data_image_etc1_compressed_convert(int *size, const unsigned char *data8, @@ -1096,12 +1232,14 @@ eet_data_image_etc1_compressed_convert(int *size, uint8_t *comp = NULL; uint8_t *buffer; uint32_t *data; - uint32_t width, height; + uint32_t nl_width, nl_height; uint8_t header[8] = "TGV1"; int block_width, block_height, macro_block_width, macro_block_height; int block_count, image_stride, image_height, etc_block_size; + int num_planes = 1; Eet_Colorspace cspace; - Eina_Binbuf *r; + Eina_Bool unpremul = EINA_FALSE, alpha_texture = EINA_FALSE; + Eina_Binbuf *r = NULL; void *result; const char *codec; @@ -1110,9 +1248,8 @@ eet_data_image_etc1_compressed_convert(int *size, image_stride = w; image_height = h; - data = (uint32_t *) data8; - width = htonl(image_stride); - height = htonl(image_height); + nl_width = htonl(image_stride); + nl_height = htonl(image_height); compress = !!compress; // Disable dithering, as it will deteriorate the quality of flat surfaces @@ -1130,7 +1267,7 @@ eet_data_image_etc1_compressed_convert(int *size, block_height = _block_size_get(image_height + 2); header[4] = (block_height << 4) | block_width; - // header[5]: 0 for ETC1, 1 for RGB8_ETC2, 2 for RGBA8_ETC2_EAC + // header[5]: 0 for ETC1, 1 for RGB8_ETC2, 2 for RGBA8_ETC2_EAC, 3 for ETC1_ALPHA switch (lossy) { case EET_IMAGE_ETC1: @@ -1151,13 +1288,22 @@ eet_data_image_etc1_compressed_convert(int *size, header[5] = 2; codec = "ETC2 (RGBA)"; break; + case EET_IMAGE_ETC1_ALPHA: + cspace = EET_COLORSPACE_ETC1_ALPHA; + etc_block_size = 8; + num_planes = 2; // RGB and Alpha + header[5] = 3; + codec = "ETC1+Alpha"; + break; default: abort(); } - // header[6]: 0 for raw, 1, for LZ4 compressed - header[6] = compress; + // header[6]: 0 for raw, 1, for LZ4 compressed, 4 for unpremultiplied RGBA + // blockless mode (0x2) is never used here + header[6] = (compress ? 0x1 : 0x0) | (unpremul ? 0x4 : 0x0); - // header[7]: options (unused) + // header[7]: unused options + // Note: consider extending the header instead of filling all the bits here header[7] = 0; // Encoding being super slow, let's inform the user first. @@ -1166,8 +1312,8 @@ eet_data_image_etc1_compressed_convert(int *size, // Write header eina_binbuf_append_length(r, header, sizeof (header)); - eina_binbuf_append_length(r, (unsigned char*) &width, sizeof (width)); - eina_binbuf_append_length(r, (unsigned char*) &height, sizeof (height)); + eina_binbuf_append_length(r, (unsigned char*) &nl_width, sizeof (nl_width)); + eina_binbuf_append_length(r, (unsigned char*) &nl_height, sizeof (nl_height)); // Real block size in pixels, obviously a multiple of 4 macro_block_width = 4 << block_width; @@ -1180,142 +1326,193 @@ eet_data_image_etc1_compressed_convert(int *size, if (compress) comp = alloca(LZ4_compressBound(block_count * etc_block_size)); - // Write macro block - for (int y = 0; y < image_height + 2; y += macro_block_height) + // Write a whole plane (RGB or Alpha) + for (int plane = 0; plane < num_planes; plane++) { - uint32_t *input, *last_col, *last_row, *last_pix; - int real_y; - int wlen; - - if (y == 0) real_y = 0; - else if (y < image_height + 1) real_y = y - 1; - else real_y = image_height - 1; - - for (int x = 0; x < image_stride + 2; x += macro_block_width) + if (!alpha_texture) + { + // Normal mode + data = (uint32_t *) data8; + } + else if (!plane) { - uint8_t *offset = buffer; - int real_x = x; + int len = image_stride * image_height; + // RGB plane for ETC1+Alpha + data = malloc(len * 4); + if (!data) goto finish; + memcpy(data, data8, len * 4); + if (unpremul) _eet_argb_unpremul(data, len); + } + else + { + // Alpha plane for ETC1+Alpha + _alpha_to_greyscale_convert(data, image_stride * image_height); + } - if (x == 0) real_x = 0; - else if (x < image_stride + 1) real_x = x - 1; - else real_x = image_stride - 1; + // Write macro block + for (int y = 0; y < image_height + 2; y += macro_block_height) + { + uint32_t *input, *last_col, *last_row, *last_pix; + int real_y; + int wlen; - input = data + real_y * image_stride + real_x; - last_row = data + image_stride * (image_height - 1) + real_x; - last_col = data + (real_y + 1) * image_stride - 1; - last_pix = data + image_height * image_stride - 1; + if (y == 0) real_y = 0; + else if (y < image_height + 1) real_y = y - 1; + else real_y = image_height - 1; - for (int by = 0; by < macro_block_height; by += 4) + for (int x = 0; x < image_stride + 2; x += macro_block_width) { - int dup_top = ((y + by) == 0) ? 1 : 0; - int max_row = MAX(0, MIN(4, image_height - real_y - by)); - int oy = (y == 0) ? 1 : 0; + uint8_t *offset = buffer; + int real_x = x; + + if (x == 0) real_x = 0; + else if (x < image_stride + 1) real_x = x - 1; + else real_x = image_stride - 1; + + input = data + real_y * image_stride + real_x; + last_row = data + image_stride * (image_height - 1) + real_x; + last_col = data + (real_y + 1) * image_stride - 1; + last_pix = data + image_height * image_stride - 1; - for (int bx = 0; bx < macro_block_width; bx += 4) + for (int by = 0; by < macro_block_height; by += 4) { - int dup_left = ((x + bx) == 0) ? 1 : 0; - int max_col = MAX(0, MIN(4, image_stride - real_x - bx)); - uint32_t todo[16] = { 0 }; - int row, col; - int ox = (x == 0) ? 1 : 0; + int dup_top = ((y + by) == 0) ? 1 : 0; + int max_row = MAX(0, MIN(4, image_height - real_y - by)); + int oy = (y == 0) ? 1 : 0; - if (dup_left) + for (int bx = 0; bx < macro_block_width; bx += 4) { - // Duplicate left column - for (row = 0; row < max_row; row++) - todo[row * 4] = input[row * image_stride]; - for (row = max_row; row < 4; row++) - todo[row * 4] = last_row[0]; - } + int dup_left = ((x + bx) == 0) ? 1 : 0; + int max_col = MAX(0, MIN(4, image_stride - real_x - bx)); + uint32_t todo[16] = { 0 }; + int row, col; + int ox = (x == 0) ? 1 : 0; - if (dup_top) - { - // Duplicate top row - for (col = 0; col < max_col; col++) - todo[col] = input[MAX(col + bx - ox, 0)]; - for (col = max_col; col < 4; col++) - todo[col] = last_col[0]; - } + if (dup_left) + { + // Duplicate left column + for (row = 0; row < max_row; row++) + todo[row * 4] = input[row * image_stride]; + for (row = max_row; row < 4; row++) + todo[row * 4] = last_row[0]; + } - for (row = dup_top; row < 4; row++) - { - for (col = dup_left; col < max_col; col++) + if (dup_top) { - if (row < max_row) + // Duplicate top row + for (col = 0; col < max_col; col++) + todo[col] = input[MAX(col + bx - ox, 0)]; + for (col = max_col; col < 4; col++) + todo[col] = last_col[0]; + } + + for (row = dup_top; row < 4; row++) + { + for (col = dup_left; col < max_col; col++) { - // Normal copy - todo[row * 4 + col] = input[(row + by - oy) * image_stride + bx + col - ox]; + if (row < max_row) + { + // Normal copy + todo[row * 4 + col] = input[(row + by - oy) * image_stride + bx + col - ox]; + } + else + { + // Copy last line + todo[row * 4 + col] = last_row[col + bx - ox]; + } } - else + for (col = max_col; col < 4; col++) { - // Copy last line - todo[row * 4 + col] = last_row[col + bx - ox]; + // Right edge + if (row < max_row) + { + // Duplicate last column + todo[row * 4 + col] = last_col[MAX(row + by - oy, 0) * image_stride]; + } + else + { + // Duplicate very last pixel again and again + todo[row * 4 + col] = *last_pix; + } } } - for (col = max_col; col < 4; col++) + + switch (cspace) { - // Right edge - if (row < max_row) - { - // Duplicate last column - todo[row * 4 + col] = last_col[MAX(row + by - oy, 0) * image_stride]; - } + case EET_COLORSPACE_ETC1: + case EET_COLORSPACE_ETC1_ALPHA: + rg_etc1_pack_block(offset, (uint32_t *) todo, ¶m); + break; + case EET_COLORSPACE_RGB8_ETC2: + etc2_rgb8_block_pack(offset, (uint32_t *) todo, ¶m); + break; + case EET_COLORSPACE_RGBA8_ETC2_EAC: + etc2_rgba8_block_pack(offset, (uint32_t *) todo, ¶m); + break; + default: return 0; + } + +#ifdef DEBUG_STATS + if (plane == 0) + { + // Decode to compute PSNR, this is slow. + uint32_t done[16]; + + if (alpha) + rg_etc2_rgba8_decode_block(offset, done); else + rg_etc2_rgb8_decode_block(offset, done); + + for (int k = 0; k < 16; k++) { - // Duplicate very last pixel again and again - todo[row * 4 + col] = *last_pix; + const int r = (R_VAL(&(todo[k])) - R_VAL(&(done[k]))); + const int g = (G_VAL(&(todo[k])) - G_VAL(&(done[k]))); + const int b = (B_VAL(&(todo[k])) - B_VAL(&(done[k]))); + const int a = (A_VAL(&(todo[k])) - A_VAL(&(done[k]))); + mse += r*r + g*g + b*b; + if (alpha) mse_alpha += a*a; + mse_div++; } } - } +#endif - switch (cspace) - { - case EET_COLORSPACE_ETC1: - rg_etc1_pack_block(offset, (uint32_t *) todo, ¶m); - break; - case EET_COLORSPACE_RGB8_ETC2: - etc2_rgb8_block_pack(offset, (uint32_t *) todo, ¶m); - break; - case EET_COLORSPACE_RGBA8_ETC2_EAC: - etc2_rgba8_block_pack(offset, (uint32_t *) todo, ¶m); - break; - default: return 0; + offset += etc_block_size; } - - offset += etc_block_size; } - } - - if (compress) - { - wlen = LZ4_compressHC((char *) buffer, (char *) comp, - block_count * etc_block_size); - } - else - { - comp = buffer; - wlen = block_count * etc_block_size; - } - if (wlen > 0) - { - unsigned int blen = wlen; + if (compress) + { + wlen = LZ4_compressHC((char *) buffer, (char *) comp, + block_count * etc_block_size); + } + else + { + comp = buffer; + wlen = block_count * etc_block_size; + } - while (blen) + if (wlen > 0) { - unsigned char plen; + unsigned int blen = wlen; - plen = blen & 0x7F; - blen = blen >> 7; + while (blen) + { + unsigned char plen; + + plen = blen & 0x7F; + blen = blen >> 7; - if (blen) plen = 0x80 | plen; - eina_binbuf_append_length(r, &plen, 1); + if (blen) plen = 0x80 | plen; + eina_binbuf_append_length(r, &plen, 1); + } + eina_binbuf_append_length(r, (unsigned char *) comp, wlen); } - eina_binbuf_append_length(r, (unsigned char *) comp, wlen); - } - } - } + } // 4 rows + } // macroblocks + } // planes +finish: + if (alpha_texture) free(data); *size = eina_binbuf_length_get(r); result = eina_binbuf_string_steal(r); eina_binbuf_free(r); @@ -1871,6 +2068,7 @@ eet_data_image_encode_cipher(const void *data, if (alpha) abort(); // fallthrough case EET_IMAGE_ETC2_RGBA: + case EET_IMAGE_ETC1_ALPHA: d = eet_data_image_etc1_compressed_convert(&size, data, w, h, quality, comp, lossy); break; @@ -2065,6 +2263,10 @@ eet_data_image_header_decode_cipher(const void *data, if (alpha) *alpha = EINA_TRUE; if (lossy) *lossy = EET_IMAGE_ETC2_RGBA; break; + case 3: + if (alpha) *alpha = EINA_TRUE; + if (lossy) *lossy = EET_IMAGE_ETC1_ALPHA; + break; default: return 0; } @@ -2111,6 +2313,11 @@ static const Eet_Colorspace _eet_etc1_colorspace[] = { EET_COLORSPACE_ARGB8888 }; +static const Eet_Colorspace _eet_etc1_alpha_colorspace[] = { + EET_COLORSPACE_ETC1_ALPHA, + EET_COLORSPACE_ARGB8888 +}; + static const Eet_Colorspace _eet_etc2_rgb_colorspace[] = { EET_COLORSPACE_RGB8_ETC2, EET_COLORSPACE_ARGB8888 @@ -2141,6 +2348,8 @@ eet_data_image_colorspace_get(Eet_File *ef, *cspaces = _eet_etc2_rgb_colorspace; else if (lossy == EET_IMAGE_ETC2_RGBA) *cspaces = _eet_etc2_rgba_colorspace; + else if (lossy == EET_IMAGE_ETC1_ALPHA) + *cspaces = _eet_etc1_alpha_colorspace; } return r; @@ -2331,7 +2540,8 @@ _eet_data_image_decode_inside(const void *data, } else if ((lossy == EET_IMAGE_ETC1) || (lossy == EET_IMAGE_ETC2_RGB) || - (lossy == EET_IMAGE_ETC2_RGBA)) + (lossy == EET_IMAGE_ETC2_RGBA) || + (lossy == EET_IMAGE_ETC1_ALPHA)) { return eet_data_image_etc2_decode(data, size, d, src_x, src_y, src_w, src_h, @@ -2481,6 +2691,10 @@ eet_data_image_decode_to_cspace_surface_cipher(const void *data, ilossy != EET_IMAGE_ETC2_RGBA) return 0; + if (cspace == EET_COLORSPACE_ETC1_ALPHA && + ilossy != EET_IMAGE_ETC1_ALPHA) + return 0; + if (cspace == EET_COLORSPACE_ARGB8888 && w * 4 > row_stride) return 0; --
