Evas masking: Font masking for GL
authorJean-Philippe Andre <jp.andre@samsung.com>
Tue, 25 Nov 2014 05:34:42 +0000 (14:34 +0900)
committerJean-Philippe Andre <jp.andre@samsung.com>
Wed, 7 Jan 2015 06:06:03 +0000 (15:06 +0900)
src/Makefile_Evas.am
src/modules/evas/engines/gl_common/evas_gl_common.h
src/modules/evas/engines/gl_common/evas_gl_context.c
src/modules/evas/engines/gl_common/evas_gl_font.c
src/modules/evas/engines/gl_common/shader/evas_gl_enum.x
src/modules/evas/engines/gl_common/shader/evas_gl_shaders.x
src/modules/evas/engines/gl_common/shader/font_mask_frag.shd [new file with mode: 0644]
src/modules/evas/engines/gl_common/shader/font_mask_vert.shd [new file with mode: 0644]
src/modules/evas/engines/gl_generic/evas_engine.c

index 6208b66..a2f7431 100644 (file)
@@ -599,6 +599,8 @@ modules/evas/engines/gl_common/evas_gl_3d_shader.c
 GL_SHADERS_GEN = \
 modules/evas/engines/gl_common/shader/font_frag.shd \
 modules/evas/engines/gl_common/shader/font_vert.shd \
+modules/evas/engines/gl_common/shader/font_mask_frag.shd \
+modules/evas/engines/gl_common/shader/font_mask_vert.shd \
 modules/evas/engines/gl_common/shader/img_12_bgra_frag.shd \
 modules/evas/engines/gl_common/shader/img_12_bgra_nomul_frag.shd \
 modules/evas/engines/gl_common/shader/img_12_bgra_nomul_vert.shd \
index eda2b8b..c314e4d 100644 (file)
@@ -729,6 +729,13 @@ void              evas_gl_common_context_font_push(Evas_Engine_GL_Context *gc,
                                                    double sx, double sy, double sw, double sh,
                                                    int x, int y, int w, int h,
                                                    int r, int g, int b, int a);
+void              evas_gl_common_context_masked_font_push(Evas_Engine_GL_Context *gc,
+                                                          Evas_GL_Texture *tex,
+                                                          double sx, double sy, double sw, double sh,
+                                                          int x, int y, int w, int h,
+                                                          int r, int g, int b, int a,
+                                                          Evas_GL_Texture *texa,
+                                                          int mx, int my, int mw, int mh);
 void             evas_gl_common_context_yuv_push(Evas_Engine_GL_Context *gc,
                                                  Evas_GL_Texture *tex,
                                                  double sx, double sy, double sw, double sh,
index 08ccbb6..abe448e 100644 (file)
@@ -856,6 +856,9 @@ evas_gl_common_context_new(void)
         SHADER_TEXTURE_ADD(shared, IMG_MASK_NOMUL, tex);
         SHADER_TEXTURE_ADD(shared, IMG_MASK_NOMUL, texa);
 
+        SHADER_TEXTURE_ADD(shared, FONT_MASK, tex);
+        SHADER_TEXTURE_ADD(shared, FONT_MASK, texa);
+
         if (gc->state.current.cur_prog == PRG_INVALID)
            glUseProgram(shared->shader[0].prog);
         else glUseProgram(gc->state.current.cur_prog);
@@ -1900,6 +1903,106 @@ evas_gl_common_context_image_push(Evas_Engine_GL_Context *gc,
 }
 
 void
+evas_gl_common_context_masked_font_push(Evas_Engine_GL_Context *gc,
+                                        Evas_GL_Texture *tex,
+                                        double sx, double sy, double sw, double sh,
+                                        int x, int y, int w, int h,
+                                        int r, int g, int b, int a,
+                                        Evas_GL_Texture *texa,
+                                        int mx, int my, int mw, int mh)
+{
+   int pnum, nv, nc, nu, na, i;
+   GLfloat tx1, tx2, ty1, ty2, t2x1, t2x2, t2y1, t2y2;
+   GLuint prog = gc->shared->shader[SHADER_FONT_MASK].prog;
+   int pn = 0;
+
+   pn = _evas_gl_common_context_push(RTYPE_FONT,
+                                     gc, tex,
+                                     prog,
+                                     x, y, w, h,
+                                     1,
+                                     0,
+                                     0, 0, 0, 0, 0);
+
+   gc->pipe[pn].region.type = RTYPE_FONT;
+   gc->pipe[pn].shader.cur_tex = tex->pt->texture;
+   gc->pipe[pn].shader.cur_texa = texa->pt->texture;
+   gc->pipe[pn].shader.cur_prog = prog;
+   gc->pipe[pn].shader.smooth = 0;
+   gc->pipe[pn].shader.blend = 1;
+   gc->pipe[pn].shader.render_op = gc->dc->render_op;
+   gc->pipe[pn].shader.clip = 0;
+   gc->pipe[pn].shader.cx = 0;
+   gc->pipe[pn].shader.cy = 0;
+   gc->pipe[pn].shader.cw = 0;
+   gc->pipe[pn].shader.ch = 0;
+   gc->pipe[pn].array.line = 0;
+   gc->pipe[pn].array.use_vertex = 1;
+   gc->pipe[pn].array.use_color = 1;
+   gc->pipe[pn].array.use_texuv = 1;
+   gc->pipe[pn].array.use_texuv2 = 0;
+   gc->pipe[pn].array.use_texuv3 = 0;
+   gc->pipe[pn].array.use_texa = 1; //
+   gc->pipe[pn].array.use_texsam = 0;
+
+   pipe_region_expand(gc, pn, x, y, w, h);
+
+   pnum = gc->pipe[pn].array.num;
+   nv = pnum * 3; nc = pnum * 4; nu = pnum * 2; na = pnum * 2;
+   gc->pipe[pn].array.num += 6;
+   array_alloc(gc, pn);
+
+   if (sw == 0.0)
+     {
+        tx1 = tex->sx1;
+        ty1 = tex->sy1;
+        tx2 = tex->sx2;
+        ty2 = tex->sy2;
+     }
+   else
+     {
+        tx1 = ((double)(tex->x) + sx) / (double)tex->pt->w;
+        ty1 = ((double)(tex->y) + sy) / (double)tex->pt->h;
+        tx2 = ((double)(tex->x) + sx + sw) / (double)tex->pt->w;
+        ty2 = ((double)(tex->y) + sy + sh) / (double)tex->pt->h;
+     }
+
+   t2x1 = (texa->x + mx) / (double)texa->pt->w;
+   t2y1 = (texa->y + my) / (double)texa->pt->h;
+   t2x2 = (texa->x + mx + mw) / (double)texa->pt->w;
+   t2y2 = (texa->y + my + mh) / (double)texa->pt->h;
+
+   PUSH_VERTEX(pn, x    , y    , 0);
+   PUSH_VERTEX(pn, x + w, y    , 0);
+   PUSH_VERTEX(pn, x    , y + h, 0);
+
+   PUSH_TEXUV(pn, tx1, ty1);
+   PUSH_TEXUV(pn, tx2, ty1);
+   PUSH_TEXUV(pn, tx1, ty2);
+
+   PUSH_TEXA(pn, t2x1, t2y1);
+   PUSH_TEXA(pn, t2x2, t2y1);
+   PUSH_TEXA(pn, t2x1, t2y2);
+
+   PUSH_VERTEX(pn, x + w, y    , 0);
+   PUSH_VERTEX(pn, x + w, y + h, 0);
+   PUSH_VERTEX(pn, x    , y + h, 0);
+
+   PUSH_TEXUV(pn, tx2, ty1);
+   PUSH_TEXUV(pn, tx2, ty2);
+   PUSH_TEXUV(pn, tx1, ty2);
+
+   PUSH_TEXA(pn, t2x2, t2y1);
+   PUSH_TEXA(pn, t2x2, t2y2);
+   PUSH_TEXA(pn, t2x1, t2y2);
+
+   for (i = 0; i < 6; i++)
+     {
+        PUSH_COLOR(pn, r, g, b, a);
+     }
+}
+
+void
 evas_gl_common_context_font_push(Evas_Engine_GL_Context *gc,
                                  Evas_GL_Texture *tex,
                                  double sx, double sy, double sw, double sh,
index 33c1f58..b7663a2 100644 (file)
@@ -68,6 +68,7 @@ evas_gl_font_texture_draw(void *context, void *surface EINA_UNUSED, void *draw_c
    int c, cx, cy, cw, ch;
    int i;
    int sx, sy, sw, sh;
+   double mx, my, mw, mh, mmx, mmy, mmw, mmh;
 
    if (dc != gc->dc) return;
    tex = fg->ext_dat;
@@ -78,6 +79,42 @@ evas_gl_font_texture_draw(void *context, void *surface EINA_UNUSED, void *draw_c
    g = (dc->col.col >> 8 ) & 0xff;
    b = (dc->col.col      ) & 0xff;
    sx = 0; sy = 0; sw = tex->w, sh = tex->h;
+
+   if (gc->dc->clip.mask && (sw > 0) && (sh > 0))
+     {
+        // FIXME: This code path does not handle half the stuff the other path does...
+        Evas_GL_Image *mask = gc->dc->clip.mask;
+        int nx, ny, nw, nh, dx, dy, dw, dh;
+
+        nx = x; ny = y; nw = tex->w; nh = tex->h;
+        RECTS_CLIP_TO_RECT(nx, ny, nw, nh,
+                           gc->dc->clip.x, gc->dc->clip.y,
+                           gc->dc->clip.w, gc->dc->clip.h);
+        if ((nw < 1) || (nh < 1)) return;
+
+        ssx = (double)sx + ((double)(sw * (nx - x)) / (double)(tex->w));
+        ssy = (double)sy + ((double)(sh * (ny - y)) / (double)(tex->h));
+        ssw = ((double)sw * (double)(nw)) / (double)(tex->w);
+        ssh = ((double)sh * (double)(nh)) / (double)(tex->h);
+
+        dx = x; dy = y; dw = sw; dh = sh;
+        mx = gc->dc->clip.mask_x; my = gc->dc->clip.mask_y; mw = mask->w; mh = mask->h;
+        //RECTS_CLIP_TO_RECT(mx, my, mw, mh, cx, cy, cw, ch);
+        RECTS_CLIP_TO_RECT(mx, my, mw, mh, dx, dy, dw, dh);
+
+        mmx = (double)(mx - gc->dc->clip.mask_x) + ((double)(mw * (nx - dx)) / (double)(dw));
+        mmy = (double)(my - gc->dc->clip.mask_y) + ((double)(mh * (ny - dy)) / (double)(dh));
+        mmw = ((double)mw * (double)(nw)) / (double)(dw);
+        mmh = ((double)mh * (double)(nh)) / (double)(dh);
+
+        evas_gl_common_context_masked_font_push(gc, tex,
+                                                ssx, ssy, ssw, ssh,
+                                                nx, ny, nw, nh,
+                                                r, g, b, a,
+                                                mask->tex, mmx, mmy, mmw, mmh);
+        return;
+     }
+
    if ((!gc->dc->cutout.rects) ||
        ((gc->shared->info.tune.cutout.max > 0) &&
            (gc->dc->cutout.active > gc->shared->info.tune.cutout.max)))
index 74af14d..04614ac 100644 (file)
@@ -3,6 +3,7 @@
 
 typedef enum {
    SHADER_FONT,
+   SHADER_FONT_MASK,
    SHADER_IMG_12_BGRA_NOMUL,
    SHADER_IMG_12_BGRA,
    SHADER_IMG_12_NOMUL,
index 8ee9ea9..9916ef0 100644 (file)
@@ -48,6 +48,56 @@ Evas_GL_Program_Source shader_font_vert_src =
    NULL, 0
 };
 
+/* Source: modules/evas/engines/gl_common/shader/font_mask_frag.shd */
+static const char const font_mask_frag_glsl[] =
+   "#ifdef GL_ES\n"
+   "#ifdef GL_FRAGMENT_PRECISION_HIGH\n"
+   "precision highp float;\n"
+   "#else\n"
+   "precision mediump float;\n"
+   "#endif\n"
+   "#endif\n"
+   "uniform sampler2D tex;\n"
+   "uniform sampler2D texa;\n"
+   "varying vec4 col;\n"
+   "varying vec2 tex_c;\n"
+   "varying vec2 tex_a;\n"
+   "void main()\n"
+   "{\n"
+   "   gl_FragColor = texture2D(tex, tex_c.xy).aaaa * texture2D(texa, tex_a.xy).aaaa * col;\n"
+   "}\n";
+Evas_GL_Program_Source shader_font_mask_frag_src =
+{
+   font_mask_frag_glsl,
+   NULL, 0
+};
+
+/* Source: modules/evas/engines/gl_common/shader/font_mask_vert.shd */
+static const char const font_mask_vert_glsl[] =
+   "#ifdef GL_ES\n"
+   "precision highp float;\n"
+   "#endif\n"
+   "attribute vec4 vertex;\n"
+   "attribute vec4 color;\n"
+   "attribute vec2 tex_coord;\n"
+   "attribute vec2 tex_coorda;\n"
+   "uniform mat4 mvp;\n"
+   "varying vec4 col;\n"
+   "varying vec2 tex_c;\n"
+   "varying vec2 tex_a;\n"
+   "void main()\n"
+   "{\n"
+   "   gl_Position = mvp * vertex;\n"
+   "   col = color;\n"
+   "   tex_c = tex_coord;\n"
+   "   tex_a = tex_coorda;\n"
+   "}\n";
+Evas_GL_Program_Source shader_font_mask_vert_src =
+{
+   font_mask_vert_glsl,
+   NULL, 0
+};
+
 /* Source: modules/evas/engines/gl_common/shader/img_12_bgra_frag.shd */
 static const char const img_12_bgra_frag_glsl[] =
    "#ifdef GL_ES\n"
@@ -2182,7 +2232,7 @@ Evas_GL_Program_Source shader_yuy2_vert_src =
 };
 
 /* Source: modules/evas/engines/gl_common/shader/img_mask_frag.shd */
-static const char img_mask_frag_glsl[] =
+static const char const img_mask_frag_glsl[] =
    "#ifdef GL_ES\n"
    "#ifdef GL_FRAGMENT_PRECISION_HIGH\n"
    "precision highp float;\n"
@@ -2207,7 +2257,7 @@ Evas_GL_Program_Source shader_img_mask_frag_src =
 };
 
 /* Source: modules/evas/engines/gl_common/shader/img_mask_vert.shd */
-static const char img_mask_vert_glsl[] =
+static const char const img_mask_vert_glsl[] =
    "#ifdef GL_ES\n"
    "precision highp float;\n"
    "#endif\n"
@@ -2233,7 +2283,7 @@ Evas_GL_Program_Source shader_img_mask_vert_src =
 };
 
 /* Source: modules/evas/engines/gl_common/shader/img_mask_nomul_frag.shd */
-static const char img_mask_nomul_frag_glsl[] =
+static const char const img_mask_nomul_frag_glsl[] =
    "#ifdef GL_ES\n"
    "#ifdef GL_FRAGMENT_PRECISION_HIGH\n"
    "precision highp float;\n"
@@ -2257,7 +2307,7 @@ Evas_GL_Program_Source shader_img_mask_nomul_frag_src =
 };
 
 /* Source: modules/evas/engines/gl_common/shader/img_mask_nomul_vert.shd */
-static const char img_mask_nomul_vert_glsl[] =
+static const char const img_mask_nomul_vert_glsl[] =
    "#ifdef GL_ES\n"
    "precision highp float;\n"
    "#endif\n"
@@ -2286,6 +2336,7 @@ static const struct {
    const char *name;
 } _shaders_source[] = {
    { SHADER_FONT, &(shader_font_vert_src), &(shader_font_frag_src), "font" },
+   { SHADER_FONT_MASK, &(shader_font_mask_vert_src), &(shader_font_mask_frag_src), "font_mask" },
    { SHADER_IMG_12_BGRA_NOMUL, &(shader_img_12_bgra_nomul_vert_src), &(shader_img_12_bgra_nomul_frag_src), "img_12_bgra_nomul" },
    { SHADER_IMG_12_BGRA, &(shader_img_12_bgra_vert_src), &(shader_img_12_bgra_frag_src), "img_12_bgra" },
    { SHADER_IMG_12_NOMUL, &(shader_img_12_nomul_vert_src), &(shader_img_12_nomul_frag_src), "img_12_nomul" },
diff --git a/src/modules/evas/engines/gl_common/shader/font_mask_frag.shd b/src/modules/evas/engines/gl_common/shader/font_mask_frag.shd
new file mode 100644 (file)
index 0000000..950431e
--- /dev/null
@@ -0,0 +1,17 @@
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#endif
+uniform sampler2D tex;
+uniform sampler2D texa;
+varying vec4 col;
+varying vec2 tex_c;
+varying vec2 tex_a;
+void main()
+{
+   gl_FragColor = texture2D(tex, tex_c.xy).aaaa * texture2D(texa, tex_a.xy).aaaa * col;
+}
+
diff --git a/src/modules/evas/engines/gl_common/shader/font_mask_vert.shd b/src/modules/evas/engines/gl_common/shader/font_mask_vert.shd
new file mode 100644 (file)
index 0000000..3b5ea74
--- /dev/null
@@ -0,0 +1,19 @@
+#ifdef GL_ES
+precision highp float;
+#endif
+attribute vec4 vertex;
+attribute vec4 color;
+attribute vec2 tex_coord;
+attribute vec2 tex_coorda;
+uniform mat4 mvp;
+varying vec4 col;
+varying vec2 tex_c;
+varying vec2 tex_a;
+void main()
+{
+   gl_Position = mvp * vertex;
+   col = color;
+   tex_c = tex_coord;
+   tex_a = tex_coorda;
+}
+
index 45d35ea..ed628e4 100644 (file)
@@ -1696,6 +1696,60 @@ eng_context_flush(void *data)
 }
 
 static void
+eng_context_clip_image_unset(void *data EINA_UNUSED, void *context)
+{
+   RGBA_Draw_Context *ctx = context;
+   Evas_GL_Image *im = ctx->clip.mask;
+
+   if (im && im->im)
+     {
+#ifdef EVAS_CSERVE2
+        if (evas_cserve2_use_get())
+          evas_cache2_image_close(&im->im->cache_entry);
+        else
+#endif
+          evas_cache_image_drop(&im->im->cache_entry);
+        // Is the above code safe? Hmmm...
+        //evas_unref_queue_image_put(EVAS???, &ctx->clip.ie->cache_entry);
+     }
+   ctx->clip.mask = NULL;
+}
+
+static void
+eng_context_clip_image_set(void *data EINA_UNUSED, void *context, void *surface, int x, int y)
+{
+   RGBA_Draw_Context *ctx = context;
+   Evas_GL_Image *im = surface;
+
+   if (ctx->clip.mask && ctx->clip.mask != surface)
+     eng_context_clip_image_unset(data, context);
+
+   ctx->clip.mask = surface;
+   ctx->clip.mask_x = x;
+   ctx->clip.mask_y = y;
+
+   if (im && im->im)
+     {
+#ifdef EVAS_CSERVE2
+        if (evas_cserve2_use_get())
+          evas_cache2_image_ref(&im->im->cache_entry);
+        else
+#endif
+          evas_cache_image_ref(&im->im->cache_entry);
+     }
+}
+
+static void
+eng_context_clip_image_get(void *data EINA_UNUSED, void *context, void **ie, int *x, int *y)
+{
+   RGBA_Draw_Context *ctx = context;
+
+   if (ie) *ie = ctx->clip.mask;
+   if (x) *x = ctx->clip.mask_x;
+   if (y) *y = ctx->clip.mask_y;
+}
+
+static void
 eng_context_3d_use(void *data)
 {
    Render_Engine_GL_Generic *re = data;
@@ -1885,6 +1939,10 @@ module_open(Evas_Module *em)
    func = pfunc;
    /* now to override methods */
 #define ORD(f) EVAS_API_OVERRIDE(f, &func, eng_)
+   ORD(context_clip_image_set);
+   ORD(context_clip_image_unset);
+   ORD(context_clip_image_get);
+
    ORD(rectangle_draw);
    ORD(line_draw);
    ORD(polygon_point_add);