forked from AuroraMiddleware/gtk
gl renderer: Implement rounded clip nodes
mostly a proof of concept
This commit is contained in:
parent
cd730ccff5
commit
24e69bb877
@ -44,6 +44,7 @@ dump_framebuffer (const char *filename, int w, int h)
|
||||
|
||||
static void
|
||||
gsk_gl_renderer_setup_render_mode (GskGLRenderer *self);
|
||||
|
||||
typedef struct {
|
||||
int id;
|
||||
/* Common locations (gl_common)*/
|
||||
@ -73,6 +74,11 @@ typedef struct {
|
||||
int start_point_location;
|
||||
int end_point_location;
|
||||
};
|
||||
struct {
|
||||
int clip_bounds_location;
|
||||
int corner_widths_location;
|
||||
int corner_heights_location;
|
||||
};
|
||||
};
|
||||
} Program;
|
||||
|
||||
@ -88,6 +94,7 @@ enum {
|
||||
MODE_TEXTURE,
|
||||
MODE_COLOR_MATRIX,
|
||||
MODE_LINEAR_GRADIENT,
|
||||
MODE_ROUNDED_CLIP,
|
||||
N_MODES
|
||||
};
|
||||
|
||||
@ -120,6 +127,11 @@ typedef struct {
|
||||
graphene_point_t start_point;
|
||||
graphene_point_t end_point;
|
||||
} linear_gradient_data;
|
||||
struct {
|
||||
graphene_rect_t clip_bounds;
|
||||
float corner_widths[4];
|
||||
float corner_heights[4];
|
||||
} rounded_clip_data;
|
||||
};
|
||||
|
||||
const char *name;
|
||||
@ -204,6 +216,7 @@ struct _GskGLRenderer
|
||||
Program color_program;
|
||||
Program color_matrix_program;
|
||||
Program linear_gradient_program;
|
||||
Program rounded_clip_program;
|
||||
|
||||
GArray *render_items;
|
||||
|
||||
@ -432,6 +445,22 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
|
||||
INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient_program, start_point_location, "uStartPoint");
|
||||
INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient_program, end_point_location, "uEndPoint");
|
||||
|
||||
self->rounded_clip_program.id = gsk_shader_builder_create_program (builder,
|
||||
"blit.vs.glsl",
|
||||
"rounded_clip.fs.glsl",
|
||||
&shader_error);
|
||||
if (shader_error != NULL)
|
||||
{
|
||||
g_propagate_prefixed_error (error,
|
||||
shader_error,
|
||||
"Unable to create 'rounded_clip' program: ");
|
||||
goto out;
|
||||
}
|
||||
init_common_locations (self, builder, &self->rounded_clip_program);
|
||||
INIT_PROGRAM_UNIFORM_LOCATION (rounded_clip_program, clip_bounds_location, "uClipBounds");
|
||||
INIT_PROGRAM_UNIFORM_LOCATION (rounded_clip_program, corner_widths_location, "uCornerWidths");
|
||||
INIT_PROGRAM_UNIFORM_LOCATION (rounded_clip_program, corner_heights_location, "uCornerHeights");
|
||||
|
||||
res = TRUE;
|
||||
|
||||
out:
|
||||
@ -686,6 +715,21 @@ render_item (GskGLRenderer *self,
|
||||
}
|
||||
break;
|
||||
|
||||
case MODE_ROUNDED_CLIP:
|
||||
{
|
||||
g_assert (item->program == &self->rounded_clip_program);
|
||||
glUniform1i (item->program->source_location, 0);
|
||||
gsk_gl_driver_bind_source_texture (self->gl_driver, item->render_target);
|
||||
glUniform4f (item->program->clip_bounds_location,
|
||||
item->rounded_clip_data.clip_bounds.origin.x,
|
||||
item->rounded_clip_data.clip_bounds.origin.y,
|
||||
item->rounded_clip_data.clip_bounds.size.width,
|
||||
item->rounded_clip_data.clip_bounds.size.height);
|
||||
glUniform4fv (item->program->corner_widths_location, 1, item->rounded_clip_data.corner_widths);
|
||||
glUniform4fv (item->program->corner_heights_location, 1, item->rounded_clip_data.corner_heights);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
@ -844,14 +888,23 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self,
|
||||
case GSK_ROUNDED_CLIP_NODE:
|
||||
{
|
||||
GskRenderNode *child = gsk_rounded_clip_node_get_child (node);
|
||||
const GskRoundedRect *clip = gsk_rounded_clip_node_peek_clip (node);
|
||||
graphene_matrix_t p;
|
||||
graphene_matrix_t identity;
|
||||
int i;
|
||||
|
||||
graphene_matrix_init_identity (&identity);
|
||||
init_framebuffer_for_node (self, &item, node, projection, &p);
|
||||
gsk_gl_renderer_add_render_item (self, &p, &identity, item.children, child,
|
||||
item.render_target);
|
||||
item.mode = MODE_BLIT;
|
||||
item.mode = MODE_ROUNDED_CLIP;
|
||||
item.program = &self->rounded_clip_program;
|
||||
item.rounded_clip_data.clip_bounds = clip->bounds;
|
||||
for (i = 0; i < 4; i ++)
|
||||
{
|
||||
item.rounded_clip_data.corner_widths[i] = MAX (clip->corner[i].width, 1);
|
||||
item.rounded_clip_data.corner_heights[i] = MAX (clip->corner[i].height, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -9,6 +9,7 @@ gsk_private_source_shaders = [
|
||||
'resources/glsl/color_matrix.vs.glsl',
|
||||
'resources/glsl/linear_gradient.fs.glsl',
|
||||
'resources/glsl/linear_gradient.vs.glsl',
|
||||
'resources/glsl/rounded_clip.fs.glsl',
|
||||
'resources/glsl/es2_common.fs.glsl',
|
||||
'resources/glsl/es2_common.vs.glsl',
|
||||
'resources/glsl/gl3_common.fs.glsl',
|
||||
|
91
gsk/resources/glsl/rounded_clip.fs.glsl
Normal file
91
gsk/resources/glsl/rounded_clip.fs.glsl
Normal file
@ -0,0 +1,91 @@
|
||||
uniform vec4 uClipBounds;
|
||||
uniform vec4 uCornerWidths;
|
||||
uniform vec4 uCornerHeights;
|
||||
|
||||
struct RoundedRect
|
||||
{
|
||||
vec4 bounds;
|
||||
vec4 corner_widths;
|
||||
vec4 corner_heights;
|
||||
};
|
||||
|
||||
float
|
||||
ellipsis_dist (vec2 p, vec2 radius)
|
||||
{
|
||||
vec2 p0 = p / radius;
|
||||
vec2 p1 = 2.0 * p0 / radius;
|
||||
|
||||
return (dot(p0, p0) - 1.0) / length (p1);
|
||||
}
|
||||
|
||||
float
|
||||
ellipsis_coverage (vec2 point, vec2 center, vec2 radius)
|
||||
{
|
||||
float d = ellipsis_dist (point - center, radius);
|
||||
return clamp (0.5 - d, 0.0, 1.0);
|
||||
}
|
||||
|
||||
float
|
||||
rounded_rect_coverage (RoundedRect r, vec2 p)
|
||||
{
|
||||
if (p.x < r.bounds.x || p.y < r.bounds.y ||
|
||||
p.x >= r.bounds.z || p.y >= r.bounds.w)
|
||||
return 0.0;
|
||||
|
||||
vec2 rad_tl = vec2(r.corner_widths.x, r.corner_heights.x);
|
||||
vec2 rad_tr = vec2(r.corner_widths.y, r.corner_heights.y);
|
||||
vec2 rad_br = vec2(r.corner_widths.z, r.corner_heights.z);
|
||||
vec2 rad_bl = vec2(r.corner_widths.w, r.corner_heights.w);
|
||||
|
||||
vec2 ref_tl = r.bounds.xy + vec2( r.corner_widths.x, r.corner_heights.x);
|
||||
vec2 ref_tr = r.bounds.zy + vec2(-r.corner_widths.y, r.corner_heights.y);
|
||||
vec2 ref_br = r.bounds.zw + vec2(-r.corner_widths.z, -r.corner_heights.z);
|
||||
vec2 ref_bl = r.bounds.xw + vec2( r.corner_widths.w, -r.corner_heights.w);
|
||||
|
||||
float d_tl = ellipsis_coverage(p, ref_tl, rad_tl);
|
||||
float d_tr = ellipsis_coverage(p, ref_tr, rad_tr);
|
||||
float d_br = ellipsis_coverage(p, ref_br, rad_br);
|
||||
float d_bl = ellipsis_coverage(p, ref_bl, rad_bl);
|
||||
|
||||
vec4 corner_coverages = 1.0 - vec4(d_tl, d_tr, d_br, d_bl);
|
||||
|
||||
bvec4 is_out = bvec4(p.x < ref_tl.x && p.y < ref_tl.y,
|
||||
p.x > ref_tr.x && p.y < ref_tr.y,
|
||||
p.x > ref_br.x && p.y > ref_br.y,
|
||||
p.x < ref_bl.x && p.y > ref_bl.y);
|
||||
|
||||
return 1.0 - dot(vec4(is_out), corner_coverages);
|
||||
}
|
||||
|
||||
RoundedRect
|
||||
rounded_rect_shrink (RoundedRect r, vec4 amount)
|
||||
{
|
||||
vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz;
|
||||
vec4 new_widths = max (r.corner_widths - amount.wyyw, 0.0);
|
||||
vec4 new_heights = max (r.corner_heights - amount.xxzz, 0.0);
|
||||
|
||||
return RoundedRect (new_bounds, new_widths, new_heights);
|
||||
}
|
||||
|
||||
vec4 fragCoord() {
|
||||
vec4 f = gl_FragCoord;
|
||||
f.x += uViewport.x;
|
||||
f.y = (uViewport.y + uViewport.w) - f.y;
|
||||
return f;
|
||||
}
|
||||
|
||||
vec4 clip(vec4 color) {
|
||||
vec4 bounds = uClipBounds;
|
||||
bounds.z = bounds.x + bounds.z;
|
||||
bounds.w = bounds.y + bounds.w;
|
||||
|
||||
RoundedRect r = RoundedRect(bounds, uCornerWidths, uCornerHeights);
|
||||
|
||||
return color * rounded_rect_coverage(r, fragCoord().xy);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 diffuse = Texture(uSource, vUv);
|
||||
|
||||
setOutputColor(clip(diffuse) * uAlpha);
|
||||
}
|
Loading…
Reference in New Issue
Block a user