useful for "to" field of email/sms applications where ',' is used to
separate different text entities.
+2011-04-19 Brett Nash (nash)
+
+ * Filters: So filtering of various flavours. They work only on images
+ (use a proxy if you want it on other objects). Documentation inline.
+ Supports a filter object or filter under (the area where the object
+ is filtered). Various parameters to tweak, and potential for
+ additional filters (but you get to write the shader ;-)
EAPI Eina_List *evas_object_table_children_get (const Evas_Object *o) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_MALLOC;
EAPI Evas_Object *evas_object_table_child_get (const Evas_Object *o, unsigned short col, unsigned short row) EINA_ARG_NONNULL(1);
+ typedef enum
+ {
+ /** Apply any filter effects to this object (Default) */
+ EVAS_FILTER_MODE_OBJECT,
+ /** Filter all objects beneath this object on the canvas */
+ EVAS_FILTER_MODE_BELOW,
+ } Evas_Filter_Mode;
+ typedef enum
+ {
+ /** No filter: Default */
+ EVAS_FILTER_NONE,
+ /** A blur filter. Params are quality (float), and radius (int). */
+ EVAS_FILTER_BLUR,
+ /** Negates the colors of an image. Also called solarize */
+ EVAS_FILTER_INVERT,
+ EVAS_FILTER_SOLARIZE = EVAS_FILTER_INVERT,
+ /** Makes a sepia version of the image. */
+ EVAS_FILTER_SEPIA,
+ /** Makes a greyscale version of the image. Params are 'red',
+ * 'green', 'blue' (all floats) which must add to 1. The defaults are
+ * 0.3, 0.59 and 0.11 which approximates human vision. Setting 'all'
+ * sets rgb to the same value. */
+ EVAS_FILTER_GREYSCALE,
+ EVAS_FILTER_GRAYSCALE = EVAS_FILTER_GREYSCALE,
+ /** Brighten (or darken) image. Param 'adjust' float (-1.0 to 1.0)
+ * amount to adjust. */
+ EVAS_FILTER_BRIGHTNESS,
+ /** Enhance contrast on image. Param 'adjust' float (-1.0 to 1.0)
+ * amount to adjust. */
+ EVAS_FILTER_CONTRAST,
+
+ EVAS_FILTER_LAST = EVAS_FILTER_CONTRAST
+ } Evas_Filter;
+
+ EAPI Eina_Bool evas_object_filter_mode_set (Evas_Object *o, Evas_Filter_Mode mode);
+ EAPI Evas_Filter_Mode evas_object_filter_mode_get (Evas_Object *o);
+ EAPI Eina_Bool evas_object_filter_set (Evas_Object *o, Evas_Filter filter);
+ EAPI Evas_Filter evas_object_filter_get (Evas_Object *o);
+ EAPI Eina_Bool evas_object_filter_param_set_int (Evas_Object *o, const char *param, int val);
+ EAPI int evas_object_filter_param_get_int (Evas_Object *o, const char *param);
+ EAPI Eina_Bool evas_object_filter_param_set_str (Evas_Object *o, const char *param, const char *val);
+ EAPI Eina_Bool evas_object_filter_param_set_obj (Evas_Object *o, const char *param, Evas_Object *);
+ EAPI Eina_Bool evas_object_filter_param_set_float(Evas_Object *o, const char *param, double val);
+
+
/**
* @defgroup Evas_Cserve Shared Image Cache Server
evas_clip.c \
evas_data.c \
evas_events.c \
+evas_filter.c \
evas_focus.c \
evas_key.c \
evas_key_grab.c \
--- /dev/null
+/*
+ * Filter implementation for evas
+ */
+
+#include <stddef.h> // offsetof
+
+
+#include "evas_common.h"
+#include "evas_private.h"
+
+#include "assert.h"
+
+#ifdef BUILD_NEON
+# define BUILD_NEON0 1
+#else
+# define BUILD_NEON0 0
+#endif
+
+typedef struct Evas_Filter_Info_Blur {
+ double quality;
+ int radius;
+} Evas_Filter_Info_Blur;
+
+typedef struct Evas_Filter_Info_GreyScale {
+ double r,g,b;
+} Evas_Filter_Info_GreyScale;
+typedef struct Evas_Filter_Info_Brightness {
+ double adjust;
+} Evas_Filter_Info_Brightness;
+typedef struct Evas_Filter_Info_Contrast {
+ double adjust;
+} Evas_Filter_Info_Contrast;
+
+
+typedef int (*Filter_Size_FN)(Evas_Filter_Info *,int,int,int*,int*,Eina_Bool);
+typedef uint8_t *(*Key_FN)(const Evas_Filter_Info *, uint32_t *);
+
+struct fieldinfo {
+ const char *field;
+ int type;
+ size_t offset;
+};
+
+
+struct filterinfo
+{
+ Evas_Software_Filter_Fn filter;
+ const size_t datasize;
+ Filter_Size_FN sizefn;
+ Key_FN keyfn;
+ Eina_Bool alwaysalpha;
+};
+
+enum {
+ TYPE_INT,
+ TYPE_FLOAT
+};
+
+static int blur_size_get(Evas_Filter_Info*, int, int, int *, int *, Eina_Bool);
+static uint8_t *gaussian_key_get(const Evas_Filter_Info *, uint32_t *);
+
+static Eina_Bool gaussian_filter(Evas_Filter_Info *, RGBA_Image*, RGBA_Image*);
+static Eina_Bool negation_filter(Evas_Filter_Info *, RGBA_Image*, RGBA_Image*);
+static Eina_Bool sepia_filter(Evas_Filter_Info *, RGBA_Image*, RGBA_Image*);
+static Eina_Bool greyscale_filter(Evas_Filter_Info*, RGBA_Image*, RGBA_Image*);
+static Eina_Bool brightness_filter(Evas_Filter_Info*, RGBA_Image*, RGBA_Image*);
+static Eina_Bool contrast_filter(Evas_Filter_Info *, RGBA_Image*, RGBA_Image*);
+
+static Eina_Bool negation_filter_neon(Evas_Filter_Info *, RGBA_Image *src, RGBA_Image *);
+
+struct filterinfo filterinfo[] =
+{
+ /* None */
+ { NULL, 0, NULL, NULL, EINA_FALSE},
+ /* Blur */
+ { gaussian_filter, sizeof(Evas_Filter_Info_Blur), blur_size_get,
+ gaussian_key_get, EINA_TRUE },
+ /* Negation */
+ { negation_filter, 0, NULL, NULL, EINA_FALSE },
+ /* Sepia */
+ { sepia_filter, 0, NULL, NULL, EINA_FALSE },
+ /* Greyscale */
+ { greyscale_filter, sizeof(Evas_Filter_Info_GreyScale), NULL, NULL, EINA_FALSE },
+ /* Brightness */
+ { brightness_filter, sizeof(Evas_Filter_Info_Brightness), NULL, NULL, EINA_FALSE },
+ /* Contrast */
+ { contrast_filter, sizeof(Evas_Filter_Info_Contrast), NULL, NULL, EINA_FALSE},
+};
+
+
+static struct fieldinfo blurfields[] = {
+ { "quality", TYPE_FLOAT, offsetof(Evas_Filter_Info_Blur, quality) },
+ { "radius", TYPE_INT, offsetof(Evas_Filter_Info_Blur, radius) },
+ { NULL, 0, 0 },
+};
+
+static struct fieldinfo greyfields[] = {
+ { "red", TYPE_FLOAT, offsetof(Evas_Filter_Info_GreyScale, r) },
+ { "green", TYPE_FLOAT, offsetof(Evas_Filter_Info_GreyScale, g) },
+ { "blue", TYPE_FLOAT, offsetof(Evas_Filter_Info_GreyScale, b) },
+
+ { "all", TYPE_FLOAT, offsetof(Evas_Filter_Info_GreyScale, r) },
+ { "all", TYPE_FLOAT, offsetof(Evas_Filter_Info_GreyScale, g) },
+ { "all", TYPE_FLOAT, offsetof(Evas_Filter_Info_GreyScale, b) },
+ { NULL, 0, 0 },
+};
+static struct fieldinfo brightnessfields[] = {
+ { "adjust", TYPE_FLOAT, offsetof(Evas_Filter_Info_Brightness, adjust) },
+ { NULL, 0, 0 },
+};
+static struct fieldinfo contrastfields[] = {
+ { "adjust", TYPE_FLOAT, offsetof(Evas_Filter_Info_Contrast, adjust) },
+ { NULL, 0, 0 },
+};
+
+
+
+static struct fieldinfo *filterfields[] =
+{
+ NULL,
+ blurfields,
+ NULL,
+ NULL,
+ greyfields,
+ brightnessfields,
+ contrastfields,
+};
+
+
+static Evas_Filter_Info *filter_alloc(Evas_Object *o);
+
+
+/**
+ * Set the filter mode for an object.
+ *
+ * There are two valid filtering modes currently:
+ * - EVAS_FILTER_MODE_OBJECT: which applies the filter to the object itself
+ * - EVAS_FILTER_MODE_BELOW: which makes the object invisible and filters
+ * what is below the object.
+ *
+ * The default filter mode is EVAS_FILTER_MODE_OBJECT.
+ *
+ * @param o Object to set filter mode on.
+ * @param mode Mode to set.
+ * @return EINA_TRUE on success, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool
+evas_object_filter_mode_set(Evas_Object *o, Evas_Filter_Mode mode)
+{
+ Evas_Filter_Info *info;
+ if (!o) return EINA_FALSE; /* nash: do Magic check */
+
+ if (mode != EVAS_FILTER_MODE_OBJECT && mode != EVAS_FILTER_MODE_BELOW)
+ return EINA_FALSE;
+
+ if (!o->filter)
+ {
+ filter_alloc(o);
+ }
+ if (!o->filter) return EINA_FALSE;
+ info = o->filter;
+
+ if (info->mode == mode) return EINA_TRUE; /* easy case */
+ info->mode = mode;
+ info->dirty = 1;
+ return EINA_TRUE;
+}
+
+/**
+ * Get the current filtering mode for an object.
+ *
+ * By default all objects are in object filtering mode, even if no filter is
+ * set.
+ *
+ * @param o Object to get filter mode of.
+ * @return Filter mode (default EVAS_FILTER_MODE_OBJECT)
+ */
+EAPI Evas_Filter_Mode
+evas_object_filter_mode_get(Evas_Object *o)
+{
+ if (!o) return EVAS_FILTER_MODE_OBJECT; /* nash magic */
+ if (!o->filter) filter_alloc(o);
+ if (!o->filter) return EVAS_FILTER_MODE_OBJECT;
+ return o->filter->mode;
+}
+
+/**
+ * Set the current filter type.
+ *
+ * This sets the filter type, whether a blur, color filter or some other type
+ * of filter. This is normally the only filter call necessary, although some
+ * filters require additional parameters.
+ *
+ * If the object has a filter already, and existing parameters will be
+ * cleared.
+ *
+ * Setting the blur to EVAS_FILTER_NONE removes any filter.
+ *
+ * @param o Object to set the filter on.
+ * @param filter Filter to set.
+ * @return EINA_TRUE On success
+ */
+EAPI Eina_Bool
+evas_object_filter_set(Evas_Object *o, Evas_Filter filter)
+{
+ Evas_Filter_Info *info;
+ struct filterinfo *finfo;
+
+
+ if (!o) return EINA_FALSE; /* nash: magic */
+
+ /* force filter to be signed: else gcc complains, but enums may always be
+ * signed */
+ if ((int)filter < (int)EVAS_FILTER_NONE || filter > EVAS_FILTER_LAST)
+ return EINA_FALSE;
+
+ if (!o->filter) filter_alloc(o);
+ if (!o->filter) return EINA_FALSE;
+
+ info = o->filter;
+
+ if (info->filter == filter) return EINA_TRUE;
+
+ finfo = filterinfo + filter;
+ info->filter = filter;
+ info->dirty = 1;
+ if (info->data)
+ {
+ if (info->data_free)
+ info->data_free(info->data);
+ else
+ free(info->data);
+ }
+ info->datalen = finfo->datasize;
+ if (finfo->datasize)
+ info->data = calloc(1,finfo->datasize);
+ else
+ info->data = NULL;
+ info->data_free = NULL;
+
+ return EINA_TRUE;
+}
+
+
+/**
+ * Get the current filter.
+ *
+ * @param o Object to get filter of.
+ * @return The filter if set, or EVAS_FILTER_NONE.
+ */
+EAPI Evas_Filter
+evas_object_filter_get(Evas_Object *o)
+{
+ if (!o || !o->filter) return EVAS_FILTER_NONE;
+
+ return o->filter->filter;
+}
+
+/**
+ * Set an integer parameter of a filter.
+ *
+ * This sets an integer parameter of a filter, if such parameter is known to
+ * the filter. Note that some parameters may actually set multiple fields.
+ * The individual filters define the specific parameters available.
+ *
+ * It should be noted that filter parameters are lost after the filter type
+ * changes, so set the filter type, then the parameters.
+ *
+ * @param o Object to set parameter on.
+ * @param param Name of parameter to set.
+ * @param val Value to set.
+ * @return EINA_TRUE if at least one parameter was set, EINA_FALSE
+ * otherwise.
+ */
+EAPI Eina_Bool
+evas_object_filter_param_set_int(Evas_Object *o, const char *param, int val)
+{
+ char *data;
+ const struct fieldinfo *fields;
+ Eina_Bool found;
+ int i;
+
+
+ if (!o || !o->filter || !o->filter->data) return EINA_FALSE;
+
+ fields = filterfields[o->filter->filter];
+ data = o->filter->data;
+
+ found = EINA_FALSE;
+
+ for (i = 0 ; fields[i].field ; i ++)
+ {
+ if (strcmp(fields[i].field, param) == 0)
+ {
+ if (fields[i].type != TYPE_INT) continue;
+ *(int *)(data + fields[i].offset) = val;
+ o->filter->dirty = 1;
+ evas_object_change(o);
+ found = EINA_TRUE;
+ }
+ }
+
+ return found;
+}
+
+/**
+ * Get an integer value parameter from a filter.
+ *
+ * Gets the first matching parameter for a filter. Note there is no way to
+ * later fields if they do not have their own accessor name.
+ *
+ * Also note that there is no way to tell the difference between a -1 as a
+ * value, and the error code. Ask your filter writer to use a different
+ * range.
+ *
+ * @param o The object.
+ * @Param param Name of the parameter to get.
+ * @return The value, or -1 on error.
+ */
+EAPI int
+evas_object_filter_param_get_int(Evas_Object *o, const char *param)
+{
+ char *data;
+ const struct fieldinfo *fields;
+ int val;
+ int i;
+
+ if (!o || !o->filter || !o->filter->data) return -1;
+
+ fields = blurfields;
+ data = o->filter->data;
+
+ for (i = 0 ; fields[i].field ; i ++)
+ {
+ if (strcmp(fields[i].field, param) == 0)
+ {
+ if (fields[i].type != TYPE_INT) continue;
+ val = *(int *)(data + fields[i].offset);
+ return val;
+ }
+ }
+
+ return -1;
+}
+
+EAPI Eina_Bool
+evas_object_filter_param_set_str(Evas_Object *o, const char *param,
+ const char *val)
+{
+ return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+evas_object_filter_param_set_obj(Evas_Object *o, const char *param,
+ Evas_Object *val)
+{
+ return EINA_FALSE;
+}
+
+/**
+ * Set a float parameter of a filter.
+ *
+ * This is the same as evas_object_filter_param_get_int(), but for floating
+ * point values.
+ *
+ * @param o Object to set value on.
+ * @param param Name of the parameter to set.
+ * @param EINA_TRUE if at least one parameter was set, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool
+evas_object_filter_param_set_float(Evas_Object *o, const char *param,
+ double val)
+{
+ char *data;
+ const struct fieldinfo *fields;
+ int i;
+ Eina_Bool rv;
+
+ if (!o || !o->filter || !o->filter->data) return EINA_FALSE;
+
+ rv = EINA_FALSE;
+ fields = blurfields;
+ data = o->filter->data;
+
+ for (i = 0 ; fields[i].field ; i ++)
+ {
+ if (strcmp(fields[i].field, param) == 0)
+ {
+ if (fields[i].type != TYPE_FLOAT) continue;
+ *(double *)(data + fields[i].offset) = val;
+ o->filter->dirty = 1;
+ o->changed = 1;
+ evas_object_change(o);
+ rv = EINA_TRUE;
+ }
+ }
+
+ return rv;
+}
+
+/*
+ * Internal call
+ */
+int
+evas_filter_get_size(Evas_Filter_Info *info, int inw, int inh,
+ int *outw, int *outh, Eina_Bool inv)
+{
+ if (!info) return -1;
+ if (!outw && !outh) return 0;
+
+ if (filterinfo[info->filter].sizefn)
+ return filterinfo[info->filter].sizefn(info, inw, inh, outw, outh, inv);
+
+ if (outw) *outw = inw;
+ if (outh) *outh = inh;
+ return 0;
+}
+
+Eina_Bool
+evas_filter_always_alpha(Evas_Filter_Info *info)
+{
+ if (!info) return EINA_FALSE;
+ return filterinfo[info->filter].alwaysalpha;
+}
+
+/*
+ * Another internal call:
+ * Given a filterinfo, generate a unique key for it
+ *
+ * For simple filters, it's just the filter type.
+ * for more complex filters, it's the type, with it's params.
+ *
+ * Note management of the key data is up to the caller, that is it should
+ * probably be freed after use.
+ *
+ * Note the automatic fallback generation places the single byte at the end so
+ * the memcpy will be aligned. Micro-optimisations FTW!
+ *
+ * @param info Filter info to generate from
+ * @param len Length of the buffer returned.
+ * @return key KEy buffer
+ */
+uint8_t *
+evas_filter_key_get(const Evas_Filter_Info *info, uint32_t *lenp)
+{
+ struct filterinfo *finfo;
+ uint8_t *key;
+ int len;
+ if (!info) return NULL;
+
+ finfo = filterinfo + info->filter;
+
+ if (finfo->keyfn)
+ return finfo->keyfn(info, lenp);
+
+ len = 1 + finfo->datasize;
+ key = malloc(len);
+ if (finfo->datasize) memcpy(key, info->data, finfo->datasize);
+ key[finfo->datasize] = info->filter;
+
+ return key;
+}
+
+
+static int
+blur_size_get(Evas_Filter_Info *info, int inw, int inh, int *outw, int *outh,
+ Eina_Bool inv){
+ Evas_Filter_Info_Blur *blur;
+
+ blur = info->data;
+
+ if (inv)
+ {
+ if (outw) *outw = MAX(inw - blur->radius * 2, 0);
+ if (outh) *outh = MAX(inh - blur->radius * 2, 0);
+ }
+ else
+ {
+ if (outw) *outw = inw + blur->radius * 2;
+ if (outh) *outh = inh + blur->radius * 2;
+ }
+ return 0;
+}
+
+/**
+ * Generate a key for the Gaussian generator.
+ *
+ * The size is:
+ * - 1 byte for the type (blur)
+ * - 1 byte for the quality (0-1 -> 0-255)
+ * - 2 bytes for radius (max is 508 anyway)
+ *
+ * @param info Filter info
+ * @param len Length of the returned buffer
+ * @return new buffer
+ */
+static uint8_t *
+gaussian_key_get(const Evas_Filter_Info *info, uint32_t *lenp)
+{
+ struct Evas_Filter_Info_Blur *blur;
+ uint8_t *key;
+
+ if (!info || !info->data) return NULL;
+ blur = info->data;
+
+ if (lenp) *lenp = 4;
+ key = malloc(4);
+ key[0] = EVAS_FILTER_BLUR;
+ key[1] = blur->quality * 255;
+ key[2] = blur->radius >> 8;
+ key[3] = blur->radius;
+
+ return key;
+}
+
+
+Evas_Software_Filter_Fn
+evas_filter_software_get(Evas_Filter_Info *info)
+{
+ return filterinfo[info->filter].filter;
+}
+
+
+
+
+/*
+ * Private calls
+ */
+static Evas_Filter_Info *
+filter_alloc(Evas_Object *o)
+{
+ Evas_Filter_Info *info;
+ if (!o) return NULL;
+
+ info = calloc(1,sizeof(struct Evas_Filter_Info));
+ info->dirty = 1;
+ info->filter = EVAS_FILTER_NONE;
+ info->mode = EVAS_FILTER_MODE_OBJECT;
+ info->datalen = 0;
+
+ o->filter = info;
+
+ return info;
+}
+
+/**
+ * Software implementations
+ */
+
+#define alpha(x) (((x) >> 24) )
+#define red(x) (((x) >> 16) & 0xff)
+#define green(x) (((x) >> 8) & 0xff)
+#define blue(x) (((x) ) & 0xff)
+#define all(OP,A,R,G,B,W,I) \
+ do { \
+ A OP alpha(I) * W; \
+ R OP red(I) * W; \
+ G OP green(I) * W; \
+ B OP blue(I) * W; \
+ } while (0)
+#define wavg(x,n) (((x) / (n)) & 0xff)
+#define wavgd(x,n) ((uint32_t)((x) / (n)) & 0xff)
+
+typedef int (*FilterH)(int, uint32_t *, int, uint32_t *);
+typedef int (*FilterV)(int, uint32_t *, int, int, uint32_t *);
+int gaussian_filter_h(int rad, uint32_t *in, int w, uint32_t *out);
+int gaussian_filter_h64(int rad, uint32_t *in, int w, uint32_t *out);
+int gaussian_filter_hd(int rad, uint32_t *in, int w, uint32_t *out);
+int gaussian_filter_v(int rad, uint32_t *in, int h, int skip, uint32_t *out);
+int gaussian_filter_v64(int rad, uint32_t *in, int h, int skip, uint32_t *out);
+int gaussian_filter_vd(int rad, uint32_t *in, int h, int skip, uint32_t *out);
+const uint32_t *gaussian_row_get(int row, int *npoints, uint32_t *weight);
+const uint64_t *gaussian_row_get64(int row, int *npoints, uint64_t *weight);
+const double *gaussian_row_getd(int row, int *npoints, double *weight);
+
+
+Eina_Bool
+gaussian_filter(Evas_Filter_Info *filter, RGBA_Image *src, RGBA_Image *dst)
+{
+ int i;
+ uint32_t nw, nh;
+ uint32_t *in, *tmp, *out;
+ FilterV filter_v = gaussian_filter_v;
+ FilterH filter_h = gaussian_filter_h;
+ Evas_Filter_Info_Blur *blur;
+ int w,h;
+
+ blur = filter->data;
+
+ printf("Gaussian filter\n");
+ /* Use 64 bit version if we are going to overflow */
+ if (blur->radius > 508){ /** too big for doubles: Bail out */
+ return EINA_FALSE;
+ } else if (blur->radius > 28){
+ filter_v = gaussian_filter_vd;
+ filter_h = gaussian_filter_hd;
+ } else if (blur->radius > 12){
+ filter_v = gaussian_filter_v64;
+ filter_h = gaussian_filter_h64;
+ }
+
+ w = src->cache_entry.w;
+ h = src->cache_entry.h;
+ in = src->image.data;
+
+ if (!in) return EINA_FALSE;
+
+ nw = w + 2 * blur->radius;
+ nh = h + 2 * blur->radius;
+
+ out = dst->image.data;
+ if (!out) return EINA_FALSE;
+ tmp = malloc(nw * h * sizeof(uint32_t));
+
+ for (i = 0 ; i < h ; i ++)
+ filter_h(blur->radius,in + i*w,w,tmp + i*nw);
+
+ for (i = 0 ; i < nw ; i ++)
+ filter_v(blur->radius,tmp + i,h,nw,out + i);
+
+ free(tmp);
+ return EINA_TRUE;
+}
+
+/* Blur only horizontally */
+int
+gaussian_filter_h(int rad, uint32_t *in, int w, uint32_t *out){
+ const uint32_t *points;
+ int npoints;
+ uint32_t weight;
+ int i,k;
+ uint32_t r,g,b,a;
+
+ /* Get twice the radius: even rows have 1 element */
+ points = gaussian_row_get(rad * 2,&npoints, &weight);
+
+ for (i = -rad ; i < w + rad; i ++){
+ r = g = b = a = 0;
+ for (k = -rad ; k <= rad ; k ++){
+ if ((k + i) < 0) continue;
+ if ((k + i) >= w) continue;
+ all(+=, a, r, g, b, points[k + rad], in[k + i]);
+ }
+ *(out) = (wavg(a,weight) << 24) |
+ (wavg(r,weight) << 16) |
+ (wavg(g,weight) << 8) |
+ (wavg(b,weight));
+ out ++;
+ }
+
+ return 0;
+}
+
+/* Blur only horizontally */
+int
+gaussian_filter_hd(int rad, uint32_t *in, int w, uint32_t *out){
+ const double *points;
+ int npoints;
+ double weight;
+ int i,k;
+ double r,g,b,a;
+
+ /* Get twice the radius: even rows have 1 element */
+ points = gaussian_row_getd(rad * 2,&npoints, &weight);
+
+ for (i = -rad ; i < w + rad; i ++){
+ r = g = b = a = 0;
+ for (k = -rad ; k <= rad ; k ++){
+ if ((k + i) < 0) continue;
+ if ((k + i) >= w) continue;
+ all(+=, a, r, g, b, points[k + rad], in[k + i]);
+ }
+ *(out) = (wavgd(a,weight) << 24) |
+ (wavgd(r,weight) << 16) |
+ (wavgd(g,weight) << 8) |
+ (wavgd(b,weight));
+ out ++;
+ }
+
+ return 0;
+}
+
+
+/* Blur only horizontally */
+int
+gaussian_filter_h64(int rad, uint32_t *in, int w, uint32_t *out){
+ const uint64_t *points;
+ int npoints;
+ uint64_t weight;
+ int i,k;
+ uint64_t r,g,b,a;
+
+ /* Get twice the radius: even rows have 1 element */
+ points = gaussian_row_get64(rad * 2,&npoints, &weight);
+
+ for (i = -rad ; i < w + rad; i ++){
+ r = g = b = a = 0;
+ for (k = -rad ; k <= rad ; k ++){
+ if ((k + i) < 0) continue;
+ if ((k + i) >= w) continue;
+ all(+=, a, r, g, b, points[k + rad], in[k + i]);
+ }
+ *(out) = (wavg(a,weight) << 24) |
+ (wavg(r,weight) << 16) |
+ (wavg(g,weight) << 8) |
+ (wavg(b,weight));
+ out ++;
+ }
+
+ return 0;
+}
+
+
+
+int
+gaussian_filter_v(int rad, uint32_t *in, int h, int skip, uint32_t *out){
+ const uint32_t *points;
+ int npoints;
+ uint32_t weight;
+ int i,k;
+ uint32_t r,g,b,a;
+
+ /* Get twice the radius: even rows have 1 element */
+ points = gaussian_row_get(rad * 2,&npoints, &weight);
+ weight = 0;
+ for (i = 0 ; i < npoints ; i ++)
+ weight += points[i];
+
+ for (i = -rad ; i < h + rad; i ++){
+ r = g = b = a = 0;
+ for (k = -rad ; k <= rad ; k ++){
+ if ((k + i) < 0) continue;
+ if ((k + i) >= h) continue;
+ all(+=, a, r, g, b, points[k + rad],
+ in[skip * (k + i)]);
+ }
+ *(out) = (wavg(a,weight) << 24) |
+ (wavg(r,weight) << 16) |
+ (wavg(g,weight) << 8) |
+ (wavg(b,weight));
+ out += skip;
+ }
+
+ return 0;
+}
+
+int
+gaussian_filter_v64(int rad, uint32_t *in, int h, int skip, uint32_t *out){
+ const uint64_t *points;
+ int npoints;
+ uint64_t weight;
+ int i,k;
+ uint64_t r,g,b,a;
+
+ /* Get twice the radius: even rows have 1 element */
+ points = gaussian_row_get64(rad * 2,&npoints, &weight);
+ weight = 0;
+ for (i = 0 ; i < npoints ; i ++)
+ weight += points[i];
+
+ for (i = -rad ; i < h + rad; i ++){
+ r = g = b = a = 0;
+ for (k = -rad ; k <= rad ; k ++){
+ if ((k + i) < 0) continue;
+ if ((k + i) >= h) continue;
+ all(+=, a, r, g, b, points[k + rad],
+ in[skip * (k + i)]);
+ }
+ *(out) = (wavg(a,weight) << 24) |
+ (wavg(r,weight) << 16) |
+ (wavg(g,weight) << 8) |
+ (wavg(b,weight));
+ out += skip;
+ }
+
+ return 0;
+}
+
+
+int
+gaussian_filter_vd(int rad, uint32_t *in, int h, int skip, uint32_t *out){
+ const double *points;
+ int npoints;
+ double weight;
+ int i,k;
+ double r,g,b,a;
+
+ /* Get twice the radius: even rows have 1 element */
+ points = gaussian_row_getd(rad * 2,&npoints, &weight);
+ weight = 0;
+ for (i = 0 ; i < npoints ; i ++)
+ weight += points[i];
+
+ for (i = -rad ; i < h + rad; i ++){
+ r = g = b = a = 0;
+ for (k = -rad ; k <= rad ; k ++){
+ if ((k + i) < 0) continue;
+ if ((k + i) >= h) continue;
+ all(+=, a, r, g, b, points[k + rad],
+ in[skip * (k + i)]);
+ }
+ *(out) = (wavgd(a,weight) << 24) |
+ (wavgd(r,weight) << 16) |
+ (wavgd(g,weight) << 8) |
+ (wavgd(b,weight));
+ out += skip;
+ }
+
+ return 0;
+}
+
+
+const uint32_t *
+gaussian_row_get(int row, int *npoints, uint32_t *weight){
+ static uint32_t *points = NULL;
+ static int last = -1;
+ static uint32_t lastweight = -1;
+ int c,k;
+
+ if (row < 0) return NULL;
+
+ if (npoints) *npoints = row + 1;
+
+ if (last == row){
+ if (weight) *weight = lastweight;
+ return points;
+ }
+ if (points) free(points);
+
+ points = malloc((row + 1) * sizeof(uint32_t));
+ if (!points){
+ last = -1;
+ return NULL;
+ }
+ last = row;
+
+
+ c = 1;
+ for (k = 0 ; k <= row ; k ++){
+ points[k] = c;
+ c = c * (row-k)/(k+1);
+ }
+
+ for (k = 0, lastweight = 0 ; k <= row ; k ++)
+ lastweight += points[k];
+
+ if (weight) *weight = lastweight;
+
+ return points;
+}
+
+const uint64_t *
+gaussian_row_get64(int row, int *npoints, uint64_t *weight){
+ static uint64_t *points = NULL;
+ static int last = -1;
+ static uint64_t lastweight = -1;
+ uint64_t c;
+ int k;
+
+ if (row < 0) return NULL;
+
+ if (npoints) *npoints = row + 1;
+ if (last == row){
+ if (weight) *weight = lastweight;
+ return points;
+ }
+ if (points) free(points);
+
+ points = malloc((row + 1) * sizeof(uint64_t));
+ if (!points){
+ last = -1;
+ return NULL;
+ }
+ last = row;
+
+
+ c = 1;
+ for (k = 0 ; k <= row ; k ++){
+ points[k] = c;
+ c = c * (row-k)/(k+1);
+ }
+
+ for (k = 0, lastweight = 0 ; k <= row ; k ++)
+ lastweight += points[k];
+
+ if (weight) *weight = lastweight;
+
+ return points;
+}
+const double *
+gaussian_row_getd(int row, int *npoints, double *weight){
+ static double *points = NULL;
+ static int last = -1;
+ static double lastweight = -1;
+ double c;
+ int k;
+
+ if (row < 0) return NULL;
+
+ if (last == row){
+ if (weight) *weight = lastweight;
+ return points;
+ }
+
+ if (points) free(points);
+ points = malloc((row + 1) * sizeof(double));
+ if (!points){
+ last = -1;
+ return NULL;
+ }
+ last = row;
+
+ if (npoints) *npoints = row + 1;
+
+ c = 1;
+ for (k = 0 ; k <= row ; k ++){
+ points[k] = c;
+ c = c * (row-k)/(k+1);
+ }
+
+ for (k = 0, lastweight = 0 ; k <= row ; k ++)
+ lastweight += points[k];
+
+ if (weight) *weight = lastweight;
+
+ return points;
+}
+
+
+
+static Eina_Bool
+negation_filter(Evas_Filter_Info *info, RGBA_Image *src, RGBA_Image *dst)
+{
+ uint32_t *in, *out;
+ int i,j;
+ int w,h;
+ uint32_t mask,a;
+
+ if (BUILD_NEON0 && evas_common_cpu_has_feature(CPU_FEATURE_NEON))
+ return negation_filter_neon(info, src, dst);
+
+ in = src->image.data;
+ out = dst->image.data;
+ w = src->cache_entry.w;
+ h = src->cache_entry.h;
+
+ if (src->cache_entry.flags.alpha)
+ {
+ for (i = 0 ; i < h ; i ++)
+ {
+ for (j = 0 ; j < w ; j ++)
+ {
+ a = (*in >> 24) & 0xff;
+ mask = a | (a << 8) | (a << 16);
+ *out = (mask - (*in & 0xffffff)) | (a << 24);
+ out ++;
+ in ++;
+ }
+ }
+
+ }
+ else
+ {
+ for (i = 0 ; i < h ; i ++)
+ {
+ for (j = 0 ; j < w ; j ++)
+ {
+ *out = ~(*in & ~0xff000000) | ((*in) & 0xff000000);
+ out ++;
+ in ++;
+ }
+ }
+ }
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+negation_filter_neon(Evas_Filter_Info *info, RGBA_Image *src, RGBA_Image *dst)
+{
+#if BUILD_NEON0
+ uint32_t tmp;
+
+ if (src->cache_entry.flags.alpha)
+ {
+
+ }
+ else
+ {
+ /* No alpha */
+#define AP "NEG_FILTER_NA"
+ asm volatile (
+
+ ".fpu neon \n\t"
+ "vdup.u32 q14, $0xff000000 \n\t"
+ "vmvn.u32 q15, q1 \n\t"
+
+ // fixme: do check for small loops
+ AP"loopinit: \n\t"
+ "sub %[tmp], %[e], #31 \n\t"
+
+ AP"loop: \n\t"
+ "vldm %[s]!, {d0,d1,d2,d3} \n\t"
+ "vand q2, q0, q15 \n\t"
+ "vand q3, q1, q15 \n\t"
+ "vand q4, q0, q14 \n\t"
+ "vand q5, q1, q14 \n\t"
+ // fixme: can i do this with xor
+ "cmp %[tmp], %[s] \n\t"
+
+ "vmvn q6, q2 \n\t"
+ "vmvn q7, q3 \n\t"
+
+ "vor q0, q6,q4 \n\t"
+ "vor q1, q7,q5 \n\t"
+
+ "vstm %[d]1, {d0,d1,d2,d3} \n\t"
+
+ "bhi "AP"loop \n\t"
+
+ : // no out
+ : // input
+ [e] "r" (src->image.data+ src->cache_entry.w*src->cache_entry.h),
+ [s] "r" (src->image.data),
+ [tmp] "r" (tmp),
+ [d] "r" (dst->image.data)
+ : "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q14", "q15",
+ "memory"
+ );
+#undef AP
+ }
+
+
+
+
+#endif
+ return EINA_TRUE;
+}
+
+
+
+
+
+static Eina_Bool
+sepia_filter(Evas_Filter_Info *info, RGBA_Image *src, RGBA_Image *dst)
+{
+ uint32_t *in, *out;
+ int i,j;
+ int w,h;
+ uint32_t r,g,b,nr,ng,nb;
+
+ in = src->image.data;
+ out = dst->image.data;
+ w = src->cache_entry.w;
+ h = src->cache_entry.h;
+
+ for (i = 0 ; i < h ; i ++)
+ {
+ for (j = 0; j < w ; j ++)
+ {
+ r = R_VAL(in);
+ g = G_VAL(in);
+ b = B_VAL(in);
+ nr = ((uint32_t)((r * .393) + (g *.769) + (b * .189)));
+ ng = ((uint32_t)((r * .349) + (g *.686) + (b * .168)));
+ nb = ((uint32_t)((r * .272) + (g *.534) + (b * .131)));
+ if (nr > 255) nr = 255;
+ if (ng > 255) ng = 255;
+ if (nb > 255) nb = 255;
+ *out = (*in & 0xff000000) | (nr << 16) | (ng << 8) | nb;
+ out ++;
+ in ++;
+ }
+ }
+
+ return EINA_TRUE;
+
+}
+static Eina_Bool
+greyscale_filter(Evas_Filter_Info *info, RGBA_Image *src, RGBA_Image *dst)
+{
+ uint32_t *in, *out;
+ int i,j;
+ int w,h;
+ uint32_t cur;
+ uint32_t a, r,g,b;
+
+ in = src->image.data;
+ out = dst->image.data;
+ w = src->cache_entry.w;
+ h = src->cache_entry.h;
+
+ if (src->cache_entry.flags.alpha)
+ {
+ for (i = 0 ; i < h ; i ++)
+ {
+ for (j = 0; j < w ; j ++)
+ {
+ a = A_VAL(in);
+ r = R_VAL(in);
+ g = G_VAL(in);
+ b = B_VAL(in);
+ cur = r * 0.3 + g * 0.59 + b * 0.11;
+ cur |= cur << 16;
+ *out = (a << 24) | cur | (cur << 8);
+ out ++;
+ in ++;
+ }
+ }
+ }
+ else
+ {
+ for (i = 0 ; i < h ; i ++)
+ {
+ for (j = 0; j < w ; j ++)
+ {
+ r = R_VAL(in);
+ g = G_VAL(in);
+ b = B_VAL(in);
+ cur = r * 0.3 + g * 0.59 + b * 0.11;
+ cur |= cur << 16;
+ *out = 0xff000000 | cur | (cur << 8);
+ out ++;
+ in ++;
+ }
+ }
+ }
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+brightness_filter(Evas_Filter_Info *info, RGBA_Image *src, RGBA_Image *dst)
+{
+ uint32_t *in, *out;
+ int i,j;
+ int w,h;
+
+ in = src->image.data;
+ out = dst->image.data;
+ w = src->cache_entry.w;
+ h = src->cache_entry.h;
+
+ for (i = 0 ; i < h ; i ++)
+ {
+ for (j = 0; j < w ; j ++)
+ {
+ out ++;
+ in ++;
+ }
+ }
+
+
+ return EINA_TRUE;
+
+}
+static Eina_Bool
+contrast_filter(Evas_Filter_Info *info, RGBA_Image *src, RGBA_Image *dst)
+{
+ uint32_t *in, *out;
+ int i,j;
+ int w,h;
+
+ in = src->image.data;
+ out = dst->image.data;
+ w = src->cache_entry.w;
+ h = src->cache_entry.h;
+
+ for (i = 0 ; i < h ; i ++)
+ {
+ for (j = 0; j < w ; j ++)
+ {
+ out ++;
+ in ++;
+ }
+ }
+
+ return EINA_TRUE;
+
+}
+
+
+
+
+
+
+/* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/
_evas_common_rgba_image_delete(Image_Entry *ie)
{
RGBA_Image *im = (RGBA_Image *) ie;
+ Filtered_Image *fi;
#ifdef BUILD_PIPE_RENDER
evas_common_pipe_free(im);
#ifdef EVAS_CSERVE
if (ie->data1) evas_cserve_image_free(ie);
#endif
+
+ EINA_LIST_FREE(im->filtered, fi)
+ {
+ free(fi->key);
+ _evas_common_rgba_image_delete((Image_Entry *)(fi->image));
+ free(fi);
+ }
+
free(im);
}
/*****************************************************************************/
+typedef struct _Filtered_Image Filtered_Image;
+
struct _RGBA_Image_Loadopts
{
int scale_down_by; // if > 1 then use this
Eina_Bool dirty: 1;
} mask;
+ Eina_List *filtered;
+
struct {
LK(lock);
Eina_List *list;
FPc px, py, z0, foc;
};
+struct _Filtered_Image
+{
+ void *key;
+ size_t keylen;
+ RGBA_Image *image;
+ int ref;
+};
+
// for fonts...
/////
typedef struct _Fash_Item_Index_Map Fash_Item_Index_Map;
Evas_Map_Point points[]; // actual points
};
+/* nash: Split into two bits */
+typedef struct Evas_Filter_Info
+{
+ Evas_Filter filter;
+ Evas_Filter_Mode mode;
+
+ Eina_Bool dirty : 1;
+
+ int datalen;
+ void *data;
+ void (*data_free)(void *);
+
+ uint8_t *key;
+ uint32_t len;
+ Filtered_Image *cached;
+} Evas_Filter_Info;
+
+typedef Eina_Bool (*Evas_Software_Filter_Fn)(Evas_Filter_Info *, RGBA_Image *, RGBA_Image *);
+
+Evas_Software_Filter_Fn evas_filter_software_get(Evas_Filter_Info *info);
+int evas_filter_get_size(Evas_Filter_Info *info, int inw, int inh,
+ int *outw, int *outh, Eina_Bool inv);
+Eina_Bool evas_filter_always_alpha(Evas_Filter_Info *info);
+
struct _Evas_Object
{
EINA_INLIST;
Eina_Bool redraw;
} proxy;
+ Evas_Filter_Info *filter;
+
Evas_Size_Hints *size_hints;
int last_mouse_down_counter;
Eina_Bool (*font_text_props_info_create) (void *data __UNUSED__, void *font, const Eina_Unicode *text, Evas_Text_Props *intl_props, const Evas_BiDi_Paragraph_Props *par_props, size_t pos, size_t len);
int (*font_right_inset_get) (void *data, void *font, const Evas_Text_Props *text_props);
+ void (*image_draw_filtered) (void *data, void *context, void *surface, void *image, Evas_Filter_Info *filter);
+ Filtered_Image *(*image_filtered_get) (void *image, uint8_t *key, size_t len);
+ Filtered_Image *(*image_filtered_save) (void *image, void *filtered, uint8_t *key, size_t len);
+ void (*image_filtered_free) (void *image, Filtered_Image *);
+
/* EFL-GL Glue Layer */
void *(*gl_surface_create) (void *data, void *config, int w, int h);
int (*gl_surface_destroy) (void *data, void *surface);
evas_gl_font.c \
evas_gl_polygon.c \
evas_gl_line.c \
+evas_gl_filter.c \
shader/rect_frag.h \
shader/rect_frag_bin_s3c6410.h \
shader/rect_vert.h \
shader/tex_nomul_frag.h \
shader/tex_nomul_frag_bin_s3c6410.h \
shader/tex_nomul_vert.h \
-shader/tex_nomul_vert_bin_s3c6410.h
+shader/tex_nomul_vert_bin_s3c6410.h \
+shader/filter_invert.h \
+shader/filter_invert_nomul.h \
+shader/filter_invert_bgra.h \
+shader/filter_invert_bgra_nomul.h \
+shader/filter_sepia.h \
+shader/filter_sepia_nomul.h \
+shader/filter_sepia_bgra.h \
+shader/filter_sepia_bgra_nomul.h \
+shader/filter_greyscale.h \
+shader/filter_greyscale_nomul.h \
+shader/filter_greyscale_bgra.h \
+shader/filter_greyscale_bgra_nomul.h \
+shader/filter_blur.h \
+shader/filter_blur_nomul.h \
+shader/filter_blur_bgra.h \
+shader/filter_blur_bgra_nomul.h
+
+
libevas_engine_gl_common_la_LIBADD = @EINA_LIBS@ @evas_engine_gl_common_libs@ @dlopen_libs@
endif
shader/tex_frag_s3c6410.asm \
shader/tex_vert.shd \
shader/tex_nomul_frag.shd \
-shader/tex_nomul_vert.shd
+shader/tex_nomul_vert.shd \
+shader/filter_invert.shd \
+shader/filter_invert_nomul.shd \
+shader/filter_invert_bgra.shd \
+shader/filter_invert_bgra_nomul.shd \
+shader/filter_greyscale.shd \
+shader/filter_greyscale_nomul.shd \
+shader/filter_greyscale_bgra.shd \
+shader/filter_greyscale_bgra_nomul.shd \
+shader/filter_sepia.shd \
+shader/filter_sepia_nomul.shd \
+shader/filter_sepia_bgra.shd \
+shader/filter_sepia_bgra_nomul.shd \
+shader/filter_blur.shd \
+shader/filter_blur_nomul.shd \
+shader/filter_blur_bgra.shd \
+shader/filter_blur_bgra_nomul.shd
+
Evas_GL_Program img_mask;
Evas_GL_Program yuv, yuv_nomul;
Evas_GL_Program tex, tex_nomul;
+
+ Evas_GL_Program filter_invert, filter_invert_nomul;
+ Evas_GL_Program filter_invert_bgra, filter_invert_bgra_nomul;
+ Evas_GL_Program filter_greyscale, filter_greyscale_nomul;
+ Evas_GL_Program filter_greyscale_bgra, filter_greyscale_bgra_nomul;
+ Evas_GL_Program filter_sepia, filter_sepia_nomul;
+ Evas_GL_Program filter_sepia_bgra, filter_sepia_bgra_nomul;
+#if 0
+ Evas_GL_Program filter_blur_vert;
+ Evas_GL_Program filter_blur, filter_blur_nomul;
+ Evas_GL_Program filter_blur_bgra, filter_blur_bgra_nomul;
+#endif
} shader;
int references;
int w, h;
Eina_Bool havestuff : 1;
Evas_GL_Image *def_surface;
+
+ /* If this is set: Force drawing with a particular filter */
+ GLuint filter_prog;
#if defined (GLES_VARIETY_S3C6410) || defined (GLES_VARIETY_SGX)
// FIXME: hack. expose egl display to gl core for egl image sec extn.
int scale_hint, content_hint;
int csize;
+ Eina_List *filtered;
+
unsigned char dirty : 1;
unsigned char cached : 1;
unsigned char alpha : 1;
extern Evas_GL_Program_Source shader_tex_nomul_frag_src;
extern Evas_GL_Program_Source shader_tex_nomul_vert_src;
+extern Evas_GL_Program_Source shader_filter_invert_frag_src;
+extern Evas_GL_Program_Source shader_filter_invert_nomul_frag_src;
+extern Evas_GL_Program_Source shader_filter_invert_bgra_frag_src;
+extern Evas_GL_Program_Source shader_filter_invert_bgra_nomul_frag_src;
+extern Evas_GL_Program_Source shader_filter_sepia_frag_src;
+extern Evas_GL_Program_Source shader_filter_sepia_nomul_frag_src;
+extern Evas_GL_Program_Source shader_filter_sepia_bgra_frag_src;
+extern Evas_GL_Program_Source shader_filter_sepia_bgra_nomul_frag_src;
+extern Evas_GL_Program_Source shader_filter_greyscale_frag_src;
+extern Evas_GL_Program_Source shader_filter_greyscale_nomul_frag_src;
+extern Evas_GL_Program_Source shader_filter_greyscale_bgra_frag_src;
+extern Evas_GL_Program_Source shader_filter_greyscale_bgra_nomul_frag_src;
+#if 0
+/* blur (annoyingly) needs (aka is faster with) a vertex shader */
+extern Evas_GL_Program_Source shader_filter_blur_vert_src;
+extern Evas_GL_Program_Source shader_filter_blur_frag_src;
+extern Evas_GL_Program_Source shader_filter_blur_nomul_frag_src;
+extern Evas_GL_Program_Source shader_filter_blur_bgra_frag_src;
+extern Evas_GL_Program_Source shader_filter_blur_bgra_nomul_frag_src;
+#endif
+
void glerr(int err, const char *file, const char *func, int line, const char *op);
Evas_Engine_GL_Context *evas_gl_common_context_new(void);
void evas_gl_common_image_free(Evas_GL_Image *im);
Evas_GL_Image *evas_gl_common_image_surface_new(Evas_Engine_GL_Context *gc, unsigned int w, unsigned int h, int alpha);
void evas_gl_common_image_dirty(Evas_GL_Image *im, unsigned int x, unsigned int y, unsigned int w, unsigned int h);
+void evas_gl_common_image_update(Evas_Engine_GL_Context *gc, Evas_GL_Image *im);
void evas_gl_common_image_map_draw(Evas_Engine_GL_Context *gc, Evas_GL_Image *im, int npoints, RGBA_Map_Point *p, int smooth, int level);
void evas_gl_common_image_draw(Evas_Engine_GL_Context *gc, Evas_GL_Image *im, int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh, int smooth);
void evas_gl_common_line_draw(Evas_Engine_GL_Context *gc, int x1, int y1, int x2, int y2);
+void evas_gl_common_filter_draw(void *data, Evas_Engine_GL_Context *context, void *image, Evas_Filter_Info *filter);
+Filtered_Image *evas_gl_common_image_filtered_get(Evas_GL_Image *im, uint8_t *key, size_t keylen);
+Filtered_Image *evas_gl_common_image_filtered_save(Evas_GL_Image *im, Evas_GL_Image *fimage, uint8_t *key, size_t keylen);
+void evas_gl_common_image_filtered_free(Evas_GL_Image *im, Filtered_Image *);
+
+
extern void (*glsym_glGenFramebuffers) (GLsizei a, GLuint *b);
extern void (*glsym_glBindFramebuffer) (GLenum a, GLuint b);
extern void (*glsym_glFramebufferTexture2D) (GLenum a, GLenum b, GLenum c, GLuint d, GLint e);
glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.img_mask.prog, "mvp"), 1,
GL_FALSE, proj);
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+ glUseProgram(gc->shared->shader.filter_invert.prog);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+ glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_invert.prog, "mvp"), 1,
+ GL_FALSE, proj);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+ glUseProgram(gc->shared->shader.filter_invert_nomul.prog);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+ glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_invert_nomul.prog, "mvp"), 1,
+ GL_FALSE, proj);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+ glUseProgram(gc->shared->shader.filter_invert_bgra.prog);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+ glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_invert_bgra.prog, "mvp"), 1,
+ GL_FALSE, proj);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+ glUseProgram(gc->shared->shader.filter_invert_bgra_nomul.prog);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+ glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_invert_bgra_nomul.prog, "mvp"), 1,
+ GL_FALSE, proj);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+
+ glUseProgram(gc->shared->shader.filter_greyscale.prog);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+ glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_greyscale.prog, "mvp"), 1,
+ GL_FALSE, proj);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+ glUseProgram(gc->shared->shader.filter_greyscale_nomul.prog);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+ glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_greyscale_nomul.prog, "mvp"), 1,
+ GL_FALSE, proj);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+ glUseProgram(gc->shared->shader.filter_greyscale_bgra.prog);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+ glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_greyscale_bgra.prog, "mvp"), 1,
+ GL_FALSE, proj);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+ glUseProgram(gc->shared->shader.filter_greyscale_bgra_nomul.prog);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+ glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_greyscale_bgra_nomul.prog, "mvp"), 1,
+ GL_FALSE, proj);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+
+ glUseProgram(gc->shared->shader.filter_sepia.prog);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+ glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_sepia.prog, "mvp"), 1,
+ GL_FALSE, proj);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+ glUseProgram(gc->shared->shader.filter_sepia_nomul.prog);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+ glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_sepia_nomul.prog, "mvp"), 1,
+ GL_FALSE, proj);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+ glUseProgram(gc->shared->shader.filter_sepia_bgra.prog);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+ glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_sepia_bgra.prog, "mvp"), 1,
+ GL_FALSE, proj);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+ glUseProgram(gc->shared->shader.filter_sepia_bgra_nomul.prog);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+ glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_sepia_bgra_nomul.prog, "mvp"), 1,
+ GL_FALSE, proj);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+#if 0
+ glUseProgram(gc->shared->shader.filter_blur_bgra_nomul.prog);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+ glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_blur_bgra_nomul.prog, "mvp"), 1,
+ GL_FALSE, proj);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+ glUseProgram(gc->shared->shader.filter_blur_bgra_nomul.prog);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+ glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_blur_bgra_nomul.prog, "mvp"), 1,
+ GL_FALSE, proj);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+ glUseProgram(gc->shared->shader.filter_blur_bgra_nomul.prog);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+ glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_blur_bgra_nomul.prog, "mvp"), 1,
+ GL_FALSE, proj);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+ glUseProgram(gc->shared->shader.filter_blur_bgra_nomul.prog);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+ glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_blur_bgra_nomul.prog, "mvp"), 1,
+ GL_FALSE, proj);
+ GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+#endif
glUseProgram(gc->pipe[0].shader.cur_prog);
&(shader_yuv_nomul_vert_src),
&(shader_yuv_nomul_frag_src),
"yuv_nomul")) goto error;
+
+ /* Most of the filters use the image fragment shader */
+ if (!evas_gl_common_shader_program_init(&(shared->shader.filter_invert),
+ &(shader_img_vert_src),
+ &(shader_filter_invert_frag_src),
+ "filter_invert")) goto error;
+ if (!evas_gl_common_shader_program_init(&(shared->shader.filter_invert_nomul),
+ &(shader_img_vert_src),
+ &(shader_filter_invert_nomul_frag_src),
+ "filter_invert_nomul")) goto error;
+ if (!evas_gl_common_shader_program_init(&(shared->shader.filter_invert_bgra),
+ &(shader_img_vert_src),
+ &(shader_filter_invert_bgra_frag_src),
+ "filter_invert_bgra")) goto error;
+ if (!evas_gl_common_shader_program_init(&(shared->shader.filter_invert_bgra_nomul),
+ &(shader_img_vert_src),
+ &(shader_filter_invert_bgra_nomul_frag_src),
+ "filter_invert_bgra_nomul")) goto error;
+
+ if (!evas_gl_common_shader_program_init(&(shared->shader.filter_sepia),
+ &(shader_img_vert_src),
+ &(shader_filter_sepia_frag_src),
+ "filter_sepia")) goto error;
+ if (!evas_gl_common_shader_program_init(&(shared->shader.filter_sepia_nomul),
+ &(shader_img_vert_src),
+ &(shader_filter_sepia_nomul_frag_src),
+ "filter_sepia_nomul")) goto error;
+ if (!evas_gl_common_shader_program_init(&(shared->shader.filter_sepia_bgra),
+ &(shader_img_vert_src),
+ &(shader_filter_sepia_bgra_frag_src),
+ "filter_sepia_bgra")) goto error;
+ if (!evas_gl_common_shader_program_init(&(shared->shader.filter_sepia_bgra_nomul),
+ &(shader_img_vert_src),
+ &(shader_filter_sepia_bgra_nomul_frag_src),
+ "filter_sepia_bgra_nomul")) goto error;
+
+ if (!evas_gl_common_shader_program_init(&(shared->shader.filter_greyscale),
+ &(shader_img_vert_src),
+ &(shader_filter_greyscale_frag_src),
+ "filter_greyscale")) goto error;
+ if (!evas_gl_common_shader_program_init(&(shared->shader.filter_greyscale_nomul),
+ &(shader_img_vert_src),
+ &(shader_filter_greyscale_nomul_frag_src),
+ "filter_greyscale_nomul")) goto error;
+ if (!evas_gl_common_shader_program_init(&(shared->shader.filter_greyscale_bgra),
+ &(shader_img_vert_src),
+ &(shader_filter_greyscale_bgra_frag_src),
+ "filter_greyscale_bgra")) goto error;
+ if (!evas_gl_common_shader_program_init(&(shared->shader.filter_greyscale_bgra_nomul),
+ &(shader_img_vert_src),
+ &(shader_filter_greyscale_bgra_nomul_frag_src),
+ "filter_greyscale_bgra_nomul")) goto error;
+#if 0
+ if (!evas_gl_common_shader_program_init(&(shared->shader.filter_blur),
+ &(shader_filter_blur_vert_src),
+ &(shader_filter_blur_frag_src),
+ "filter_blur")) goto error;
+ if (!evas_gl_common_shader_program_init(&(shared->shader.filter_blur_nomul),
+ &(shader_filter_blur_vert_src),
+ &(shader_filter_blur_nomul_frag_src),
+ "filter_blur_nomul")) goto error;
+ if (!evas_gl_common_shader_program_init(&(shared->shader.filter_blur_bgra),
+ &(shader_filter_blur_vert_src),
+ &(shader_filter_blur_bgra_frag_src),
+ "filter_blur_bgra")) goto error;
+ if (!evas_gl_common_shader_program_init(&(shared->shader.filter_blur_bgra_nomul),
+ &(shader_filter_blur_vert_src),
+ &(shader_filter_blur_bgra_nomul_frag_src),
+ "filter_blur_bgra_nomul")) goto error;
+#endif
+
+
glUseProgram(shared->shader.yuv.prog);
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
evas_gl_common_shader_program_shutdown(&(gc->shared->shader.yuv_nomul));
evas_gl_common_shader_program_shutdown(&(gc->shared->shader.tex));
evas_gl_common_shader_program_shutdown(&(gc->shared->shader.tex_nomul));
-
+
+ evas_gl_common_shader_program_shutdown(&(gc->shared->shader.filter_invert));
+
while (gc->shared->images)
{
evas_gl_common_image_free(gc->shared->images->data);
if (!tex->alpha) blend = 0;
if (a < 255) blend = 1;
-
- if (tex_only)
+
+ if (gc->filter_prog)
+ {
+ prog = gc->filter_prog;
+ }
+ else if (tex_only)
{
if (tex->pt->dyn.img)
{
--- /dev/null
+#include "evas_gl_private.h"
+
+
+void
+evas_gl_common_filter_draw(void *data, Evas_Engine_GL_Context *gc,
+ void *image, Evas_Filter_Info *filter)
+{
+ Evas_GL_Image *im = image;
+ RGBA_Draw_Context *dc;
+ GLuint prog;
+ int r,g,b,a;
+ int nomul, bgra;
+
+ dc = gc->dc;
+
+ if (dc->mul.use)
+ {
+ a = (dc->mul.col >> 24) & 0xff;
+ r = (dc->mul.col >> 16) & 0xff;
+ g = (dc->mul.col >> 8 ) & 0xff;
+ b = (dc->mul.col ) & 0xff;
+ }
+ else
+ {
+ r = g = b = a = 255;
+ }
+
+ nomul = (a == 255 && r == 255 && g == 255 && b == 255) ? 1 : 0;
+ bgra = (gc->shared->info.bgra) ? 1 : 0;
+
+ /* FIXME: This should so be a table */
+#if 0
+ if (filter->filter == EVAS_FILTER_BLUR)
+ {
+ if (bgra)
+ {
+ if (nomul)
+ prog = gc->shared->shader.filter_blur_bgra_nomul.prog;
+ else
+ prog = gc->shared->shader.filter_blur_bgra.prog;
+ }
+ else
+ {
+ if (a == 255 && r == 255 && g == 255 && b == 255)
+ prog = gc->shared->shader.filter_blur_nomul.prog;
+ else
+ prog = gc->shared->shader.filter_blur.prog;
+ }
+ }
+ else
+#endif
+ if (filter->filter == EVAS_FILTER_INVERT)
+ {
+ if (bgra)
+ {
+ if (nomul)
+ prog = gc->shared->shader.filter_invert_bgra_nomul.prog;
+ else
+ prog = gc->shared->shader.filter_invert_bgra.prog;
+ }
+ else
+ {
+ if (a == 255 && r == 255 && g == 255 && b == 255)
+ prog = gc->shared->shader.filter_invert_nomul.prog;
+ else
+ prog = gc->shared->shader.filter_invert.prog;
+ }
+ }
+ else if (filter->filter == EVAS_FILTER_SEPIA)
+ {
+ if (bgra)
+ {
+ if (nomul)
+ prog = gc->shared->shader.filter_sepia_bgra_nomul.prog;
+ else
+ prog = gc->shared->shader.filter_sepia_bgra.prog;
+ }
+ else
+ {
+ if (nomul)
+ prog = gc->shared->shader.filter_sepia_nomul.prog;
+ else
+ prog = gc->shared->shader.filter_sepia.prog;
+ }
+
+ }
+ else /*if (filter->filter == EVAS_FILTER_GREYSCALE)*/
+ {
+ printf("BGRA: %s Nomul: %s\n",bgra?"true":"false",nomul?"nomul":"mul");
+ if (bgra)
+ {
+ if (nomul)
+ prog = gc->shared->shader.filter_greyscale_bgra_nomul.prog;
+ else
+ prog = gc->shared->shader.filter_greyscale_bgra.prog;
+ }
+ else
+ {
+ if (nomul)
+ prog = gc->shared->shader.filter_greyscale_nomul.prog;
+ else
+ prog = gc->shared->shader.filter_greyscale.prog;
+ }
+
+ }
+
+ printf("Prog: %d %d %d\n",prog,im->w,im->h);
+ gc->filter_prog = prog;
+ evas_gl_common_image_update(gc, im);
+ evas_gl_common_context_image_push(gc, im->tex, 0, 0, im->w, im->h,
+ 0, 0, im->w, im->h,
+ r,g,b,a,
+ 1, im->tex_only);
+ gc->filter_prog = 0;
+}
+
+
+Filtered_Image *
+evas_gl_common_image_filtered_get(Evas_GL_Image *im, uint8_t *key, size_t len)
+{
+ Filtered_Image *fi;
+ Eina_List *l;
+
+ for (l = im->filtered ; l ; l = l->next)
+ {
+ fi = l->data;
+ if (fi->keylen != len) continue;
+ if (memcmp(key, fi->key, len) != 0) continue;
+ fi->ref ++;
+ return fi;
+ }
+
+ return NULL;
+}
+
+Filtered_Image *
+evas_gl_common_image_filtered_save(Evas_GL_Image *im, Evas_GL_Image *fimage,
+ uint8_t *key, size_t keylen)
+{
+ Filtered_Image *fi;
+ Eina_List *l;
+
+ for (l = im->filtered ; l ; l = l->next)
+ {
+ fi = l->data;
+ if (fi->keylen != keylen) continue;
+ if (memcmp(key, fi->key, keylen) != 0) continue;
+
+ fi->image = (void *)fimage;
+ fi->ref ++;
+ return fi;
+ }
+
+ fi = calloc(1,sizeof(Filtered_Image));
+ if (!fi) return NULL;
+
+ fi->keylen = keylen;
+ fi->key = malloc(keylen);
+ memcpy(fi->key, key, keylen);
+ fi->image = (void *)fimage;
+ fi->ref = 1;
+
+ im->filtered = eina_list_prepend(im->filtered, fi);
+
+ return fi;
+}
+
+void
+evas_gl_common_image_filtered_free(Evas_GL_Image *image, Filtered_Image *fi)
+{
+ fi->ref --;
+ if (fi->ref) return;
+
+ free(fi->key);
+ evas_gl_common_image_free((void *)fi->image);
+ fi->image = NULL;
+
+ image->filtered = eina_list_remove(image->filtered, fi);
+}
+
+
+
+/* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/
void
evas_gl_common_image_free(Evas_GL_Image *im)
{
+ Filtered_Image *fi;
+
+ evas_gl_common_context_flush(im->gc);
im->references--;
if (im->references > 0) return;
}
if (im->im) evas_cache_image_drop(&im->im->cache_entry);
if (im->tex) evas_gl_common_texture_free(im->tex);
+
+ EINA_LIST_FREE(im->filtered, fi)
+ {
+ free(fi->key);
+ evas_gl_common_image_free((Evas_GL_Image *)fi->image);
+ free(fi);
+ }
+
+
free(im);
}
im->dirty = 1;
}
-static void
-_evas_gl_common_image_update(Evas_Engine_GL_Context *gc, Evas_GL_Image *im)
+void
+evas_gl_common_image_update(Evas_Engine_GL_Context *gc, Evas_GL_Image *im)
{
if (!im->im) return;
/*
r = g = b = a = 255;
}
- _evas_gl_common_image_update(gc, im);
+ evas_gl_common_image_update(gc, im);
c = gc->dc->clip.use;
cx = gc->dc->clip.x; cy = gc->dc->clip.y;
r = g = b = a = 255;
}
- _evas_gl_common_image_update(gc, im);
+ evas_gl_common_image_update(gc, im);
if (!im->tex)
{
evas_gl_common_rect_draw(gc, dx, dy, dw, dh);
};
/////////////////////////////////////////////
+const char filter_invert_frag_glsl[] =
+#include "shader/filter_invert.h"
+ ;
+Evas_GL_Program_Source shader_filter_invert_frag_src =
+{
+ filter_invert_frag_glsl,
+ NULL, 0
+};
+
+const char filter_invert_nomul_frag_glsl[] =
+#include "shader/filter_invert_nomul.h"
+ ;
+Evas_GL_Program_Source shader_filter_invert_nomul_frag_src =
+{
+ filter_invert_nomul_frag_glsl,
+ NULL, 0
+};
+
+const char filter_invert_bgra_frag_glsl[] =
+#include "shader/filter_invert_bgra.h"
+ ;
+Evas_GL_Program_Source shader_filter_invert_bgra_frag_src =
+{
+ filter_invert_bgra_frag_glsl,
+ NULL, 0
+};
+const char filter_invert_bgra_nomul_frag_glsl[] =
+#include "shader/filter_invert_bgra_nomul.h"
+ ;
+Evas_GL_Program_Source shader_filter_invert_bgra_nomul_frag_src =
+{
+ filter_invert_bgra_nomul_frag_glsl,
+ NULL, 0
+};
+
+/////////////////////////////////////////////
+const char filter_greyscale_frag_glsl[] =
+#include "shader/filter_greyscale.h"
+ ;
+Evas_GL_Program_Source shader_filter_greyscale_frag_src =
+{
+ filter_greyscale_frag_glsl,
+ NULL, 0
+};
+
+const char filter_greyscale_nomul_frag_glsl[] =
+#include "shader/filter_greyscale_nomul.h"
+ ;
+Evas_GL_Program_Source shader_filter_greyscale_nomul_frag_src =
+{
+ filter_greyscale_nomul_frag_glsl,
+ NULL, 0
+};
+
+const char filter_greyscale_bgra_frag_glsl[] =
+#include "shader/filter_greyscale_bgra.h"
+ ;
+Evas_GL_Program_Source shader_filter_greyscale_bgra_frag_src =
+{
+ filter_greyscale_bgra_frag_glsl,
+ NULL, 0
+};
+const char filter_greyscale_bgra_nomul_frag_glsl[] =
+#include "shader/filter_greyscale_bgra_nomul.h"
+ ;
+Evas_GL_Program_Source shader_filter_greyscale_bgra_nomul_frag_src =
+{
+ filter_greyscale_bgra_nomul_frag_glsl,
+ NULL, 0
+};
+
+/////////////////////////////////////////////
+const char filter_sepia_frag_glsl[] =
+#include "shader/filter_sepia.h"
+ ;
+Evas_GL_Program_Source shader_filter_sepia_frag_src =
+{
+ filter_sepia_frag_glsl,
+ NULL, 0
+};
+
+const char filter_sepia_nomul_frag_glsl[] =
+#include "shader/filter_sepia_nomul.h"
+ ;
+Evas_GL_Program_Source shader_filter_sepia_nomul_frag_src =
+{
+ filter_sepia_nomul_frag_glsl,
+ NULL, 0
+};
+
+const char filter_sepia_bgra_frag_glsl[] =
+#include "shader/filter_sepia_bgra.h"
+ ;
+Evas_GL_Program_Source shader_filter_sepia_bgra_frag_src =
+{
+ filter_sepia_bgra_frag_glsl,
+ NULL, 0
+};
+const char filter_sepia_bgra_nomul_frag_glsl[] =
+#include "shader/filter_sepia_bgra_nomul.h"
+ ;
+Evas_GL_Program_Source shader_filter_sepia_bgra_nomul_frag_src =
+{
+ filter_sepia_bgra_nomul_frag_glsl,
+ NULL, 0
+};
+
+/////////////////////////////////////////////
+#if 0
+ Blur is a work in progress currently.
+ Mostly because GPUs are so hopeless.
+const char filter_blur_vert_glsl[] =
+#include "shader/filter_blur_vert.h"
+ ;
+
+Evas_GL_Program_Source shader_filter_blur_vert_src =
+{
+ filter_blur_vert_glsl,
+ NULL, 0
+};
+
+const char filter_blur_frag_glsl[] =
+#include "shader/filter_blur.h"
+ ;
+Evas_GL_Program_Source shader_filter_blur_frag_src =
+{
+ filter_blur_frag_glsl,
+ NULL, 0
+};
+
+const char filter_blur_nomul_frag_glsl[] =
+#include "shader/filter_blur_nomul.h"
+ ;
+Evas_GL_Program_Source shader_filter_blur_nomul_frag_src =
+{
+ filter_blur_nomul_frag_glsl,
+ NULL, 0
+};
+
+const char filter_blur_bgra_frag_glsl[] =
+#include "shader/filter_blur_bgra.h"
+ ;
+Evas_GL_Program_Source shader_filter_blur_bgra_frag_src =
+{
+ filter_blur_bgra_frag_glsl,
+ NULL, 0
+};
+const char filter_blur_bgra_nomul_frag_glsl[] =
+#include "shader/filter_blur_bgra_nomul.h"
+ ;
+Evas_GL_Program_Source shader_filter_blur_bgra_nomul_frag_src =
+{
+ filter_blur_bgra_nomul_frag_glsl,
+ NULL, 0
+};
+
+#endif
+
+
+
+/////////////////////////////////////////////
static void
gl_compile_link_error(GLuint target, const char *action)
{
--- /dev/null
+"#ifdef GL_ES\n"
+"precision mediump float;\n"
+"#endif\n"
+"uniform sampler2D tex;\n"
+"uniform sampler1D gaussian;\n"
+"varying vec4 col;\n"
+"varying vec2 tex_c;\n"
+"varying weight;\n"
+"uniform radius;\n"
+"void main()\n"
+"{\n"
+" int i;\n"
+" vec4 fc = vec4(0,0,0,0);\n"
+" \n"
+" for (i = 0 ; i < radius ; i ++){\n"
+" fc += texture2D(tex, tex_c.xy).rgba *\n"
+" texture1D(gaussian,i/radius).aaaa;\n"
+" }\n"
+" gl_FragColor = fc / 4 * col;\n"
+"}\n"
--- /dev/null
+#ifdef GL_ES
+precision mediump float;
+#endif
+uniform sampler2D tex;
+uniform sampler1D gaussian;
+varying vec4 col;
+varying vec2 tex_c;
+varying weight;
+uniform radius;
+void main()
+{
+ int i;
+ vec4 fc = vec4(0,0,0,0);
+
+ for (i = 0 ; i < radius ; i ++){
+ fc += texture2D(tex, tex_c.xy).rgba *
+ texture1D(gaussian,i/radius).aaaa;
+ }
+ gl_FragColor = fc / 4 * col;
+}
--- /dev/null
+"#ifdef GL_ES\n"
+"precision mediump float;\n"
+"#endif\n"
+"uniform sampler2D tex;\n"
+"uniform sampler1D gaussian;\n"
+"varying vec4 col;\n"
+"varying vec2 tex_c;\n"
+"varying weight;\n"
+"uniform radius;\n"
+"void main()\n"
+"{\n"
+" int i;\n"
+" vec4 fc = vec4(0,0,0,0);\n"
+" \n"
+" for (i = 0 ; i < radius ; i ++){\n"
+" fc += texture2D(tex, tex_c.xy).rgba *\n"
+" texture1D(gaussian,i/radius).aaaa;\n"
+" }\n"
+" gl_FragColor = fc / 4;\n"
+"}\n"
--- /dev/null
+#ifdef GL_ES
+precision mediump float;
+#endif
+uniform sampler2D tex;
+uniform sampler1D gaussian;
+varying vec4 col;
+varying vec2 tex_c;
+varying weight;
+uniform radius;
+void main()
+{
+ int i;
+ vec4 fc = vec4(0,0,0,0);
+
+ for (i = 0 ; i < radius ; i ++){
+ fc += texture2D(tex, tex_c.xy).rgba *
+ texture1D(gaussian,i/radius).aaaa;
+ }
+ gl_FragColor = fc / 4;
+}
--- /dev/null
+"#ifdef GL_ES\n"
+"precision mediump float;\n"
+"#endif\n"
+"uniform sampler2D tex;\n"
+"uniform sampler1D gaussian;\n"
+"varying vec4 col;\n"
+"varying vec2 tex_c;\n"
+"varying weight;\n"
+"uniform radius;\n"
+"void main()\n"
+"{\n"
+" int i;\n"
+" vec4 fc = vec4(0,0,0,0);\n"
+" \n"
+" for (i = 0 ; i < radius ; i ++){\n"
+" fc += texture2D(tex, tex_c.xy).rgba *\n"
+" texture1D(gaussian,i/radius).aaaa;\n"
+" }\n"
+" gl_FragColor = fc / 4;\n"
+"}\n"
--- /dev/null
+#ifdef GL_ES
+precision mediump float;
+#endif
+uniform sampler2D tex;
+uniform sampler1D gaussian;
+varying vec4 col;
+varying vec2 tex_c;
+varying weight;
+uniform radius;
+void main()
+{
+ int i;
+ vec4 fc = vec4(0,0,0,0);
+
+ for (i = 0 ; i < radius ; i ++){
+ fc += texture2D(tex, tex_c.xy).rgba *
+ texture1D(gaussian,i/radius).aaaa;
+ }
+ gl_FragColor = fc / 4;
+}
--- /dev/null
+"#ifdef GL_ES\n"
+"precision mediump float;\n"
+"#endif\n"
+"uniform sampler2D tex;\n"
+"uniform sampler1D gaussian;\n"
+"varying vec4 col;\n"
+"varying vec2 tex_c;\n"
+"varying weight;\n"
+"uniform radius;\n"
+"void main()\n"
+"{\n"
+" int i;\n"
+" vec4 fc = vec4(0,0,0,0);\n"
+" \n"
+" for (i = 0 ; i < radius ; i ++){\n"
+" fc += texture2D(tex, tex_c.xy).rgba *\n"
+" texture1D(gaussian,i/radius).aaaa;\n"
+" }\n"
+" gl_FragColor = fc / 4;\n"
+"}\n"
--- /dev/null
+#ifdef GL_ES
+precision mediump float;
+#endif
+uniform sampler2D tex;
+uniform sampler1D gaussian;
+varying vec4 col;
+varying vec2 tex_c;
+varying weight;
+uniform radius;
+void main()
+{
+ int i;
+ vec4 fc = vec4(0,0,0,0);
+
+ for (i = 0 ; i < radius ; i ++){
+ fc += texture2D(tex, tex_c.xy).rgba *
+ texture1D(gaussian,i/radius).aaaa;
+ }
+ gl_FragColor = fc / 4;
+}
--- /dev/null
+"#ifdef GL_ES\n"
+"precision mediump float;\n"
+"#endif\n"
+"attribute vec4 vertex;\n"
+"attribute vec4 color;\n"
+"attribute vec2 tex_coord;\n"
+"attribute float r;\n"
+"uniform mat4 mvp;\n"
+"uniform sampler1D tex_blur;\n"
+"varying float weight;\n"
+"varying vec4 col;\n"
+"varying vec2 tex_c;\n"
+"\n"
+"void main(){\n"
+" /* FIXME: This index shoudl be tweaked so for \n"
+" radius 1, I want 3 points at 1/4, 2/4, 3/4 */\n"
+" /*\n"
+" for (float i = 0 ; i <= radius * 2 ; i ++){\n"
+" float pos = i;\n"
+" float r = float(radius);\n"
+" weight += sampler1D(tex_blur, 1.0 / (r * 2.0 * pos));\n"
+" }*/\n"
+" for (float i = 0.0 ; i < r * 2.0 ; i += 1.0){\n"
+" weight += sampler1D(tex_blur, 1.0 / (r * 2.0 * i));\n"
+" }\n"
+" gl_Position = mvp * vertex;\n"
+" col = color;\n"
+" tex_c = tex_coord;\n"
+"}\n"
--- /dev/null
+#ifdef GL_ES
+precision mediump float;
+#endif
+attribute vec4 vertex;
+attribute vec4 color;
+attribute vec2 tex_coord;
+attribute float r;
+uniform mat4 mvp;
+uniform sampler1D tex_blur;
+varying float weight;
+varying vec4 col;
+varying vec2 tex_c;
+
+void main(){
+ /* FIXME: This index shoudl be tweaked so for
+ radius 1, I want 3 points at 1/4, 2/4, 3/4 */
+ /*
+ for (float i = 0 ; i <= radius * 2 ; i ++){
+ float pos = i;
+ float r = float(radius);
+ weight += sampler1D(tex_blur, 1.0 / (r * 2.0 * pos));
+ }*/
+ for (float i = 0.0 ; i < r * 2.0 ; i += 1.0){
+ weight += sampler1D(tex_blur, 1.0 / (r * 2.0 * i));
+ }
+ gl_Position = mvp * vertex;
+ col = color;
+ tex_c = tex_coord;
+}
return &(n->ns);
}
+static void
+eng_image_draw_filtered(void *data, void *context, void *surface,
+ void *image, Evas_Filter_Info *filter)
+{
+ Render_Engine *re = data;
+
+ if (!image) return;
+ eng_window_use(re->win);
+ evas_gl_common_context_target_surface_set(re->win->gl_context, surface);
+ re->win->gl_context->dc = context;
+
+ evas_gl_common_filter_draw(data, re->win->gl_context, image, filter);
+}
+
+static Filtered_Image *
+eng_image_filtered_get(void *im, uint8_t *key, size_t keylen)
+{
+ return evas_gl_common_image_filtered_get(im, key, keylen);
+}
+
+static Filtered_Image *
+eng_image_filtered_save(void *im, void *fim, uint8_t *key, size_t keylen)
+{
+ return evas_gl_common_image_filtered_save(im, fim, key, keylen);
+}
+
+static void
+eng_image_filtered_free(void *im, Filtered_Image *fim)
+{
+ evas_gl_common_image_filtered_free(im, fim);
+}
+
+
+
//
//
/////////////////////////////////////////////////////////////////////////
ORD(image_mask_create);
ORD(image_native_set);
ORD(image_native_get);
+ ORD(image_draw_filtered);
+ ORD(image_filtered_get);
+ ORD(image_filtered_save);
+ ORD(image_filtered_free);
ORD(font_draw);
return EINA_TRUE;
}
+
+/* Filter API */
+static void
+eng_image_draw_filtered(void *data, void *context, void *surface,
+ void *image, Evas_Filter_Info *filter)
+{
+ Evas_Software_Filter_Fn fn;
+ RGBA_Image *im = image;
+
+ fn = evas_filter_software_get(filter);
+ if (!fn) return;
+ if (im->cache_entry.cache) evas_cache_image_load_data(&im->cache_entry);
+ fn(filter, image, surface);
+
+ return;
+}
+
+static Filtered_Image *
+eng_image_filtered_get(void *image, uint8_t *key, size_t keylen)
+{
+ RGBA_Image *im = image;
+ Filtered_Image *fi;
+ Eina_List *l;
+
+ for (l = im->filtered ; l ; l = l->next)
+ {
+ fi = l->data;
+ if (fi->keylen != keylen) continue;
+ if (memcmp(key, fi->key, keylen) != 0) continue;
+ fi->ref ++;
+ return fi;
+ }
+
+ return NULL;
+}
+
+static Filtered_Image *
+eng_image_filtered_save(void *image, void *fimage, uint8_t *key, size_t keylen)
+{
+ RGBA_Image *im = image;
+ Filtered_Image *fi;
+ Eina_List *l;
+
+ for (l = im->filtered ; l ; l = l->next)
+ {
+ fi = l->data;
+ if (fi->keylen != keylen) continue;
+ if (memcmp(key, fi->key, keylen) == 0) continue;
+ evas_cache_image_drop((void *)fi->image);
+ fi->image = fimage;
+ return fi;
+ }
+
+ fi = calloc(1,sizeof(Filtered_Image));
+ if (!fi) return NULL;
+
+ fi->keylen = keylen;
+ fi->key = malloc(keylen);
+ memcpy(fi->key, key, keylen);
+ fi->image = fimage;
+ fi->ref = 1;
+
+ im->filtered = eina_list_prepend(im->filtered, fi);
+
+ return fi;
+}
+
+static void
+eng_image_filtered_free(void *image, Filtered_Image *fi)
+{
+ RGBA_Image *im = image;
+
+ fi->ref --;
+ if (fi->ref) return;
+
+ free(fi->key);
+ evas_cache_image_drop(&fi->image->cache_entry);
+ fi->image = NULL;
+
+ im->filtered = eina_list_remove(im->filtered, fi);
+}
+
/*
*****
**
eng_font_pen_coords_get,
eng_font_text_props_info_create,
eng_font_right_inset_get,
+ eng_image_draw_filtered,
+ eng_image_filtered_get,
+ eng_image_filtered_save,
+ eng_image_filtered_free,
NULL, // FIXME: need software mesa for gl rendering <- gl_surface_create
NULL, // FIXME: need software mesa for gl rendering <- gl_surface_destroy
NULL, // FIXME: need software mesa for gl rendering <- gl_context_create