forked from enlightenment/efl
Evas TGV: Fix distortion of TGV images (ETC1)
Due to some invalid geometry considerations, there was a 1 pixel distortion in images, varying with the lz4 compressed macro-block size. Anyhow, I couldn't wrap my head around Cedric's code. So I rewrote the whole thing instead, fixed it and improved the block size selection (based on the image size, to optimize lz4 compression).
This commit is contained in:
parent
709c1d86c0
commit
28ce791dfa
|
@ -37,6 +37,11 @@
|
||||||
#define OFFSET_HEIGHT 12
|
#define OFFSET_HEIGHT 12
|
||||||
#define OFFSET_BLOCKS 16
|
#define OFFSET_BLOCKS 16
|
||||||
|
|
||||||
|
#undef MIN
|
||||||
|
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
|
||||||
|
|
||||||
|
#undef MAX
|
||||||
|
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
|
||||||
|
|
||||||
/*---*/
|
/*---*/
|
||||||
|
|
||||||
|
@ -993,160 +998,186 @@ eet_data_image_lossless_compressed_convert(int *size,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_block_size_get(int size)
|
||||||
|
{
|
||||||
|
static const int MAX_BLOCK = 6; // 256 pixels
|
||||||
|
|
||||||
|
int k = 0;
|
||||||
|
while ((4 << k) < size) k++;
|
||||||
|
k = MAX(0, k - 1);
|
||||||
|
if ((size * 3 / 2) >= (4 << k)) return MAX(0, MIN(k - 1, MAX_BLOCK));
|
||||||
|
return MIN(k, MAX_BLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
eet_data_image_etc1_compressed_convert(int *size,
|
eet_data_image_etc1_compressed_convert(int *size,
|
||||||
const unsigned char *data8,
|
const unsigned char *data8,
|
||||||
unsigned int w,
|
unsigned int w,
|
||||||
unsigned int h,
|
unsigned int h,
|
||||||
int quality,
|
int quality,
|
||||||
int compression)
|
int compress)
|
||||||
{
|
{
|
||||||
Eina_Binbuf *r;
|
|
||||||
rg_etc1_pack_params param;
|
rg_etc1_pack_params param;
|
||||||
unsigned char header[8] = "TGV1";
|
|
||||||
unsigned int nw, nh;
|
|
||||||
unsigned int block, block_count;
|
|
||||||
unsigned int x, y;
|
|
||||||
unsigned int compress_length;
|
|
||||||
unsigned int real_x, real_y;
|
|
||||||
unsigned int *data = (unsigned int *) data8;
|
|
||||||
char *comp;
|
char *comp;
|
||||||
char *buffer;
|
char *buffer;
|
||||||
|
uint32_t *data;
|
||||||
|
uint32_t width, height;
|
||||||
|
uint8_t header[8] = "TGV1";
|
||||||
|
int block_width, block_height, macro_block_width, macro_block_height;
|
||||||
|
int block_count, image_stride, image_height;
|
||||||
|
Eina_Binbuf *r;
|
||||||
void *result;
|
void *result;
|
||||||
|
|
||||||
r = eina_binbuf_new();
|
r = eina_binbuf_new();
|
||||||
if (!r) return NULL;
|
if (!r) return NULL;
|
||||||
|
|
||||||
nw = htonl(w);
|
image_stride = w;
|
||||||
nh = htonl(h);
|
image_height = h;
|
||||||
|
data = (uint32_t *) data8;
|
||||||
|
width = htonl(image_stride);
|
||||||
|
height = htonl(image_height);
|
||||||
|
|
||||||
// Disable dithering, as it will deteriorate the quality of flat surfaces
|
// Disable dithering, as it will deteriorate the quality of flat surfaces
|
||||||
param.m_dithering = 0;
|
param.m_dithering = 0;
|
||||||
|
|
||||||
if (quality > 95)
|
if (quality > 95)
|
||||||
{
|
param.m_quality = rg_etc1_high_quality;
|
||||||
param.m_quality = rg_etc1_high_quality;
|
|
||||||
block = 7;
|
|
||||||
}
|
|
||||||
else if (quality > 30)
|
else if (quality > 30)
|
||||||
{
|
param.m_quality = rg_etc1_medium_quality;
|
||||||
param.m_quality = rg_etc1_medium_quality;
|
|
||||||
block = 6;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
param.m_quality = rg_etc1_low_quality;
|
||||||
param.m_quality = rg_etc1_low_quality;
|
|
||||||
block = 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
header[4] = (block << 4) | block;
|
// header[4]: 4 bit block width, 4 bit block height
|
||||||
|
block_width = _block_size_get(image_stride + 2);
|
||||||
|
block_height = _block_size_get(image_height + 2);
|
||||||
|
header[4] = (block_height << 4) | block_width;
|
||||||
|
|
||||||
|
// header[5]: 0 for ETC1
|
||||||
header[5] = 0;
|
header[5] = 0;
|
||||||
header[6] = (!!compression & 0x1); // For now only LZ4 compression
|
|
||||||
|
// header[6]: 0 for raw, 1, for LZ4 compressed
|
||||||
|
header[6] = (!!compress & 0x1);
|
||||||
|
|
||||||
|
// header[7]: options (unused)
|
||||||
header[7] = 0;
|
header[7] = 0;
|
||||||
|
|
||||||
|
// Write header
|
||||||
eina_binbuf_append_length(r, header, sizeof (header));
|
eina_binbuf_append_length(r, header, sizeof (header));
|
||||||
eina_binbuf_append_length(r, (unsigned char*) &nw, sizeof (nw));
|
eina_binbuf_append_length(r, (unsigned char*) &width, sizeof (width));
|
||||||
eina_binbuf_append_length(r, (unsigned char*) &nh, sizeof (nh));
|
eina_binbuf_append_length(r, (unsigned char*) &height, sizeof (height));
|
||||||
|
|
||||||
block = 4 << block;
|
// Real block size in pixels, obviously a multiple of 4
|
||||||
block_count = (block * block) / (4 * 4);
|
macro_block_width = 4 << block_width;
|
||||||
|
macro_block_height = 4 << block_height;
|
||||||
|
|
||||||
|
// Number of ETC1 blocks in a compressed block
|
||||||
|
block_count = (macro_block_width * macro_block_height) / (4 * 4);
|
||||||
buffer = alloca(block_count * 8);
|
buffer = alloca(block_count * 8);
|
||||||
|
|
||||||
if (compression)
|
if (compress)
|
||||||
{
|
{
|
||||||
compress_length = LZ4_compressBound(block_count * 8);
|
comp = alloca(LZ4_compressBound(block_count * 8));
|
||||||
comp = alloca(compress_length);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
comp = NULL;
|
comp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write block
|
// Write macro block
|
||||||
for (y = 0; y < h + 2; y += block)
|
for (int y = 0; y < image_height + 2; y += macro_block_height)
|
||||||
{
|
{
|
||||||
real_y = y > 0 ? y - 1 : 0;
|
uint32_t *input, *last_col, *last_row, *last_pix;
|
||||||
|
int real_y;
|
||||||
|
int wlen;
|
||||||
|
|
||||||
for (x = 0; x < w + 2; x += block)
|
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)
|
||||||
{
|
{
|
||||||
unsigned int i, j;
|
|
||||||
unsigned char duplicate_w[2], duplicate_h[2];
|
|
||||||
int wlen;
|
|
||||||
char *offset = buffer;
|
char *offset = buffer;
|
||||||
|
int real_x = x;
|
||||||
|
|
||||||
real_x = x > 0 ? x - 1 : 0;
|
if (x == 0) real_x = 0;
|
||||||
|
else if (x < image_stride + 1) real_x = x - 1;
|
||||||
|
else real_x = image_stride - 1;
|
||||||
|
|
||||||
for (i = 0; i < block; i += 4)
|
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 by = 0; by < macro_block_height; by += 4)
|
||||||
{
|
{
|
||||||
unsigned char block_h;
|
int dup_top = ((y + by) == 0) ? 1 : 0;
|
||||||
int kmax;
|
int max_row = MAX(0, MIN(4, image_height - real_y - by));
|
||||||
|
int oy = (y == 0) ? 1 : 0;
|
||||||
|
|
||||||
duplicate_h[0] = !!((real_y + i) == 0);
|
for (int bx = 0; bx < macro_block_width; bx += 4)
|
||||||
duplicate_h[1] = !!((real_y + i + (4 - duplicate_h[0])) >= h);
|
|
||||||
block_h = 4 - duplicate_h[0] - duplicate_h[1];
|
|
||||||
|
|
||||||
kmax = real_y + i + block_h < h ?
|
|
||||||
block_h : h - real_y - i - 1;
|
|
||||||
|
|
||||||
for (j = 0; j < block; j += 4)
|
|
||||||
{
|
{
|
||||||
unsigned char todo[64] = { 0 };
|
int dup_left = ((x + bx) == 0) ? 1 : 0;
|
||||||
unsigned char block_w;
|
int max_col = MAX(0, MIN(4, image_stride - real_x - bx));
|
||||||
int block_length;
|
uint32_t todo[16] = { 0 };
|
||||||
int k, lmax;
|
int row, col;
|
||||||
|
int ox = (x == 0) ? 1 : 0;
|
||||||
|
|
||||||
|
if (dup_left)
|
||||||
duplicate_w[0] = !!((real_x + j) == 0);
|
|
||||||
duplicate_w[1] = !!(((real_x + j + (4 - duplicate_w[0]))) >= w);
|
|
||||||
block_w = 4 - duplicate_w[0] - duplicate_w[1];
|
|
||||||
|
|
||||||
lmax = real_x + j + block_w < w ?
|
|
||||||
block_w : w - real_x - j - 1;
|
|
||||||
block_length = real_x + j + 4 < w ?
|
|
||||||
4 : w - real_x - j - 1;
|
|
||||||
|
|
||||||
if (lmax > 0)
|
|
||||||
{
|
{
|
||||||
for (k = 0; k < kmax; k++)
|
// Duplicate left column
|
||||||
memcpy(&todo[(k + duplicate_h[0]) * 16 + duplicate_w[0] * 4],
|
for (row = 0; row < max_row; row++)
|
||||||
&data[(real_y + i + k) * w + real_x + j],
|
todo[row * 4] = input[row * image_stride];
|
||||||
4 * lmax);
|
for (row = max_row; row < 4; row++)
|
||||||
|
todo[row * 4] = last_row[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dup_top)
|
||||||
if (duplicate_h[0] && block_length > 0) // Duplicate first line
|
|
||||||
memcpy(&todo[0],
|
|
||||||
&data[(real_y + i) * w + real_x + j],
|
|
||||||
block_length * 4);
|
|
||||||
|
|
||||||
if (duplicate_h[1] && block_length > 0 && kmax >= 0) // Duplicate last line
|
|
||||||
memcpy(&todo[kmax * 16],
|
|
||||||
&data[(real_y + i + kmax) * w + real_x + j],
|
|
||||||
block_length * 4);
|
|
||||||
|
|
||||||
if (duplicate_w[0]) // Duplicate first row
|
|
||||||
{
|
{
|
||||||
for (k = 0; k < kmax; k++)
|
// Duplicate top row
|
||||||
memcpy(&todo[(k + duplicate_h[0]) * 16],
|
for (col = 0; col < max_col; col++)
|
||||||
&data[(real_y + i + k) * w + real_x + j],
|
todo[col] = input[MAX(col + bx - ox, 0)];
|
||||||
4); // Copy a pixel at a time
|
for (col = max_col; col < 4; col++)
|
||||||
|
todo[col] = last_col[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (duplicate_w[1] && lmax >= 0) // Duplicate last row
|
for (row = dup_top; row < 4; row++)
|
||||||
{
|
{
|
||||||
for (k = 0; k < kmax; k++)
|
for (col = dup_left; col < max_col; col++)
|
||||||
memcpy(&todo[(k + duplicate_h[0]) * 16 + (duplicate_w[0] + lmax) * 4],
|
{
|
||||||
&data[(real_y + i + k) * w + real_x + j + lmax],
|
if (row < max_row)
|
||||||
4); // Copy a pixel at a time
|
{
|
||||||
|
// 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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (col = max_col; col < 4; col++)
|
||||||
|
{
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
rg_etc1_pack_block(offset, (unsigned int*) todo, ¶m);
|
rg_etc1_pack_block(offset, (unsigned int*) todo, ¶m);
|
||||||
offset += 8;
|
offset += 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compression)
|
if (compress)
|
||||||
{
|
{
|
||||||
wlen = LZ4_compressHC(buffer, comp, block_count * 8);
|
wlen = LZ4_compressHC(buffer, comp, block_count * 8);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,18 @@
|
||||||
#include "lz4hc.h"
|
#include "lz4hc.h"
|
||||||
#include "rg_etc1.h"
|
#include "rg_etc1.h"
|
||||||
|
|
||||||
|
static int
|
||||||
|
_block_size_get(int size)
|
||||||
|
{
|
||||||
|
static const int MAX_BLOCK = 6; // 256 pixels
|
||||||
|
|
||||||
|
int k = 0;
|
||||||
|
while ((4 << k) < size) k++;
|
||||||
|
k = MAX(0, k - 1);
|
||||||
|
if ((size * 3 / 2) >= (4 << k)) return MAX(0, MIN(k - 1, MAX_BLOCK));
|
||||||
|
return MIN(k, MAX_BLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
evas_image_save_file_tgv(RGBA_Image *im,
|
evas_image_save_file_tgv(RGBA_Image *im,
|
||||||
const char *file, const char *key EINA_UNUSED,
|
const char *file, const char *key EINA_UNUSED,
|
||||||
|
@ -25,11 +37,8 @@ evas_image_save_file_tgv(RGBA_Image *im,
|
||||||
uint32_t *data;
|
uint32_t *data;
|
||||||
uint32_t width, height;
|
uint32_t width, height;
|
||||||
uint8_t header[8] = "TGV1";
|
uint8_t header[8] = "TGV1";
|
||||||
unsigned int block;
|
int block_width, block_height, macro_block_width, macro_block_height;
|
||||||
unsigned int x, y;
|
int block_count, image_stride, image_height;
|
||||||
unsigned int compress_length;
|
|
||||||
unsigned int block_count;
|
|
||||||
unsigned int real_x, real_y;
|
|
||||||
|
|
||||||
if (!im || !im->image.data || !file)
|
if (!im || !im->image.data || !file)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -38,17 +47,19 @@ evas_image_save_file_tgv(RGBA_Image *im,
|
||||||
if (im->cache_entry.flags.alpha)
|
if (im->cache_entry.flags.alpha)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
// Only RGBA encoding for now. TODO: Direct copy of ETC1/2 blocks.
|
||||||
|
if (im->cache_entry.space != EVAS_COLORSPACE_ARGB8888)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
image_stride = im->cache_entry.w;
|
||||||
|
image_height = im->cache_entry.h;
|
||||||
data = im->image.data;
|
data = im->image.data;
|
||||||
width = htonl(im->cache_entry.w);
|
width = htonl(image_stride);
|
||||||
height = htonl(im->cache_entry.h);
|
height = htonl(image_height);
|
||||||
|
|
||||||
// Disable dithering, as it will deteriorate the quality of flat surfaces
|
// Disable dithering, as it will deteriorate the quality of flat surfaces
|
||||||
param.m_dithering = 0;
|
param.m_dithering = 0;
|
||||||
|
|
||||||
// FIXME: Depending on the block size, we have some distortion of the image
|
|
||||||
// Usually, one or two pixels on the top & left borders are removed
|
|
||||||
block = 6;
|
|
||||||
|
|
||||||
if (quality > 95)
|
if (quality > 95)
|
||||||
param.m_quality = rg_etc1_high_quality;
|
param.m_quality = rg_etc1_high_quality;
|
||||||
else if (quality > 30)
|
else if (quality > 30)
|
||||||
|
@ -56,9 +67,18 @@ evas_image_save_file_tgv(RGBA_Image *im,
|
||||||
else
|
else
|
||||||
param.m_quality = rg_etc1_low_quality;
|
param.m_quality = rg_etc1_low_quality;
|
||||||
|
|
||||||
header[4] = (block << 4) | block;
|
// header[4]: 4 bit block width, 4 bit block height
|
||||||
|
block_width = _block_size_get(image_stride + 2);
|
||||||
|
block_height = _block_size_get(image_height + 2);
|
||||||
|
header[4] = (block_height << 4) | block_width;
|
||||||
|
|
||||||
|
// header[5]: 0 for ETC1
|
||||||
header[5] = 0;
|
header[5] = 0;
|
||||||
|
|
||||||
|
// header[6]: 0 for raw, 1, for LZ4 compressed
|
||||||
header[6] = (!!compress & 0x1);
|
header[6] = (!!compress & 0x1);
|
||||||
|
|
||||||
|
// header[7]: options (unused)
|
||||||
header[7] = 0;
|
header[7] = 0;
|
||||||
|
|
||||||
f = fopen(file, "w");
|
f = fopen(file, "w");
|
||||||
|
@ -69,88 +89,109 @@ evas_image_save_file_tgv(RGBA_Image *im,
|
||||||
if (fwrite(&width, sizeof (uint32_t), 1, f) != 1) goto on_error;
|
if (fwrite(&width, sizeof (uint32_t), 1, f) != 1) goto on_error;
|
||||||
if (fwrite(&height, sizeof (uint32_t), 1, f) != 1) goto on_error;
|
if (fwrite(&height, sizeof (uint32_t), 1, f) != 1) goto on_error;
|
||||||
|
|
||||||
block = 4 << block;
|
// Real block size in pixels, obviously a multiple of 4
|
||||||
|
macro_block_width = 4 << block_width;
|
||||||
|
macro_block_height = 4 << block_height;
|
||||||
|
|
||||||
block_count = (block * block) / (4 * 4);
|
// Number of ETC1 blocks in a compressed block
|
||||||
|
block_count = (macro_block_width * macro_block_height) / (4 * 4);
|
||||||
buffer = alloca(block_count * 8);
|
buffer = alloca(block_count * 8);
|
||||||
|
|
||||||
if (compress)
|
if (compress)
|
||||||
{
|
{
|
||||||
compress_length = LZ4_compressBound(block_count * 8);
|
comp = alloca(LZ4_compressBound(block_count * 8));
|
||||||
comp = alloca(compress_length);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
comp = NULL;
|
comp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write block
|
// Write macro block
|
||||||
for (y = 0; y < im->cache_entry.h + 2; y += block)
|
for (int y = 0; y < image_height + 2; y += macro_block_height)
|
||||||
{
|
{
|
||||||
real_y = y > 0 ? y - 1 : 0;
|
uint32_t *input, *last_col, *last_row, *last_pix;
|
||||||
|
int real_y;
|
||||||
|
int wlen;
|
||||||
|
|
||||||
for (x = 0; x < im->cache_entry.w + 2; x += block)
|
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)
|
||||||
{
|
{
|
||||||
unsigned int i, j;
|
|
||||||
unsigned char duplicate_w[2], duplicate_h[2];
|
|
||||||
int wlen;
|
|
||||||
char *offset = buffer;
|
char *offset = buffer;
|
||||||
|
int real_x = x;
|
||||||
|
|
||||||
real_x = x > 0 ? x - 1 : 0;
|
if (x == 0) real_x = 0;
|
||||||
|
else if (x < image_stride + 1) real_x = x - 1;
|
||||||
|
else real_x = image_stride - 1;
|
||||||
|
|
||||||
for (i = 0; i < block; i += 4)
|
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 by = 0; by < macro_block_height; by += 4)
|
||||||
{
|
{
|
||||||
unsigned char block_h;
|
int dup_top = ((y + by) == 0) ? 1 : 0;
|
||||||
int kmax;
|
int max_row = MAX(0, MIN(4, image_height - real_y - by));
|
||||||
|
int oy = (y == 0) ? 1 : 0;
|
||||||
|
|
||||||
duplicate_h[0] = !!((real_y + i) == 0);
|
for (int bx = 0; bx < macro_block_width; bx += 4)
|
||||||
duplicate_h[1] = !!((real_y + i + (4 - duplicate_h[0])) >= im->cache_entry.h);
|
|
||||||
block_h = 4 - duplicate_h[0] - duplicate_h[1];
|
|
||||||
|
|
||||||
kmax = real_y + i + block_h < im->cache_entry.h ?
|
|
||||||
block_h : im->cache_entry.h - real_y - i - 1;
|
|
||||||
|
|
||||||
for (j = 0; j < block; j += 4)
|
|
||||||
{
|
{
|
||||||
unsigned char todo[64] = { 0 };
|
int dup_left = ((x + bx) == 0) ? 1 : 0;
|
||||||
unsigned char block_w;
|
int max_col = MAX(0, MIN(4, image_stride - real_x - bx));
|
||||||
int block_length;
|
uint32_t todo[16] = { 0 };
|
||||||
int k, lmax;
|
int row, col;
|
||||||
|
int ox = (x == 0) ? 1 : 0;
|
||||||
|
|
||||||
duplicate_w[0] = !!((real_x + j) == 0);
|
if (dup_left)
|
||||||
duplicate_w[1] = !!(((real_x + j + (4 - duplicate_w[0]))) >= im->cache_entry.w);
|
|
||||||
block_w = 4 - duplicate_w[0] - duplicate_w[1];
|
|
||||||
|
|
||||||
lmax = real_x + j + block_w < im->cache_entry.w ?
|
|
||||||
block_w : im->cache_entry.w - real_x - j - 1;
|
|
||||||
block_length = real_x + j + 4 < im->cache_entry.w ?
|
|
||||||
4 : im->cache_entry.w - real_x - j - 1;
|
|
||||||
|
|
||||||
if (lmax > 0)
|
|
||||||
{
|
{
|
||||||
for (k = 0; k < kmax; k++)
|
// Duplicate left column
|
||||||
memcpy(&todo[(k + duplicate_h[0]) * 16 + duplicate_w[0] * 4],
|
for (row = 0; row < max_row; row++)
|
||||||
&data[(real_y + i + k) * im->cache_entry.w + real_x + j],
|
todo[row * 4] = input[row * image_stride];
|
||||||
4 * lmax);
|
for (row = max_row; row < 4; row++)
|
||||||
|
todo[row * 4] = last_row[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (duplicate_h[0] && block_length > 0) // Duplicate first line
|
if (dup_top)
|
||||||
memcpy(&todo[0], &data[(real_y + i) * im->cache_entry.w + real_x + j], block_length * 4);
|
|
||||||
if (duplicate_h[1] && block_length > 0 && kmax >= 0) // Duplicate last line
|
|
||||||
memcpy(&todo[kmax * 16], &data[(real_y + i + kmax) * im->cache_entry.w + real_x + j], block_length * 4);
|
|
||||||
if (duplicate_w[0]) // Duplicate first row
|
|
||||||
{
|
{
|
||||||
for (k = 0; k < kmax; k++)
|
// Duplicate top row
|
||||||
memcpy(&todo[(k + duplicate_h[0]) * 16],
|
for (col = 0; col < max_col; col++)
|
||||||
&data[(real_y + i + k) * im->cache_entry.w + real_x + j],
|
todo[col] = input[MAX(col + bx - ox, 0)];
|
||||||
4); // Copy a pixel at a time
|
for (col = max_col; col < 4; col++)
|
||||||
|
todo[col] = last_col[0];
|
||||||
}
|
}
|
||||||
if (duplicate_w[1] && lmax >= 0) // Duplicate last row
|
|
||||||
|
for (row = dup_top; row < 4; row++)
|
||||||
{
|
{
|
||||||
for (k = 0; k < kmax; k++)
|
for (col = dup_left; col < max_col; col++)
|
||||||
memcpy(&todo[(k + duplicate_h[0]) * 16 + (duplicate_w[0] + lmax) * 4],
|
{
|
||||||
&data[(real_y + i + k) * im->cache_entry.w + real_x + j + lmax],
|
if (row < max_row)
|
||||||
4); // Copy a pixel at a time
|
{
|
||||||
|
// 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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (col = max_col; col < 4; col++)
|
||||||
|
{
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rg_etc1_pack_block(offset, (unsigned int*) todo, ¶m);
|
rg_etc1_pack_block(offset, (unsigned int*) todo, ¶m);
|
||||||
|
|
Loading…
Reference in New Issue