From 1fac1dcf5730981fe4054efffdea05b18c3fb17e Mon Sep 17 00:00:00 2001 From: Jean-Philippe Andre Date: Tue, 25 Nov 2014 14:34:42 +0900 Subject: [PATCH] Evas masking: Font masking for GL --- src/Makefile_Evas.am | 2 + .../evas/engines/gl_common/evas_gl_common.h | 7 ++ .../evas/engines/gl_common/evas_gl_context.c | 103 ++++++++++++++++++ .../evas/engines/gl_common/evas_gl_font.c | 37 +++++++ .../engines/gl_common/shader/evas_gl_enum.x | 1 + .../gl_common/shader/evas_gl_shaders.x | 59 +++++++++- .../gl_common/shader/font_mask_frag.shd | 17 +++ .../gl_common/shader/font_mask_vert.shd | 19 ++++ .../evas/engines/gl_generic/evas_engine.c | 58 ++++++++++ 9 files changed, 299 insertions(+), 4 deletions(-) create mode 100644 src/modules/evas/engines/gl_common/shader/font_mask_frag.shd create mode 100644 src/modules/evas/engines/gl_common/shader/font_mask_vert.shd diff --git a/src/Makefile_Evas.am b/src/Makefile_Evas.am index 6208b66db8..a2f7431701 100644 --- a/src/Makefile_Evas.am +++ b/src/Makefile_Evas.am @@ -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 \ diff --git a/src/modules/evas/engines/gl_common/evas_gl_common.h b/src/modules/evas/engines/gl_common/evas_gl_common.h index eda2b8bc98..c314e4d88e 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_common.h +++ b/src/modules/evas/engines/gl_common/evas_gl_common.h @@ -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, diff --git a/src/modules/evas/engines/gl_common/evas_gl_context.c b/src/modules/evas/engines/gl_common/evas_gl_context.c index 08ccbb6ec9..abe448e21b 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_context.c +++ b/src/modules/evas/engines/gl_common/evas_gl_context.c @@ -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); @@ -1899,6 +1902,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, diff --git a/src/modules/evas/engines/gl_common/evas_gl_font.c b/src/modules/evas/engines/gl_common/evas_gl_font.c index 33c1f58561..b7663a2b44 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_font.c +++ b/src/modules/evas/engines/gl_common/evas_gl_font.c @@ -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))) diff --git a/src/modules/evas/engines/gl_common/shader/evas_gl_enum.x b/src/modules/evas/engines/gl_common/shader/evas_gl_enum.x index 74af14d6d9..04614ac134 100644 --- a/src/modules/evas/engines/gl_common/shader/evas_gl_enum.x +++ b/src/modules/evas/engines/gl_common/shader/evas_gl_enum.x @@ -3,6 +3,7 @@ typedef enum { SHADER_FONT, + SHADER_FONT_MASK, SHADER_IMG_12_BGRA_NOMUL, SHADER_IMG_12_BGRA, SHADER_IMG_12_NOMUL, diff --git a/src/modules/evas/engines/gl_common/shader/evas_gl_shaders.x b/src/modules/evas/engines/gl_common/shader/evas_gl_shaders.x index 8ee9ea920f..9916ef0f0f 100644 --- a/src/modules/evas/engines/gl_common/shader/evas_gl_shaders.x +++ b/src/modules/evas/engines/gl_common/shader/evas_gl_shaders.x @@ -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 index 0000000000..950431e8c5 --- /dev/null +++ b/src/modules/evas/engines/gl_common/shader/font_mask_frag.shd @@ -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 index 0000000000..3b5ea7430d --- /dev/null +++ b/src/modules/evas/engines/gl_common/shader/font_mask_vert.shd @@ -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; +} + diff --git a/src/modules/evas/engines/gl_generic/evas_engine.c b/src/modules/evas/engines/gl_generic/evas_engine.c index 45d35ea587..ed628e40d9 100644 --- a/src/modules/evas/engines/gl_generic/evas_engine.c +++ b/src/modules/evas/engines/gl_generic/evas_engine.c @@ -1695,6 +1695,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) { @@ -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);