forked from AuroraMiddleware/gtk
gl renderer: Add simple blend node implementation
This commit is contained in:
parent
1e16cb088a
commit
c848b9014b
@ -326,6 +326,7 @@ struct _GskGLRenderer
|
||||
Program unblurred_outset_shadow_program;
|
||||
Program border_program;
|
||||
Program cross_fade_program;
|
||||
Program blend_program;
|
||||
};
|
||||
};
|
||||
|
||||
@ -1900,6 +1901,54 @@ render_cross_fade_node (GskGLRenderer *self,
|
||||
ops_draw (builder, vertex_data);
|
||||
}
|
||||
|
||||
static inline void
|
||||
render_blend_node (GskGLRenderer *self,
|
||||
GskRenderNode *node,
|
||||
RenderOpBuilder *builder)
|
||||
{
|
||||
GskRenderNode *top_child = gsk_blend_node_get_top_child (node);
|
||||
GskRenderNode *bottom_child = gsk_blend_node_get_bottom_child (node);
|
||||
const float min_x = builder->dx + node->bounds.origin.x;
|
||||
const float min_y = builder->dy + node->bounds.origin.y;
|
||||
const float max_x = min_x + node->bounds.size.width;
|
||||
const float max_y = min_y + node->bounds.size.height;
|
||||
int top_texture_id;
|
||||
int bottom_texture_id;
|
||||
gboolean is_offscreen1, is_offscreen2;
|
||||
RenderOp op;
|
||||
const GskQuadVertex vertex_data[GL_N_VERTICES] = {
|
||||
{ { min_x, min_y }, { 0, 1 }, },
|
||||
{ { min_x, max_y }, { 0, 0 }, },
|
||||
{ { max_x, min_y }, { 1, 1 }, },
|
||||
|
||||
{ { max_x, max_y }, { 1, 0 }, },
|
||||
{ { min_x, max_y }, { 0, 0 }, },
|
||||
{ { max_x, min_y }, { 1, 1 }, },
|
||||
};
|
||||
|
||||
/* TODO: We create 2 textures here as big as the blend node, but both the
|
||||
* start and the end node might be a lot smaller than that. */
|
||||
add_offscreen_ops (self, builder,
|
||||
&node->bounds,
|
||||
bottom_child,
|
||||
&bottom_texture_id, &is_offscreen1,
|
||||
FORCE_OFFSCREEN | RESET_CLIP);
|
||||
|
||||
add_offscreen_ops (self, builder,
|
||||
&node->bounds,
|
||||
top_child,
|
||||
&top_texture_id, &is_offscreen2,
|
||||
FORCE_OFFSCREEN | RESET_CLIP);
|
||||
|
||||
ops_set_program (builder, &self->blend_program);
|
||||
ops_set_texture (builder, bottom_texture_id);
|
||||
op.op = OP_CHANGE_BLEND;
|
||||
op.blend.source2 = top_texture_id;
|
||||
op.blend.mode = gsk_blend_node_get_blend_mode (node);
|
||||
ops_add (builder, &op);
|
||||
ops_draw (builder, vertex_data);
|
||||
}
|
||||
|
||||
static inline void
|
||||
apply_viewport_op (const Program *program,
|
||||
const RenderOp *op)
|
||||
@ -2174,6 +2223,18 @@ apply_cross_fade_op (const Program *program,
|
||||
glUniform1f (program->cross_fade.progress_location, op->cross_fade.progress);
|
||||
}
|
||||
|
||||
static inline void
|
||||
apply_blend_op (const Program *program,
|
||||
const RenderOp *op)
|
||||
{
|
||||
/* End texture id */
|
||||
glUniform1i (program->blend.source2_location, 1);
|
||||
glActiveTexture (GL_TEXTURE0 + 1);
|
||||
glBindTexture (GL_TEXTURE_2D, op->blend.source2);
|
||||
/* progress */
|
||||
glUniform1i (program->blend.mode_location, op->blend.mode);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_renderer_dispose (GObject *gobject)
|
||||
{
|
||||
@ -2206,6 +2267,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
|
||||
{ "unblurred outset shadow", "unblurred_outset_shadow.fs.glsl" },
|
||||
{ "border", "border.fs.glsl" },
|
||||
{ "cross fade", "cross_fade.fs.glsl" },
|
||||
{ "blend", "blend.fs.glsl" },
|
||||
};
|
||||
|
||||
builder = gsk_shader_builder_new ();
|
||||
@ -2336,6 +2398,10 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
|
||||
INIT_PROGRAM_UNIFORM_LOCATION (cross_fade, progress);
|
||||
INIT_PROGRAM_UNIFORM_LOCATION (cross_fade, source2);
|
||||
|
||||
/* blend */
|
||||
INIT_PROGRAM_UNIFORM_LOCATION (blend, source2);
|
||||
INIT_PROGRAM_UNIFORM_LOCATION (blend, mode);
|
||||
|
||||
g_object_unref (builder);
|
||||
return TRUE;
|
||||
}
|
||||
@ -2588,8 +2654,11 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
|
||||
render_cross_fade_node (self, node, builder);
|
||||
break;
|
||||
|
||||
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
|
||||
case GSK_BLEND_NODE:
|
||||
render_blend_node (self, node, builder);
|
||||
break;
|
||||
|
||||
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
|
||||
case GSK_REPEAT_NODE:
|
||||
case GSK_CAIRO_NODE:
|
||||
default:
|
||||
@ -2855,6 +2924,11 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self,
|
||||
apply_cross_fade_op (program, op);
|
||||
break;
|
||||
|
||||
case OP_CHANGE_BLEND:
|
||||
g_assert (program == &self->blend_program);
|
||||
apply_blend_op (program, op);
|
||||
break;
|
||||
|
||||
case OP_CHANGE_LINEAR_GRADIENT:
|
||||
apply_linear_gradient_op (program, op);
|
||||
break;
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "gskrendernodeprivate.h"
|
||||
|
||||
#define GL_N_VERTICES 6
|
||||
#define GL_N_PROGRAMS 11
|
||||
#define GL_N_PROGRAMS 12
|
||||
|
||||
|
||||
|
||||
@ -61,6 +61,7 @@ enum {
|
||||
OP_DUMP_FRAMEBUFFER = 23,
|
||||
OP_PUSH_DEBUG_GROUP = 24,
|
||||
OP_POP_DEBUG_GROUP = 25,
|
||||
OP_CHANGE_BLEND = 26,
|
||||
};
|
||||
|
||||
typedef struct
|
||||
@ -136,6 +137,10 @@ typedef struct
|
||||
int source2_location;
|
||||
int progress_location;
|
||||
} cross_fade;
|
||||
struct {
|
||||
int source2_location;
|
||||
int mode_location;
|
||||
} blend;
|
||||
};
|
||||
|
||||
} Program;
|
||||
@ -214,6 +219,10 @@ typedef struct
|
||||
float progress;
|
||||
int source2;
|
||||
} cross_fade;
|
||||
struct {
|
||||
int source2;
|
||||
int mode;
|
||||
} blend;
|
||||
struct {
|
||||
char *filename;
|
||||
int width;
|
||||
|
@ -11,6 +11,7 @@ gsk_private_gl_shaders = [
|
||||
'resources/glsl/unblurred_outset_shadow.fs.glsl',
|
||||
'resources/glsl/border.fs.glsl',
|
||||
'resources/glsl/cross_fade.fs.glsl',
|
||||
'resources/glsl/blend.fs.glsl',
|
||||
'resources/glsl/es2_common.fs.glsl',
|
||||
'resources/glsl/es2_common.vs.glsl',
|
||||
'resources/glsl/gl3_common.fs.glsl',
|
||||
|
287
gsk/resources/glsl/blend.fs.glsl
Normal file
287
gsk/resources/glsl/blend.fs.glsl
Normal file
@ -0,0 +1,287 @@
|
||||
uniform int u_mode;
|
||||
uniform sampler2D u_source2;
|
||||
|
||||
float
|
||||
combine (float source, float backdrop)
|
||||
{
|
||||
return source + backdrop * (1 - source);
|
||||
}
|
||||
|
||||
vec4
|
||||
composite (vec4 Cs, vec4 Cb, vec3 B)
|
||||
{
|
||||
float ao = Cs.a + Cb.a * (1 - Cs.a);
|
||||
vec3 Co = (Cs.a*(1 - Cb.a)*Cs.rgb + Cs.a*Cb.a*B + (1 - Cs.a)*Cb.a*Cb.rgb) / ao;
|
||||
return vec4(Co, ao);
|
||||
}
|
||||
|
||||
vec4
|
||||
normal (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
return composite (Cs, Cb, Cs.rgb);
|
||||
}
|
||||
|
||||
vec4
|
||||
multiply (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
return composite (Cs, Cb, Cs.rgb * Cb.rgb);
|
||||
}
|
||||
|
||||
vec4
|
||||
difference (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
return composite (Cs, Cb, abs(Cs.rgb - Cb.rgb));
|
||||
}
|
||||
|
||||
vec4
|
||||
screen (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
return composite (Cs, Cb, Cs.rgb + Cb.rgb - Cs.rgb * Cb.rgb);
|
||||
}
|
||||
|
||||
float
|
||||
hard_light (float source, float backdrop)
|
||||
{
|
||||
if (source <= 0.5)
|
||||
return 2 * backdrop * source;
|
||||
else
|
||||
return 2 * (backdrop + source - backdrop * source) - 1;
|
||||
}
|
||||
|
||||
vec4
|
||||
hard_light (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = vec3 (hard_light (Cs.r, Cb.r),
|
||||
hard_light (Cs.g, Cb.g),
|
||||
hard_light (Cs.b, Cb.b));
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
float
|
||||
soft_light (float source, float backdrop)
|
||||
{
|
||||
float db;
|
||||
|
||||
if (backdrop <= 0.25)
|
||||
db = ((16 * backdrop - 12) * backdrop + 4) * backdrop;
|
||||
else
|
||||
db = sqrt (backdrop);
|
||||
|
||||
if (source <= 0.5)
|
||||
return backdrop - (1 - 2 * source) * backdrop * (1 - backdrop);
|
||||
else
|
||||
return backdrop + (2 * source - 1) * (db - backdrop);
|
||||
}
|
||||
|
||||
vec4
|
||||
soft_light (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = vec3 (soft_light (Cs.r, Cb.r),
|
||||
soft_light (Cs.g, Cb.g),
|
||||
soft_light (Cs.b, Cb.b));
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
vec4
|
||||
overlay (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = vec3 (hard_light (Cb.r, Cs.r),
|
||||
hard_light (Cb.g, Cs.g),
|
||||
hard_light (Cb.b, Cs.b));
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
vec4
|
||||
darken (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = min (Cs.rgb, Cb.rgb);
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
vec4
|
||||
lighten (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = max (Cs.rgb, Cb.rgb);
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
float
|
||||
color_dodge (float source, float backdrop)
|
||||
{
|
||||
return (source == 1.0) ? source : min (backdrop / (1.0 - source), 1.0);
|
||||
}
|
||||
|
||||
vec4
|
||||
color_dodge (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = vec3 (color_dodge (Cs.r, Cb.r),
|
||||
color_dodge (Cs.g, Cb.g),
|
||||
color_dodge (Cs.b, Cb.b));
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
|
||||
float
|
||||
color_burn (float source, float backdrop)
|
||||
{
|
||||
return (source == 0.0) ? source : max ((1.0 - ((1.0 - backdrop) / source)), 0.0);
|
||||
}
|
||||
|
||||
vec4
|
||||
color_burn (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = vec3 (color_burn (Cs.r, Cb.r),
|
||||
color_burn (Cs.g, Cb.g),
|
||||
color_burn (Cs.b, Cb.b));
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
vec4
|
||||
exclusion (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = Cb.rgb + Cs.rgb - 2.0 * Cb.rgb * Cs.rgb;
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
float
|
||||
lum (vec3 c)
|
||||
{
|
||||
return 0.3 * c.r + 0.59 * c.g + 0.11 * c.b;
|
||||
}
|
||||
|
||||
vec3
|
||||
clip_color (vec3 c)
|
||||
{
|
||||
float l = lum (c);
|
||||
float n = min (c.r, min (c.g, c.b));
|
||||
float x = max (c.r, max (c.g, c.b));
|
||||
if (n < 0) c = l + (((c - l) * l) / (l - n));
|
||||
if (x > 1) c = l + (((c - l) * (1 - l)) / (x - l));
|
||||
return c;
|
||||
}
|
||||
|
||||
vec3
|
||||
set_lum (vec3 c, float l)
|
||||
{
|
||||
float d = l - lum (c);
|
||||
return clip_color (vec3 (c.r + d, c.g + d, c.b + d));
|
||||
}
|
||||
|
||||
float
|
||||
sat (vec3 c)
|
||||
{
|
||||
return max (c.r, max (c.g, c.b)) - min (c.r, min (c.g, c.b));
|
||||
}
|
||||
|
||||
vec3
|
||||
set_sat (vec3 c, float s)
|
||||
{
|
||||
float cmin = min (c.r, min (c.g, c.b));
|
||||
float cmax = max (c.r, max (c.g, c.b));
|
||||
vec3 res;
|
||||
|
||||
if (cmax == cmin)
|
||||
res = vec3 (0, 0, 0);
|
||||
else
|
||||
{
|
||||
if (c.r == cmax)
|
||||
{
|
||||
if (c.g == cmin)
|
||||
{
|
||||
res.b = ((c.b - cmin) * s) / (cmax - cmin);
|
||||
res.g = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
res.g = ((c.g - cmin) * s) / (cmax - cmin);
|
||||
res.b = 0;
|
||||
}
|
||||
res.r = s;
|
||||
}
|
||||
else if (c.g == cmax)
|
||||
{
|
||||
if (c.r == cmin)
|
||||
{
|
||||
res.b = ((c.b - cmin) * s) / (cmax - cmin);
|
||||
res.r = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
res.r = ((c.r - cmin) * s) / (cmax - cmin);
|
||||
res.b = 0;
|
||||
}
|
||||
res.g = s;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c.r == cmin)
|
||||
{
|
||||
res.g = ((c.g - cmin) * s) / (cmax - cmin);
|
||||
res.r = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
res.r = ((c.r - cmin) * s) / (cmax - cmin);
|
||||
res.g = 0;
|
||||
}
|
||||
res.b = s;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
vec4
|
||||
color (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = set_lum (Cs.rgb, lum (Cb.rgb));
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
vec4
|
||||
hue (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = set_lum (set_sat (Cs.rgb, sat (Cb.rgb)), lum (Cb.rgb));
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
vec4
|
||||
saturation (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = set_lum (set_sat (Cb.rgb, sat (Cs.rgb)), lum (Cb.rgb));
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
vec4
|
||||
luminosity (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = set_lum (Cb.rgb, lum (Cs.rgb));
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 bottom_color = Texture(u_source, vUv);
|
||||
vec4 top_color = Texture(u_source2, vUv);
|
||||
|
||||
vec4 result;
|
||||
switch(u_mode) {
|
||||
case 0: result = normal(bottom_color, top_color); break;
|
||||
case 1: result = multiply(bottom_color, top_color); break;
|
||||
case 2: result = screen(bottom_color, top_color); break;
|
||||
case 3: result = overlay(bottom_color, top_color); break;
|
||||
case 4: result = darken(bottom_color, top_color); break;
|
||||
case 5: result = lighten(bottom_color, top_color); break;
|
||||
case 6: result = color_dodge(bottom_color, top_color); break;
|
||||
case 7: result = color_burn(bottom_color, top_color); break;
|
||||
case 8: result = hard_light(bottom_color, top_color); break;
|
||||
case 9: result = soft_light(bottom_color, top_color); break;
|
||||
case 10: result = difference(bottom_color, top_color); break;
|
||||
case 11: result = exclusion(bottom_color, top_color); break;
|
||||
case 12: result = color(bottom_color, top_color); break;
|
||||
case 13: result = hue(bottom_color, top_color); break;
|
||||
case 14: result = saturation(bottom_color, top_color); break;
|
||||
case 15: result = luminosity(bottom_color, top_color); break;
|
||||
default: discard;
|
||||
}
|
||||
|
||||
setOutputColor(result * u_alpha);
|
||||
}
|
Loading…
Reference in New Issue
Block a user