summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJean-Philippe Andre <jp.andre@samsung.com>2015-05-28 14:37:10 +0900
committerJean-Philippe Andre <jp.andre@samsung.com>2015-06-25 14:36:08 +0900
commit70efb699a5c53d2e5b17fcf669ae8852a1038ce3 (patch)
tree94ce83eec3b6cc21360d80512cc404f3fe669c0a /src
parent1b2819f2cbe3aa1970ea2467f01b07b24f793f4d (diff)
Evas filters: Implement table & function support for curve
Now the points can be specified by passing a table or a proper Lua function. The previous functionality (parsing a string) is still valid.
Diffstat (limited to 'src')
-rw-r--r--src/lib/evas/filters/evas_filter_parser.c222
-rw-r--r--src/lib/evas/filters/evas_filter_private.h2
-rw-r--r--src/lib/evas/filters/evas_filter_utils.c52
3 files changed, 211 insertions, 65 deletions
diff --git a/src/lib/evas/filters/evas_filter_parser.c b/src/lib/evas/filters/evas_filter_parser.c
index 60a93fe..0972e7c 100644
--- a/src/lib/evas/filters/evas_filter_parser.c
+++ b/src/lib/evas/filters/evas_filter_parser.c
@@ -276,7 +276,8 @@ typedef enum
276 VT_REAL, 276 VT_REAL,
277 VT_STRING, 277 VT_STRING,
278 VT_COLOR, 278 VT_COLOR,
279 VT_BUFFER 279 VT_BUFFER,
280 VT_SPECIAL
280} Value_Type; 281} Value_Type;
281 282
282typedef struct _Buffer 283typedef struct _Buffer
@@ -293,7 +294,8 @@ typedef struct _Buffer
293 Eina_Bool manual : 1; // created by "buffer" instruction 294 Eina_Bool manual : 1; // created by "buffer" instruction
294} Buffer; 295} Buffer;
295 296
296typedef struct _Instruction_Param 297typedef struct _Instruction_Param Instruction_Param;
298struct _Instruction_Param
297{ 299{
298 EINA_INLIST; 300 EINA_INLIST;
299 Eina_Stringshare *name; 301 Eina_Stringshare *name;
@@ -305,11 +307,15 @@ typedef struct _Instruction_Param
305 char *s; 307 char *s;
306 unsigned int c; 308 unsigned int c;
307 Buffer *buf; 309 Buffer *buf;
310 struct {
311 void *data;
312 Eina_Bool (*func)(lua_State *L, int i, Evas_Filter_Program *, Evas_Filter_Instruction *, Instruction_Param *);
313 } special;
308 } value; 314 } value;
309 Eina_Bool set : 1; 315 Eina_Bool set : 1;
310 Eina_Bool allow_seq : 1; 316 Eina_Bool allow_seq : 1;
311 Eina_Bool allow_any_string : 1; 317 Eina_Bool allow_any_string : 1;
312} Instruction_Param; 318};
313 319
314struct _Evas_Filter_Instruction 320struct _Evas_Filter_Instruction
315{ 321{
@@ -402,6 +408,10 @@ _instruction_param_addv(Evas_Filter_Instruction *instr, const char *name,
402 case VT_COLOR: 408 case VT_COLOR:
403 param->value.c = va_arg(args, DATA32); 409 param->value.c = va_arg(args, DATA32);
404 break; 410 break;
411 case VT_SPECIAL:
412 param->value.special.func = va_arg(args, typeof(param->value.special.func));
413 param->value.special.data = va_arg(args, void *);
414 break;
405 case VT_NONE: 415 case VT_NONE:
406 default: 416 default:
407 return EINA_FALSE; 417 return EINA_FALSE;
@@ -426,8 +436,8 @@ _instruction_param_adda(Evas_Filter_Instruction *instr, const char *name,
426 436
427 return ok; 437 return ok;
428} 438}
429#define _instruction_param_seq_add(a,b,c,d) _instruction_param_adda((a),(b),(c),1,(d)) 439#define _instruction_param_seq_add(a,b,c,...) _instruction_param_adda((a),(b),(c),1,__VA_ARGS__)
430#define _instruction_param_name_add(a,b,c,d) _instruction_param_adda((a),(b),(c),0,(d)) 440#define _instruction_param_name_add(a,b,c,...) _instruction_param_adda((a),(b),(c),0,__VA_ARGS__)
431 441
432static void 442static void
433_instruction_del(Evas_Filter_Instruction *instr) 443_instruction_del(Evas_Filter_Instruction *instr)
@@ -439,6 +449,8 @@ _instruction_del(Evas_Filter_Instruction *instr)
439 { 449 {
440 if (param->type == VT_STRING) 450 if (param->type == VT_STRING)
441 free(param->value.s); 451 free(param->value.s);
452 else if (param->type == VT_SPECIAL)
453 free(param->value.special.data);
442 eina_stringshare_del(param->name); 454 eina_stringshare_del(param->name);
443 instr->params = eina_inlist_remove(instr->params, EINA_INLIST_GET(param)); 455 instr->params = eina_inlist_remove(instr->params, EINA_INLIST_GET(param));
444 free(param); 456 free(param);
@@ -510,6 +522,23 @@ _instruction_param_getc(Evas_Filter_Instruction *instr, const char *name,
510 return 0; 522 return 0;
511} 523}
512 524
525static void *
526_instruction_param_getspecial(Evas_Filter_Instruction *instr, const char *name,
527 Eina_Bool *isset)
528{
529 Instruction_Param *param;
530
531 EINA_INLIST_FOREACH(instr->params, param)
532 if (!strcasecmp(name, param->name))
533 {
534 if (isset) *isset = param->set;
535 return param->value.special.data;
536 }
537
538 if (isset) *isset = EINA_FALSE;
539 return 0;
540}
541
513static const char * 542static const char *
514_instruction_param_gets(Evas_Filter_Instruction *instr, const char *name, 543_instruction_param_gets(Evas_Filter_Instruction *instr, const char *name,
515 Eina_Bool *isset) 544 Eina_Bool *isset)
@@ -1200,6 +1229,138 @@ _bump_instruction_prepare(Evas_Filter_Program *pgm, Evas_Filter_Instruction *ins
1200 return EINA_TRUE; 1229 return EINA_TRUE;
1201} 1230}
1202 1231
1232static Eina_Bool
1233_lua_curve_points_func(lua_State *L, int i, Evas_Filter_Program *pgm EINA_UNUSED,
1234 Evas_Filter_Instruction *instr, Instruction_Param *param)
1235{
1236 int values[256];
1237 char *token, *copy = NULL;
1238 const char *points_str;
1239 lua_Number n;
1240 int k;
1241
1242 switch (lua_type(L, i))
1243 {
1244 case LUA_TTABLE:
1245 // FIXME: indices start from 0 here. Lua prefers starting with 1.
1246 for (k = 0; k < 256; k++)
1247 {
1248 lua_rawgeti(L, i, k);
1249 if (lua_isnil(L, -1))
1250 {
1251 lua_pop(L, 1);
1252 values[k] = -1;
1253 }
1254 else if (lua_isnumber(L, -1))
1255 {
1256 n = lua_tonumber(L, -1);
1257 if ((n < -1) || (n > 255))
1258 {
1259 WRN("Value out of range in argument '%s' of function '%s' (got %d, expected 0-255)",
1260 param->name, instr->name, (int) n);
1261 if (n < -1) n = 0;
1262 if (n > 255) n = 255;
1263 }
1264 lua_pop(L, 1);
1265 values[k] = (int) n;
1266 }
1267 else
1268 {
1269 lua_pop(L, 1);
1270 ERR("Invalid value type '%s' (expected number) in table for argument '%s' of function '%s'",
1271 lua_typename(L, -1), param->name, instr->name);
1272 return EINA_FALSE;
1273 }
1274 }
1275 break;
1276
1277 case LUA_TSTRING:
1278 for (k = 0; k < 256; k++)
1279 values[k] = -1;
1280 points_str = lua_tostring(L, i);
1281 copy = strdup(points_str);
1282 if (!copy) return EINA_FALSE;
1283 token = strtok(copy, "-");
1284 if (!token)
1285 {
1286 ERR("Invalid string format for argument '%s' of function '%s'",
1287 param->name, instr->name);
1288 free(copy);
1289 return EINA_FALSE;
1290 }
1291 while (token)
1292 {
1293 int x, y, r, minx = 0;
1294 r = sscanf(token, "%i:%i", &x, &y);
1295 if ((r != 2) || (x < minx) || (x >= 256))
1296 {
1297 ERR("Invalid string format for argument '%s' of function '%s'",
1298 param->name, instr->name);
1299 free(copy);
1300 return EINA_FALSE;
1301 }
1302 minx = x + 1;
1303 if ((y < -1) || (y > 255))
1304 {
1305 WRN("Value out of range in argument '%s' of function '%s' (got %d, expected 0-255)",
1306 param->name, instr->name, y);
1307 if (y < -1) y = 0;
1308 if (y > 255) y = 255;
1309 }
1310 values[x] = y;
1311 token = strtok(NULL, "-");
1312 }
1313 free(copy);
1314 break;
1315
1316 case LUA_TFUNCTION:
1317 for (k = 0; k < 256; k++)
1318 {
1319 lua_pushvalue(L, i);
1320 lua_pushinteger(L, k);
1321 if (!lua_pcall(L, 1, 1, 0))
1322 {
1323 if (!lua_isnumber(L, -1))
1324 {
1325 ERR("Function returned an invalid type '%s' (expected number) "
1326 "in argument '%s' of function '%s'",
1327 lua_typename(L, -1), param->name, instr->name);
1328 return EINA_FALSE;
1329 }
1330 n = lua_tonumber(L, -1);
1331 if ((n < -1) || (n > 255))
1332 {
1333 WRN("Value out of range in argument '%s' of function '%s' (got %d, expected 0-255)",
1334 param->name, instr->name, (int) n);
1335 if (n < -1) n = 0;
1336 if (n > 255) n = 255;
1337 }
1338 lua_pop(L, 1);
1339 values[k] = (int) n;
1340 }
1341 else
1342 {
1343 ERR("Failed to call function for argument '%s' of function '%s': %s",
1344 param->name, instr->name, lua_tostring(L, -1));
1345 return EINA_FALSE;
1346 }
1347 }
1348 break;
1349
1350 default:
1351 ERR("Invalid type '%s' for argument '%s' of function '%s'",
1352 lua_typename(L, i), param->name, instr->name);
1353 return EINA_FALSE;
1354 }
1355
1356 free(param->value.special.data);
1357 param->value.special.data = malloc(sizeof(values));
1358 if (!param->value.special.data) return EINA_FALSE;
1359 memcpy(param->value.special.data, values, sizeof(values));
1360
1361 return EINA_TRUE;
1362}
1363
1203/** 1364/**
1204 @page evasfiltersref 1365 @page evasfiltersref
1205 1366
@@ -1258,7 +1419,7 @@ _curve_instruction_prepare(Evas_Filter_Program *pgm, Evas_Filter_Instruction *in
1258 1419
1259 // TODO: Allow passing an array of 256 values as points. 1420 // TODO: Allow passing an array of 256 values as points.
1260 // It could be easily computed from another function in the script. 1421 // It could be easily computed from another function in the script.
1261 _instruction_param_seq_add(instr, "points", VT_STRING, NULL); 1422 _instruction_param_seq_add(instr, "points", VT_SPECIAL, _lua_curve_points_func, NULL);
1262 param = EINA_INLIST_CONTAINER_GET(eina_inlist_last(instr->params), Instruction_Param); 1423 param = EINA_INLIST_CONTAINER_GET(eina_inlist_last(instr->params), Instruction_Param);
1263 param->allow_any_string = EINA_TRUE; 1424 param->allow_any_string = EINA_TRUE;
1264 1425
@@ -1865,6 +2026,11 @@ _lua_parameter_parse(Evas_Filter_Program *pgm, lua_State *L,
1865 } 2026 }
1866 break; 2027 break;
1867 } 2028 }
2029 case VT_SPECIAL:
2030 if (!param->value.special.func ||
2031 !param->value.special.func(L, i, pgm, instr, param))
2032 goto fail;
2033 break;
1868 case VT_NONE: 2034 case VT_NONE:
1869 default: 2035 default:
1870 // This should not happen 2036 // This should not happen
@@ -2369,6 +2535,11 @@ _filter_program_state_set(Evas_Filter_Program *pgm)
2369#define JOINC(k) ARGB_JOIN(pgm->state.k.a, pgm->state.k.r, pgm->state.k.g, pgm->state.k.b) 2535#define JOINC(k) ARGB_JOIN(pgm->state.k.a, pgm->state.k.r, pgm->state.k.g, pgm->state.k.b)
2370#define SETFIELD(name, val) do { lua_pushinteger(L, val); lua_setfield(L, -2, name); } while(0) 2536#define SETFIELD(name, val) do { lua_pushinteger(L, val); lua_setfield(L, -2, name); } while(0)
2371 2537
2538 // TODO: Mark program as dependent on some values so we can improve
2539 // the changed flag (ie. re-run the filter only when required)
2540 // eg. edje state_val changed but it is not used by the filter --> no redraw
2541 // --> this needs a metatable with __index
2542
2372 lua_newtable(L); // "state" 2543 lua_newtable(L); // "state"
2373 { 2544 {
2374 SETFIELD("color", JOINC(color)); 2545 SETFIELD("color", JOINC(color));
@@ -2434,6 +2605,10 @@ evas_filter_program_parse(Evas_Filter_Program *pgm, const char *str)
2434 if (!L) return EINA_FALSE; 2605 if (!L) return EINA_FALSE;
2435 2606
2436 ok = !luaL_loadstring(L, str); 2607 ok = !luaL_loadstring(L, str);
2608 if (!ok)
2609 {
2610 ERR("Failed to load Lua program: %s", lua_tostring(L, -1));
2611 }
2437 2612
2438#ifdef FILTERS_LEGACY_COMPAT 2613#ifdef FILTERS_LEGACY_COMPAT
2439 if (!ok) 2614 if (!ok)
@@ -2954,18 +3129,18 @@ _instr2cmd_curve(Evas_Filter_Context *ctx,
2954{ 3129{
2955 Evas_Filter_Interpolation_Mode mode = EVAS_FILTER_INTERPOLATION_MODE_LINEAR; 3130 Evas_Filter_Interpolation_Mode mode = EVAS_FILTER_INTERPOLATION_MODE_LINEAR;
2956 Evas_Filter_Channel channel = EVAS_FILTER_CHANNEL_RGB; 3131 Evas_Filter_Channel channel = EVAS_FILTER_CHANNEL_RGB;
2957 const char *points_str, *interpolation, *channel_name; 3132 const char *interpolation, *channel_name;
2958 DATA8 values[256] = {0}, points[512];
2959 int cmdid, point_count = 0;
2960 char *token, *copy = NULL;
2961 Buffer *src, *dst; 3133 Buffer *src, *dst;
2962 Eina_Bool parse_ok = EINA_FALSE; 3134 DATA8 values[256];
3135 int *points;
3136 int cmdid;
2963 3137
2964 src = _instruction_param_getbuf(instr, "src", NULL); 3138 src = _instruction_param_getbuf(instr, "src", NULL);
2965 dst = _instruction_param_getbuf(instr, "dst", NULL); 3139 dst = _instruction_param_getbuf(instr, "dst", NULL);
2966 points_str = _instruction_param_gets(instr, "points", NULL); 3140 points = _instruction_param_getspecial(instr, "points", NULL);
2967 interpolation = _instruction_param_gets(instr, "interpolation", NULL); 3141 interpolation = _instruction_param_gets(instr, "interpolation", NULL);
2968 channel_name = _instruction_param_gets(instr, "channel", NULL); 3142 channel_name = _instruction_param_gets(instr, "channel", NULL);
3143 INSTR_PARAM_CHECK(points);
2969 INSTR_PARAM_CHECK(src); 3144 INSTR_PARAM_CHECK(src);
2970 INSTR_PARAM_CHECK(dst); 3145 INSTR_PARAM_CHECK(dst);
2971 3146
@@ -2989,28 +3164,7 @@ _instr2cmd_curve(Evas_Filter_Context *ctx,
2989 if (interpolation && !strcasecmp(interpolation, "none")) 3164 if (interpolation && !strcasecmp(interpolation, "none"))
2990 mode = EVAS_FILTER_INTERPOLATION_MODE_NONE; 3165 mode = EVAS_FILTER_INTERPOLATION_MODE_NONE;
2991 3166
2992 if (!points_str) goto interpolated; 3167 if (!evas_filter_interpolate(values, points, mode))
2993 copy = strdup(points_str);
2994 token = strtok(copy, "-");
2995 if (!token) goto interpolated;
2996
2997 while (token)
2998 {
2999 int x, y, r, maxx = 0;
3000 r = sscanf(token, "%u:%u", &x, &y);
3001 if (r != 2) goto interpolated;
3002 if (x < maxx || x >= 256) goto interpolated;
3003 points[point_count * 2 + 0] = x;
3004 points[point_count * 2 + 1] = y;
3005 point_count++;
3006 token = strtok(NULL, "-");
3007 }
3008
3009 parse_ok = evas_filter_interpolate(values, points, point_count, mode);
3010
3011interpolated:
3012 free(copy);
3013 if (!parse_ok)
3014 { 3168 {
3015 int x; 3169 int x;
3016 ERR("Failed to parse the interpolation chain"); 3170 ERR("Failed to parse the interpolation chain");
diff --git a/src/lib/evas/filters/evas_filter_private.h b/src/lib/evas/filters/evas_filter_private.h
index c613be7..9e49aa2 100644
--- a/src/lib/evas/filters/evas_filter_private.h
+++ b/src/lib/evas/filters/evas_filter_private.h
@@ -239,7 +239,7 @@ Evas_Filter_Buffer *_filter_buffer_data_new(Evas_Filter_Context *ctx, void *data
239#define evas_filter_buffer_alloc_new(ctx, w, h, a) _filter_buffer_data_new(ctx, NULL, w, h, a) 239#define evas_filter_buffer_alloc_new(ctx, w, h, a) _filter_buffer_data_new(ctx, NULL, w, h, a)
240Evas_Filter_Buffer *evas_filter_temporary_buffer_get(Evas_Filter_Context *ctx, int w, int h, Eina_Bool alpha_only); 240Evas_Filter_Buffer *evas_filter_temporary_buffer_get(Evas_Filter_Context *ctx, int w, int h, Eina_Bool alpha_only);
241Evas_Filter_Buffer *evas_filter_buffer_scaled_get(Evas_Filter_Context *ctx, Evas_Filter_Buffer *src, unsigned w, unsigned h); 241Evas_Filter_Buffer *evas_filter_buffer_scaled_get(Evas_Filter_Context *ctx, Evas_Filter_Buffer *src, unsigned w, unsigned h);
242Eina_Bool evas_filter_interpolate(DATA8* output /* 256 values */, DATA8* points /* pairs x + y */, int point_count, Evas_Filter_Interpolation_Mode mode); 242Eina_Bool evas_filter_interpolate(DATA8* output /* 256 values */, int *points /* 256 values */, Evas_Filter_Interpolation_Mode mode);
243Evas_Filter_Command *_evas_filter_command_get(Evas_Filter_Context *ctx, int cmdid); 243Evas_Filter_Command *_evas_filter_command_get(Evas_Filter_Context *ctx, int cmdid);
244int evas_filter_smallest_pow2_larger_than(int val); 244int evas_filter_smallest_pow2_larger_than(int val);
245 245
diff --git a/src/lib/evas/filters/evas_filter_utils.c b/src/lib/evas/filters/evas_filter_utils.c
index 1e27895..088cb53 100644
--- a/src/lib/evas/filters/evas_filter_utils.c
+++ b/src/lib/evas/filters/evas_filter_utils.c
@@ -84,60 +84,52 @@ evas_filter_buffer_scaled_get(Evas_Filter_Context *ctx,
84} 84}
85 85
86static Eina_Bool 86static Eina_Bool
87_interpolate_none(DATA8 *output, DATA8 *points, int point_count) 87_interpolate_none(DATA8 *output, int *points)
88{ 88{
89 int j, k, val, x1, x2; 89 DATA8 val = 0;
90 for (j = 0; j < point_count; j++) 90 int j;
91 for (j = 0; j < 256; j++)
91 { 92 {
92 x1 = points[j * 2]; 93 if (points[j] == -1)
93 val = points[j * 2 + 1]; 94 output[j] = val;
94 if (j < (point_count - 1))
95 x2 = points[(j + 1) * 2];
96 else 95 else
97 x2 = 256; 96 val = output[j] = (DATA8) points[j];
98 if (x2 < x1) return EINA_FALSE;
99 for (k = x1; k < x2; k++)
100 output[k] = val;
101 } 97 }
102 return EINA_TRUE; 98 return EINA_TRUE;
103} 99}
104 100
105static Eina_Bool 101static Eina_Bool
106_interpolate_linear(DATA8 *output, DATA8 *points, int point_count) 102_interpolate_linear(DATA8 *output, int *points)
107{ 103{
108 int j, k, val1, val2, x1, x2; 104 DATA8 val = 0;
109 for (j = 0; j < point_count; j++) 105 int j, k, last_idx = 0;
106 for (j = 0; j < 256; j++)
110 { 107 {
111 x1 = points[j * 2]; 108 if (points[j] != -1)
112 val1 = points[j * 2 + 1];
113 if (j < (point_count - 1))
114 { 109 {
115 x2 = points[(j + 1) * 2]; 110 output[j] = (DATA8) points[j];
116 val2 = points[(j + 1) * 2 + 1]; 111 for (k = last_idx + 1; k < j; k++)
112 output[k] = (DATA8) (points[j] + ((k - last_idx) * (points[j] - points[last_idx]) / (j - last_idx)));
113 last_idx = j;
117 } 114 }
118 else
119 {
120 x2 = 256;
121 val2 = val1;
122 }
123 if (x2 < x1) return EINA_FALSE;
124 for (k = x1; k < x2; k++)
125 output[k] = val1 + ((val2 - val1) * (k - x1)) / (x2 - x1);
126 } 115 }
116 val = (DATA8) points[last_idx];
117 for (j = last_idx + 1; j < 256; j++)
118 output[j] = val;
127 return EINA_TRUE; 119 return EINA_TRUE;
128} 120}
129 121
130Eina_Bool 122Eina_Bool
131evas_filter_interpolate(DATA8 *output, DATA8 *points, int point_count, 123evas_filter_interpolate(DATA8 *output, int *points,
132 Evas_Filter_Interpolation_Mode mode) 124 Evas_Filter_Interpolation_Mode mode)
133{ 125{
134 switch (mode) 126 switch (mode)
135 { 127 {
136 case EVAS_FILTER_INTERPOLATION_MODE_NONE: 128 case EVAS_FILTER_INTERPOLATION_MODE_NONE:
137 return _interpolate_none(output, points, point_count); 129 return _interpolate_none(output, points);
138 case EVAS_FILTER_INTERPOLATION_MODE_LINEAR: 130 case EVAS_FILTER_INTERPOLATION_MODE_LINEAR:
139 default: 131 default:
140 return _interpolate_linear(output, points, point_count); 132 return _interpolate_linear(output, points);
141 } 133 }
142} 134}
143 135