2013-12-08 23:43:52 -08:00
|
|
|
#include "evas_filter.h"
|
|
|
|
#include "evas_filter_private.h"
|
|
|
|
|
|
|
|
static void
|
2014-01-06 17:16:39 -08:00
|
|
|
_filter_displace_cpu_alpha_do(int w, int h, int map_w, int map_h, int intensity,
|
2014-02-17 02:54:47 -08:00
|
|
|
DATA8 *src, DATA8 *dst, DATA32 *map_start,
|
2014-01-06 18:03:46 -08:00
|
|
|
Eina_Bool stretch, Eina_Bool smooth,
|
|
|
|
Eina_Bool blend)
|
2013-12-08 23:43:52 -08:00
|
|
|
{
|
|
|
|
int x, y, map_x, map_y;
|
2014-01-06 17:16:39 -08:00
|
|
|
const int dx = RED;
|
|
|
|
const int dy = GREEN;
|
2013-12-08 23:43:52 -08:00
|
|
|
DATA8 *map;
|
|
|
|
|
|
|
|
for (y = 0, map_y = 0; y < h; y++, map_y++)
|
|
|
|
{
|
|
|
|
if (map_y >= map_h) map_y = 0;
|
2014-02-17 02:54:47 -08:00
|
|
|
map = (DATA8 *) (map_start + map_y * map_w);
|
2013-12-08 23:43:52 -08:00
|
|
|
|
2014-02-17 02:37:32 -08:00
|
|
|
for (x = 0, map_x = 0; x < w;
|
|
|
|
x++, dst++, src++, map_x++, map += sizeof(DATA32))
|
2013-12-08 23:43:52 -08:00
|
|
|
{
|
|
|
|
int offx = 0, offy = 0, offx_dec = 0, offy_dec = 0, val = 0;
|
|
|
|
Eina_Bool out = 0;
|
|
|
|
|
2014-01-06 18:03:46 -08:00
|
|
|
// wrap around (x)
|
2013-12-08 23:43:52 -08:00
|
|
|
if (map_x >= map_w)
|
|
|
|
{
|
|
|
|
map_x = 0;
|
2014-02-17 02:54:47 -08:00
|
|
|
map = (DATA8 *) (map_start + map_y * map_w);
|
2013-12-08 23:43:52 -08:00
|
|
|
}
|
|
|
|
|
2014-01-06 18:03:46 -08:00
|
|
|
// x
|
2014-01-06 17:16:39 -08:00
|
|
|
val = ((int) map[dx] - 128) * intensity;
|
|
|
|
offx = val >> 7;
|
|
|
|
offx_dec = val & 0x7f;
|
|
|
|
if ((x + offx) < 0) { offx = -x; out = 1; }
|
|
|
|
if ((x + offx + 1) >= w) { offx = w - x - 2; out = 1; }
|
|
|
|
|
2014-01-06 18:03:46 -08:00
|
|
|
// y
|
2014-01-06 17:16:39 -08:00
|
|
|
val = ((int) map[dy] - 128) * intensity;
|
|
|
|
offy = val >> 7;
|
|
|
|
offy_dec = val & 0x7f;
|
|
|
|
if ((y + offy) < 0) { offy = -y; out = 1; }
|
|
|
|
if ((y + offy + 1) >= h) { offy = h - y - 2; out = 1; }
|
2013-12-08 23:43:52 -08:00
|
|
|
|
2014-01-06 18:03:46 -08:00
|
|
|
// get value
|
2013-12-08 23:43:52 -08:00
|
|
|
if (out && !stretch)
|
2014-01-06 18:03:46 -08:00
|
|
|
val = 0;
|
2013-12-08 23:43:52 -08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!smooth)
|
2014-01-06 18:03:46 -08:00
|
|
|
val = src[offx + offy * w];
|
2014-01-06 17:16:39 -08:00
|
|
|
else
|
2013-12-08 23:43:52 -08:00
|
|
|
{
|
|
|
|
val = src[offx + offy * w] * (128 - offx_dec) * (128 - offy_dec);
|
|
|
|
val += src[offx + 1 + offy * w] * offx_dec * (128 - offy_dec);
|
|
|
|
val += src[offx + (offy + 1) * w] * (128 - offx_dec) * offy_dec;
|
|
|
|
val += src[offx + 1 + (offy + 1) * w] * offx_dec * offy_dec;
|
2014-01-06 18:03:46 -08:00
|
|
|
val = val >> 14; // <=> *dst = val / (128 * 128)
|
2013-12-08 23:43:52 -08:00
|
|
|
}
|
|
|
|
}
|
2014-01-06 18:03:46 -08:00
|
|
|
|
|
|
|
// apply alpha
|
|
|
|
if (map[ALPHA] != 255)
|
|
|
|
val = (val * map[ALPHA]) / 255;
|
|
|
|
|
|
|
|
// write to dest
|
|
|
|
if (blend)
|
|
|
|
*dst = (*dst * (255 - val)) / 255 + val;
|
|
|
|
else
|
|
|
|
*dst = val;
|
2013-12-08 23:43:52 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2014-01-06 17:16:39 -08:00
|
|
|
_filter_displace_cpu_rgba_do(int w, int h, int map_w, int map_h, int intensity,
|
2014-02-13 23:50:31 -08:00
|
|
|
DATA32 *src, DATA32 *dst, DATA32 *map_start,
|
2014-01-06 18:03:46 -08:00
|
|
|
Eina_Bool stretch, Eina_Bool smooth,
|
|
|
|
Eina_Bool blend)
|
2013-12-08 23:43:52 -08:00
|
|
|
{
|
|
|
|
int x, y, map_x, map_y;
|
2014-01-06 17:16:39 -08:00
|
|
|
const int dx = RED;
|
|
|
|
const int dy = GREEN;
|
2014-02-13 23:50:31 -08:00
|
|
|
Eina_Bool unpremul = EINA_FALSE;
|
2013-12-08 23:43:52 -08:00
|
|
|
DATA8 *map;
|
|
|
|
|
|
|
|
for (y = 0, map_y = 0; y < h; y++, map_y++)
|
|
|
|
{
|
|
|
|
if (map_y >= map_h) map_y = 0;
|
2014-02-13 23:50:31 -08:00
|
|
|
map = (DATA8 *) (map_start + map_y * map_w);
|
2013-12-08 23:43:52 -08:00
|
|
|
|
2014-02-17 02:37:32 -08:00
|
|
|
for (x = 0, map_x = 0; x < w;
|
|
|
|
x++, dst++, src++, map_x++, map += sizeof(DATA32))
|
2013-12-08 23:43:52 -08:00
|
|
|
{
|
|
|
|
int offx = 0, offy = 0, offx_dec = 0, offy_dec = 0, val = 0;
|
2014-02-13 23:28:35 -08:00
|
|
|
DATA32 col = 0;
|
2013-12-08 23:43:52 -08:00
|
|
|
Eina_Bool out = 0;
|
|
|
|
|
2014-01-06 18:03:46 -08:00
|
|
|
// wrap (x)
|
2013-12-08 23:43:52 -08:00
|
|
|
if (map_x >= map_w)
|
|
|
|
{
|
|
|
|
map_x = 0;
|
2014-02-13 23:50:31 -08:00
|
|
|
map = (DATA8 *) (map_start + map_y * map_w);
|
2013-12-08 23:43:52 -08:00
|
|
|
}
|
|
|
|
|
2014-02-13 23:50:31 -08:00
|
|
|
if (!map[ALPHA]) continue;
|
|
|
|
if (!unpremul && map[ALPHA] != 0xFF)
|
|
|
|
{
|
|
|
|
unpremul = EINA_TRUE;
|
|
|
|
evas_data_argb_unpremul(map_start, map_w * map_h);
|
|
|
|
}
|
|
|
|
|
2014-01-06 18:03:46 -08:00
|
|
|
// x
|
2014-01-06 17:16:39 -08:00
|
|
|
val = ((int) map[dx] - 128) * intensity;
|
|
|
|
offx = val >> 7;
|
|
|
|
offx_dec = val & 0x7f;
|
|
|
|
if ((x + offx) < 0) { offx = -x; out = 1; }
|
|
|
|
if ((x + offx + 1) >= w) { offx = w - x - 2; out = 1; }
|
|
|
|
|
2014-01-06 18:03:46 -08:00
|
|
|
// y
|
2014-01-06 17:16:39 -08:00
|
|
|
val = ((int) map[dy] - 128) * intensity;
|
|
|
|
offy = val >> 7;
|
|
|
|
offy_dec = val & 0x7f;
|
|
|
|
if ((y + offy) < 0) { offy = -y; out = 1; }
|
|
|
|
if ((y + offy + 1) >= h) { offy = h - y - 2; out = 1; }
|
2013-12-08 23:43:52 -08:00
|
|
|
|
2014-01-06 18:03:46 -08:00
|
|
|
// get value
|
2013-12-08 23:43:52 -08:00
|
|
|
if (out && !stretch)
|
2014-02-13 23:28:35 -08:00
|
|
|
col = A_VAL(src + offx + offy * w) << (ALPHA * 8);
|
2013-12-08 23:43:52 -08:00
|
|
|
else if (!smooth)
|
2014-02-13 23:28:35 -08:00
|
|
|
col = src[offx + offy * w];
|
2014-01-06 17:16:39 -08:00
|
|
|
else
|
2013-12-08 23:43:52 -08:00
|
|
|
{
|
|
|
|
int R, G, B, A;
|
|
|
|
DATA32 s00, s01, s10, s11; // indexes represent x,y
|
|
|
|
int mul00, mul01, mul10, mul11;
|
|
|
|
|
2014-02-13 23:28:35 -08:00
|
|
|
mul00 = (128 - offx_dec) * (128 - offy_dec);
|
2013-12-08 23:43:52 -08:00
|
|
|
mul01 = (128 - offx_dec) * offy_dec;
|
|
|
|
mul10 = offx_dec * (128 - offy_dec);
|
|
|
|
mul11 = offx_dec * offy_dec;
|
|
|
|
|
|
|
|
s00 = src[offx + offy * w];
|
|
|
|
s01 = src[offx + (offy + 1) * w];
|
|
|
|
s10 = src[offx + 1 + offy * w];
|
|
|
|
s11 = src[offx + 1 + (offy + 1) * w];
|
|
|
|
|
|
|
|
A = (ALPHA_OF(s00) * mul00) + (ALPHA_OF(s10) * mul10)
|
|
|
|
+ (ALPHA_OF(s01) * mul01) + (ALPHA_OF(s11) * mul11);
|
|
|
|
|
|
|
|
R = (RED_OF(s00) * mul00) + (RED_OF(s10) * mul10)
|
|
|
|
+ (RED_OF(s01) * mul01) + (RED_OF(s11) * mul11);
|
|
|
|
|
|
|
|
G = (GREEN_OF(s00) * mul00) + (GREEN_OF(s10) * mul10)
|
|
|
|
+ (GREEN_OF(s01) * mul01) + (GREEN_OF(s11) * mul11);
|
|
|
|
|
|
|
|
B = (BLUE_OF(s00) * mul00) + (BLUE_OF(s10) * mul10)
|
|
|
|
+ (BLUE_OF(s01) * mul01) + (BLUE_OF(s11) * mul11);
|
|
|
|
|
2014-02-13 23:28:35 -08:00
|
|
|
A >>= 14;
|
2013-12-08 23:43:52 -08:00
|
|
|
R >>= 14;
|
|
|
|
G >>= 14;
|
|
|
|
B >>= 14;
|
|
|
|
|
2014-02-13 23:28:35 -08:00
|
|
|
col = ARGB_JOIN(A, R, G, B);
|
2013-12-08 23:43:52 -08:00
|
|
|
}
|
2014-01-06 18:03:46 -08:00
|
|
|
|
2014-02-13 23:28:35 -08:00
|
|
|
if (map[ALPHA] != 0xFF)
|
|
|
|
col = MUL_256(map[ALPHA], col);
|
|
|
|
|
|
|
|
if (blend)
|
|
|
|
{
|
|
|
|
DATA32 a = 256 - ALPHA_OF(col);
|
|
|
|
*dst = col + MUL_256(a, *dst);
|
|
|
|
}
|
2014-01-06 18:03:46 -08:00
|
|
|
else
|
2014-02-13 23:28:35 -08:00
|
|
|
*dst = col;
|
2013-12-08 23:43:52 -08:00
|
|
|
}
|
|
|
|
}
|
2014-02-13 23:50:31 -08:00
|
|
|
|
|
|
|
if (unpremul)
|
|
|
|
evas_data_argb_premul(map_start, map_w * map_h);
|
2013-12-08 23:43:52 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Apply distortion map on alpha image
|
|
|
|
* input: alpha
|
|
|
|
* output: alpha
|
2014-01-06 18:03:46 -08:00
|
|
|
* map: rg+a (rgba)
|
2013-12-08 23:43:52 -08:00
|
|
|
*/
|
|
|
|
static Eina_Bool
|
|
|
|
_filter_displace_cpu_alpha(Evas_Filter_Command *cmd)
|
|
|
|
{
|
2014-01-06 17:16:39 -08:00
|
|
|
int w, h, map_w, map_h, intensity;
|
2014-02-17 02:54:47 -08:00
|
|
|
DATA8 *dst, *src;
|
|
|
|
DATA32 *map_start;
|
2014-01-06 18:03:46 -08:00
|
|
|
Eina_Bool stretch, smooth, blend;
|
2013-12-08 23:43:52 -08:00
|
|
|
|
|
|
|
w = cmd->input->w;
|
|
|
|
h = cmd->input->h;
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL(w == cmd->output->w, EINA_FALSE);
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL(h == cmd->output->h, EINA_FALSE);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->input->backing, EINA_FALSE);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->mask->backing, EINA_FALSE);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->output->backing, EINA_FALSE);
|
|
|
|
|
2014-03-03 19:05:44 -08:00
|
|
|
src = ((RGBA_Image *) cmd->input->backing)->image.data8;
|
2014-02-17 02:54:47 -08:00
|
|
|
map_start = ((RGBA_Image *) cmd->mask->backing)->image.data;
|
2014-03-03 19:05:44 -08:00
|
|
|
dst = ((RGBA_Image *) cmd->output->backing)->image.data8;
|
2013-12-08 23:43:52 -08:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(src, EINA_FALSE);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(map_start, EINA_FALSE);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(dst, EINA_FALSE);
|
|
|
|
|
|
|
|
stretch = cmd->displacement.flags & EVAS_FILTER_DISPLACE_STRETCH;
|
|
|
|
smooth = cmd->displacement.flags & EVAS_FILTER_DISPLACE_LINEAR;
|
|
|
|
map_w = cmd->mask->w;
|
|
|
|
map_h = cmd->mask->h;
|
|
|
|
intensity = cmd->displacement.intensity;
|
2014-01-06 18:03:46 -08:00
|
|
|
blend = (cmd->draw.render_op == EVAS_RENDER_BLEND);
|
2013-12-08 23:43:52 -08:00
|
|
|
|
2014-02-17 02:54:47 -08:00
|
|
|
// Stretch if necessary.
|
|
|
|
if ((map_w != w || map_h != h) && (cmd->draw.fillmode & EVAS_FILTER_FILL_MODE_STRETCH_XY))
|
|
|
|
{
|
|
|
|
Evas_Filter_Buffer *fb;
|
|
|
|
|
|
|
|
if (cmd->draw.fillmode & EVAS_FILTER_FILL_MODE_STRETCH_X)
|
|
|
|
map_w = w;
|
|
|
|
if (cmd->draw.fillmode & EVAS_FILTER_FILL_MODE_STRETCH_Y)
|
|
|
|
map_h = h;
|
|
|
|
|
|
|
|
BUFFERS_LOCK();
|
|
|
|
fb = evas_filter_buffer_scaled_get(cmd->ctx, cmd->mask, map_w, map_h);
|
|
|
|
BUFFERS_UNLOCK();
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(fb, EINA_FALSE);
|
|
|
|
fb->locked = EINA_FALSE;
|
|
|
|
map_start = ((RGBA_Image *) fb->backing)->image.data;
|
|
|
|
}
|
|
|
|
|
2014-01-06 17:16:39 -08:00
|
|
|
_filter_displace_cpu_alpha_do(w, h, map_w, map_h, intensity,
|
2014-01-06 18:03:46 -08:00
|
|
|
src, dst, map_start, stretch, smooth, blend);
|
2013-12-08 23:43:52 -08:00
|
|
|
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Apply distortion map on rgba image
|
|
|
|
* input: rgba
|
|
|
|
* output: rgba
|
2014-01-06 18:03:46 -08:00
|
|
|
* map: rg+a (rgba)
|
2013-12-08 23:43:52 -08:00
|
|
|
*/
|
|
|
|
static Eina_Bool
|
|
|
|
_filter_displace_cpu_rgba(Evas_Filter_Command *cmd)
|
|
|
|
{
|
2014-01-06 17:16:39 -08:00
|
|
|
int w, h, map_w, map_h, intensity;
|
2014-02-13 23:50:31 -08:00
|
|
|
DATA32 *dst, *src, *map_start;
|
2014-01-06 18:03:46 -08:00
|
|
|
Eina_Bool stretch, smooth, blend;
|
2013-12-08 23:43:52 -08:00
|
|
|
|
|
|
|
w = cmd->input->w;
|
|
|
|
h = cmd->input->h;
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL(w == cmd->output->w, EINA_FALSE);
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL(h == cmd->output->h, EINA_FALSE);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->input->backing, EINA_FALSE);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->mask->backing, EINA_FALSE);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->output->backing, EINA_FALSE);
|
|
|
|
|
|
|
|
src = ((RGBA_Image *) cmd->input->backing)->image.data;
|
2014-02-13 23:50:31 -08:00
|
|
|
map_start = ((RGBA_Image *) cmd->mask->backing)->image.data;
|
2013-12-08 23:43:52 -08:00
|
|
|
dst = ((RGBA_Image *) cmd->output->backing)->image.data;
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(src, EINA_FALSE);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(map_start, EINA_FALSE);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(dst, EINA_FALSE);
|
|
|
|
|
|
|
|
stretch = cmd->displacement.flags & EVAS_FILTER_DISPLACE_STRETCH;
|
|
|
|
smooth = cmd->displacement.flags & EVAS_FILTER_DISPLACE_LINEAR;
|
|
|
|
map_w = cmd->mask->w;
|
|
|
|
map_h = cmd->mask->h;
|
|
|
|
intensity = cmd->displacement.intensity;
|
2014-01-06 18:03:46 -08:00
|
|
|
blend = (cmd->draw.render_op == EVAS_RENDER_BLEND);
|
2013-12-08 23:43:52 -08:00
|
|
|
|
2014-02-17 02:54:47 -08:00
|
|
|
// Stretch if necessary.
|
|
|
|
if ((map_w != w || map_h != h) && (cmd->draw.fillmode & EVAS_FILTER_FILL_MODE_STRETCH_XY))
|
|
|
|
{
|
|
|
|
Evas_Filter_Buffer *fb;
|
|
|
|
|
|
|
|
if (cmd->draw.fillmode & EVAS_FILTER_FILL_MODE_STRETCH_X)
|
|
|
|
map_w = w;
|
|
|
|
if (cmd->draw.fillmode & EVAS_FILTER_FILL_MODE_STRETCH_Y)
|
|
|
|
map_h = h;
|
|
|
|
|
|
|
|
BUFFERS_LOCK();
|
|
|
|
fb = evas_filter_buffer_scaled_get(cmd->ctx, cmd->mask, map_w, map_h);
|
|
|
|
BUFFERS_UNLOCK();
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(fb, EINA_FALSE);
|
|
|
|
fb->locked = EINA_FALSE;
|
|
|
|
map_start = ((RGBA_Image *) fb->backing)->image.data;
|
|
|
|
}
|
|
|
|
|
2014-01-06 18:03:46 -08:00
|
|
|
_filter_displace_cpu_rgba_do(w, h, map_w, map_h, intensity,
|
|
|
|
src, dst, map_start, stretch, smooth, blend);
|
2013-12-08 23:43:52 -08:00
|
|
|
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
Evas_Filter_Apply_Func
|
|
|
|
evas_filter_displace_cpu_func_get(Evas_Filter_Command *cmd)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd, NULL);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->input, NULL);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->output, NULL);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->mask, NULL);
|
2014-01-06 17:16:39 -08:00
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL(!cmd->mask->alpha_only, NULL);
|
2013-12-08 23:43:52 -08:00
|
|
|
|
|
|
|
if (cmd->input->alpha_only != cmd->output->alpha_only)
|
|
|
|
{
|
2013-12-29 22:43:52 -08:00
|
|
|
CRI("Invalid color formats");
|
2013-12-08 23:43:52 -08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cmd->input->alpha_only)
|
2014-01-06 17:16:39 -08:00
|
|
|
return _filter_displace_cpu_alpha;
|
2013-12-08 23:43:52 -08:00
|
|
|
else
|
2014-01-06 17:16:39 -08:00
|
|
|
return _filter_displace_cpu_rgba;
|
2013-12-08 23:43:52 -08:00
|
|
|
}
|