Evas filters: Add offset parameter to vflip

It is not possible to logically handle padding and offset at the same
time for a proper mirror effect, unless this is handled directly at the
transformation level.

Also, add support for blend() operation padding computation.
This commit is contained in:
Jean-Philippe Andre 2014-01-07 18:38:22 +09:00
parent d9fb0cdc34
commit 209a7077a0
4 changed files with 155 additions and 6 deletions

View File

@ -1048,9 +1048,11 @@ end:
}
int
evas_filter_command_transform_add(Evas_Filter_Context *ctx, void *draw_context,
evas_filter_command_transform_add(Evas_Filter_Context *ctx,
void *draw_context EINA_UNUSED,
int inbuf, int outbuf,
Evas_Filter_Transform_Flags flags)
Evas_Filter_Transform_Flags flags,
int ox, int oy)
{
Evas_Filter_Command *cmd;
Evas_Filter_Buffer *in, *out;
@ -1076,6 +1078,8 @@ evas_filter_command_transform_add(Evas_Filter_Context *ctx, void *draw_context,
if (!cmd) return -1;
cmd->transform.flags = flags;
cmd->draw.ox = ox;
cmd->draw.oy = oy;
return cmd->id;
}

View File

@ -684,6 +684,38 @@ _buffer_del(Buffer *buf)
/* Instruction definitions */
static void
_blend_padding_update(Evas_Filter_Program *pgm, Evas_Filter_Instruction *instr,
int *padl, int *padr, int *padt, int *padb)
{
const char *outbuf;
Buffer *out;
int ox, oy, l = 0, r = 0, t = 0, b = 0;
ox = _instruction_param_geti(instr, "ox", NULL);
oy = _instruction_param_geti(instr, "oy", NULL);
outbuf = _instruction_param_gets(instr, "dst", NULL);
out = _buffer_get(pgm, outbuf);
EINA_SAFETY_ON_NULL_RETURN(out);
if (ox < 0) l = (-ox);
else r = ox;
if (oy < 0) t = (-oy);
else b = oy;
if (out->pad.l < l) out->pad.l = l;
if (out->pad.r < r) out->pad.r = r;
if (out->pad.t < t) out->pad.t = t;
if (out->pad.b < b) out->pad.b = b;
if (padl) *padl = l;
if (padr) *padr = r;
if (padt) *padt = t;
if (padb) *padb = b;
}
static Eina_Bool
_blend_instruction_prepare(Evas_Filter_Instruction *instr)
{
@ -696,6 +728,7 @@ _blend_instruction_prepare(Evas_Filter_Instruction *instr)
*/
instr->type = EVAS_FILTER_MODE_BLEND;
instr->pad.update = _blend_padding_update;
_instruction_param_seq_add(instr, "src", VT_BUFFER, "input");
_instruction_param_seq_add(instr, "dst", VT_BUFFER, "output");
_instruction_param_seq_add(instr, "ox", VT_INT, 0);
@ -1024,6 +1057,62 @@ _mask_instruction_prepare(Evas_Filter_Instruction *instr)
return EINA_TRUE;
}
static void
_transform_padding_update(Evas_Filter_Program *pgm,
Evas_Filter_Instruction *instr,
int *padl, int *padr, int *padt, int *padb)
{
const char *outbuf;
Buffer *out;
int ox, oy, l = 0, r = 0, t = 0, b = 0;
//ox = _instruction_param_geti(instr, "ox", NULL);
ox = 0;
oy = _instruction_param_geti(instr, "oy", NULL);
outbuf = _instruction_param_gets(instr, "dst", NULL);
out = _buffer_get(pgm, outbuf);
EINA_SAFETY_ON_NULL_RETURN(out);
if (ox < 0) l = (-ox) * 2;
else r = ox * 2;
if (oy < 0) t = (-oy) * 2;
else b = oy * 2;
if (out->pad.l < l) out->pad.l = l;
if (out->pad.r < r) out->pad.r = r;
if (out->pad.t < t) out->pad.t = t;
if (out->pad.b < b) out->pad.b = b;
if (padl) *padl = l;
if (padr) *padr = r;
if (padt) *padt = t;
if (padb) *padb = b;
}
static Eina_Bool
_transform_instruction_prepare(Evas_Filter_Instruction *instr)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(instr, EINA_FALSE);
EINA_SAFETY_ON_NULL_RETURN_VAL(instr->name, EINA_FALSE);
EINA_SAFETY_ON_FALSE_RETURN_VAL(!strcasecmp(instr->name, "transform"), EINA_FALSE);
/*
* mask [op=]STRING [input=BUFFER] [output=BUFFER] (oy=INT)
*/
instr->type = EVAS_FILTER_MODE_TRANSFORM;
instr->pad.update = _transform_padding_update;
_instruction_param_seq_add(instr, "op", VT_STRING, "vflip");
_instruction_param_seq_add(instr, "src", VT_BUFFER, "input");
_instruction_param_seq_add(instr, "dst", VT_BUFFER, "output");
//_instruction_param_name_add(instr, "ox", VT_INT, 0);
_instruction_param_name_add(instr, "oy", VT_INT, 0);
return EINA_TRUE;
}
static Evas_Filter_Instruction *
_instruction_create(const char *name)
{
@ -1048,6 +1137,8 @@ _instruction_create(const char *name)
prepare = _grow_instruction_prepare;
else if (!strcasecmp(name, "mask"))
prepare = _mask_instruction_prepare;
else if (!strcasecmp(name, "transform"))
prepare = _transform_instruction_prepare;
if (!prepare)
{
@ -1647,6 +1738,34 @@ interpolated:
return cmdid;
}
static int
_instr2cmd_transform(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm,
Evas_Filter_Instruction *instr, void *dc)
{
Evas_Filter_Transform_Flags flags;
const char *src, *dst, *op;
Buffer *in, *out;
int ox = 0, oy;
op = _instruction_param_gets(instr, "op", NULL);
src = _instruction_param_gets(instr, "src", NULL);
dst = _instruction_param_gets(instr, "dst", NULL);
// ox = _instruction_param_geti(instr, "ox", NULL);
oy = _instruction_param_geti(instr, "oy", NULL);
if (!strcasecmp(op, "vflip"))
flags = EVAS_FILTER_TRANSFORM_VFLIP;
else
{
ERR("Invalid transform '%s'", op);
return -1;
}
in = _buffer_get(pgm, src);
out = _buffer_get(pgm, dst);
return evas_filter_command_transform_add(ctx, dc, in->cid, out->cid, flags, ox, oy);
}
static int
_command_from_instruction(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm,
Evas_Filter_Instruction *instr, void *dc)
@ -1680,6 +1799,9 @@ _command_from_instruction(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm,
case EVAS_FILTER_MODE_CURVE:
instr2cmd = _instr2cmd_curve;
break;
case EVAS_FILTER_MODE_TRANSFORM:
instr2cmd = _instr2cmd_transform;
break;
default:
CRI("Invalid instruction type: %d", instr->type);
return -1;

View File

@ -5,7 +5,8 @@ _vflip_cpu(Evas_Filter_Command *cmd)
{
size_t datasize, stride;
DATA8 *in, *out, *span;
int w, h, sy, dy;
int w, h, sy, dy, oy, center, t, b, objh;
int s0, s1, d0, d1;
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd, EINA_FALSE);
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->input, EINA_FALSE);
@ -24,23 +25,43 @@ _vflip_cpu(Evas_Filter_Command *cmd)
datasize = cmd->input->alpha_only ? sizeof(DATA8) : sizeof(DATA32);
stride = w * datasize;
oy = cmd->draw.oy;
t = cmd->ctx->padt;
b = cmd->ctx->padb;
objh = h - t - b;
center = t + objh / 2 + oy;
s0 = t;
s1 = h - b - 1;
if (oy >= 0)
{
d0 = center + (objh / 2) + oy;
d1 = center - (objh / 2) - oy;
}
else
{
d0 = center + (objh / 2) - oy;
d1 = center - (objh / 2) + oy;
}
if (in == out)
{
span = malloc(stride);
if (!span) return EINA_FALSE;
}
for (sy = 0, dy = h - 1; dy >= 0; sy++, dy--)
for (sy = s0, dy = d0; (dy >= d1) && (sy <= s1); sy++, dy--)
{
DATA8* src = in + stride * sy;
DATA8* dst = out + stride * dy;
if (in == out)
{
if (src == dst) break;
memcpy(span, dst, stride);
memcpy(dst, src, stride);
memcpy(src, span, stride);
if (sy >= (h / 2)) break;
if (sy >= center) break;
}
else
memcpy(dst, src, stride);

View File

@ -227,9 +227,11 @@ int evas_filter_command_bump_map_add(Evas_Filter_Context *c
* @param inbuf Input buffer (Alpha or RGBA)
* @param outbuf Output buffer (Alpha or RGBA), same size as inbuf
* @param flags Specifies the operation to apply (eg. vflip)
* @param ox X offset
* @param oy Y offset
* @return Filter command ID or -1 in case of error
*/
int evas_filter_command_transform_add(Evas_Filter_Context *ctx, void *draw_context, int inbuf, int outbuf, Evas_Filter_Transform_Flags flags);
int evas_filter_command_transform_add(Evas_Filter_Context *ctx, void *draw_context, int inbuf, int outbuf, Evas_Filter_Transform_Flags flags, int ox, int oy);
#endif