diff options
author | M Henning <drawoc@darkrefraction.com> | 2022-02-06 21:00:31 -0500 |
---|---|---|
committer | M Henning <drawoc@darkrefraction.com> | 2022-06-20 14:28:03 -0400 |
commit | 276ec89977dce2cd8a78ef33279f79bbe53d63cf (patch) | |
tree | 3ea79e4cf5a404dc21c94e9bdb17750ac20fb059 /shaders | |
parent | a9b6151af8741a82f6e502ae4849d626da96f283 (diff) |
shaders: Import shaders from gtk4 GL renderer
Captured from gtk4-widget-factory on gtk 4.6.0
Reviewed-by: Emma Anholt <emma@anholt.net>
Diffstat (limited to 'shaders')
49 files changed, 20293 insertions, 0 deletions
diff --git a/shaders/gtk4/102.shader_test b/shaders/gtk4/102.shader_test new file mode 100644 index 0000000..64871f6 --- /dev/null +++ b/shaders/gtk4/102.shader_test @@ -0,0 +1,465 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// linear_gradient.glsl +uniform vec4 u_points; + +_OUT_ vec4 info; + +void main() { + gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0)); + + vec2 mv0 = u_modelview[0].xy; + vec2 mv1 = u_modelview[1].xy; + vec2 offset = aPosition - u_points.xy; + vec2 coord = vec2(dot(mv0, offset), + dot(mv1, offset)); + + // Original equation: + // VS | maxDist = length(end - start); + // VS | gradient = end - start; + // VS | gradientLength = length(gradient); + // FS | pos = frag_coord - start + // FS | proj = (dot(gradient, pos) / (gradientLength * gradientLength)) * gradient + // FS | offset = length(proj) / maxDist + + // Simplified formula derivation: + // 1. Notice that maxDist = gradientLength: + // offset = length(proj) / gradientLength + // 2. Let gnorm = gradient / gradientLength, then: + // proj = (dot(gnorm * gradientLength, pos) / (gradientLength * gradientLength)) * (gnorm * gradientLength) = + // = dot(gnorm, pos) * gnorm + // 3. Since gnorm is unit length then: + // length(proj) = length(dot(gnorm, pos) * gnorm) = dot(gnorm, pos) + // 4. We can avoid the FS division by passing a scaled pos from the VS: + // offset = dot(gnorm, pos) / gradientLength = dot(gnorm, pos / gradientLength) + // 5. 1.0 / length(gradient) is inversesqrt(dot(gradient, gradient)) in GLSL + vec2 gradient = vec2(dot(mv0, u_points.zw), + dot(mv1, u_points.zw)); + float rcp_gradient_length = inversesqrt(dot(gradient, gradient)); + + info = rcp_gradient_length * vec4(coord, gradient); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// linear_gradient.glsl + +#define MAX_COLOR_STOPS 6 + +#ifdef GSK_LEGACY +uniform int u_num_color_stops; +#else +uniform highp int u_num_color_stops; // Why? Because it works like this. +#endif + +uniform float u_color_stops[MAX_COLOR_STOPS * 5]; +uniform bool u_repeat; + +_IN_ vec4 info; + +float get_offset(int index) { + // u_color_stops[5 * index] makes Intel Windows driver crash. + // See https://gitlab.gnome.org/GNOME/gtk/-/issues/3783 + int base = 5 * index; + return u_color_stops[base]; +} + +vec4 get_color(int index) { + int base = 5 * index + 1; + + return vec4(u_color_stops[base], + u_color_stops[base + 1], + u_color_stops[base + 2], + u_color_stops[base + 3]); +} + +void main() { + float offset = dot(info.xy, info.zw); + float curr_offset; + float next_offset; + + if (u_repeat) { + offset = fract(offset); + } + + next_offset = get_offset(0); + if (offset < next_offset) { + gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha)); + return; + } + + if (offset >= get_offset(u_num_color_stops - 1)) { + gskSetOutputColor(gsk_scaled_premultiply(get_color(u_num_color_stops - 1), u_alpha)); + return; + } + + for (int i = 0; i < MAX_COLOR_STOPS; i++) { + curr_offset = next_offset; + next_offset = get_offset(i + 1); + + if (offset < next_offset) { + float f = (offset - curr_offset) / (next_offset - curr_offset); + vec4 curr_color = gsk_premultiply(get_color(i)); + vec4 next_color = gsk_premultiply(get_color(i + 1)); + vec4 color = mix(curr_color, next_color, f); + gskSetScaledOutputColor(color, u_alpha); + return; + } + } +} + diff --git a/shaders/gtk4/105.shader_test b/shaders/gtk4/105.shader_test new file mode 100644 index 0000000..b568bff --- /dev/null +++ b/shaders/gtk4/105.shader_test @@ -0,0 +1,465 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// linear_gradient.glsl +uniform vec4 u_points; + +_OUT_ vec4 info; + +void main() { + gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0)); + + vec2 mv0 = u_modelview[0].xy; + vec2 mv1 = u_modelview[1].xy; + vec2 offset = aPosition - u_points.xy; + vec2 coord = vec2(dot(mv0, offset), + dot(mv1, offset)); + + // Original equation: + // VS | maxDist = length(end - start); + // VS | gradient = end - start; + // VS | gradientLength = length(gradient); + // FS | pos = frag_coord - start + // FS | proj = (dot(gradient, pos) / (gradientLength * gradientLength)) * gradient + // FS | offset = length(proj) / maxDist + + // Simplified formula derivation: + // 1. Notice that maxDist = gradientLength: + // offset = length(proj) / gradientLength + // 2. Let gnorm = gradient / gradientLength, then: + // proj = (dot(gnorm * gradientLength, pos) / (gradientLength * gradientLength)) * (gnorm * gradientLength) = + // = dot(gnorm, pos) * gnorm + // 3. Since gnorm is unit length then: + // length(proj) = length(dot(gnorm, pos) * gnorm) = dot(gnorm, pos) + // 4. We can avoid the FS division by passing a scaled pos from the VS: + // offset = dot(gnorm, pos) / gradientLength = dot(gnorm, pos / gradientLength) + // 5. 1.0 / length(gradient) is inversesqrt(dot(gradient, gradient)) in GLSL + vec2 gradient = vec2(dot(mv0, u_points.zw), + dot(mv1, u_points.zw)); + float rcp_gradient_length = inversesqrt(dot(gradient, gradient)); + + info = rcp_gradient_length * vec4(coord, gradient); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// linear_gradient.glsl + +#define MAX_COLOR_STOPS 6 + +#ifdef GSK_LEGACY +uniform int u_num_color_stops; +#else +uniform highp int u_num_color_stops; // Why? Because it works like this. +#endif + +uniform float u_color_stops[MAX_COLOR_STOPS * 5]; +uniform bool u_repeat; + +_IN_ vec4 info; + +float get_offset(int index) { + // u_color_stops[5 * index] makes Intel Windows driver crash. + // See https://gitlab.gnome.org/GNOME/gtk/-/issues/3783 + int base = 5 * index; + return u_color_stops[base]; +} + +vec4 get_color(int index) { + int base = 5 * index + 1; + + return vec4(u_color_stops[base], + u_color_stops[base + 1], + u_color_stops[base + 2], + u_color_stops[base + 3]); +} + +void main() { + float offset = dot(info.xy, info.zw); + float curr_offset; + float next_offset; + + if (u_repeat) { + offset = fract(offset); + } + + next_offset = get_offset(0); + if (offset < next_offset) { + gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha)); + return; + } + + if (offset >= get_offset(u_num_color_stops - 1)) { + gskSetOutputColor(gsk_scaled_premultiply(get_color(u_num_color_stops - 1), u_alpha)); + return; + } + + for (int i = 0; i < MAX_COLOR_STOPS; i++) { + curr_offset = next_offset; + next_offset = get_offset(i + 1); + + if (offset < next_offset) { + float f = (offset - curr_offset) / (next_offset - curr_offset); + vec4 curr_color = gsk_premultiply(get_color(i)); + vec4 next_color = gsk_premultiply(get_color(i + 1)); + vec4 color = mix(curr_color, next_color, f); + gskSetScaledOutputColor(color, u_alpha); + return; + } + } +} + diff --git a/shaders/gtk4/108.shader_test b/shaders/gtk4/108.shader_test new file mode 100644 index 0000000..ec4ce94 --- /dev/null +++ b/shaders/gtk4/108.shader_test @@ -0,0 +1,463 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// linear_gradient.glsl +uniform vec4 u_points; + +_OUT_ vec4 info; + +void main() { + gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0)); + + vec2 mv0 = u_modelview[0].xy; + vec2 mv1 = u_modelview[1].xy; + vec2 offset = aPosition - u_points.xy; + vec2 coord = vec2(dot(mv0, offset), + dot(mv1, offset)); + + // Original equation: + // VS | maxDist = length(end - start); + // VS | gradient = end - start; + // VS | gradientLength = length(gradient); + // FS | pos = frag_coord - start + // FS | proj = (dot(gradient, pos) / (gradientLength * gradientLength)) * gradient + // FS | offset = length(proj) / maxDist + + // Simplified formula derivation: + // 1. Notice that maxDist = gradientLength: + // offset = length(proj) / gradientLength + // 2. Let gnorm = gradient / gradientLength, then: + // proj = (dot(gnorm * gradientLength, pos) / (gradientLength * gradientLength)) * (gnorm * gradientLength) = + // = dot(gnorm, pos) * gnorm + // 3. Since gnorm is unit length then: + // length(proj) = length(dot(gnorm, pos) * gnorm) = dot(gnorm, pos) + // 4. We can avoid the FS division by passing a scaled pos from the VS: + // offset = dot(gnorm, pos) / gradientLength = dot(gnorm, pos / gradientLength) + // 5. 1.0 / length(gradient) is inversesqrt(dot(gradient, gradient)) in GLSL + vec2 gradient = vec2(dot(mv0, u_points.zw), + dot(mv1, u_points.zw)); + float rcp_gradient_length = inversesqrt(dot(gradient, gradient)); + + info = rcp_gradient_length * vec4(coord, gradient); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// linear_gradient.glsl + +#define MAX_COLOR_STOPS 6 + +#ifdef GSK_LEGACY +uniform int u_num_color_stops; +#else +uniform highp int u_num_color_stops; // Why? Because it works like this. +#endif + +uniform float u_color_stops[MAX_COLOR_STOPS * 5]; +uniform bool u_repeat; + +_IN_ vec4 info; + +float get_offset(int index) { + // u_color_stops[5 * index] makes Intel Windows driver crash. + // See https://gitlab.gnome.org/GNOME/gtk/-/issues/3783 + int base = 5 * index; + return u_color_stops[base]; +} + +vec4 get_color(int index) { + int base = 5 * index + 1; + + return vec4(u_color_stops[base], + u_color_stops[base + 1], + u_color_stops[base + 2], + u_color_stops[base + 3]); +} + +void main() { + float offset = dot(info.xy, info.zw); + float curr_offset; + float next_offset; + + if (u_repeat) { + offset = fract(offset); + } + + next_offset = get_offset(0); + if (offset < next_offset) { + gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha)); + return; + } + + if (offset >= get_offset(u_num_color_stops - 1)) { + gskSetOutputColor(gsk_scaled_premultiply(get_color(u_num_color_stops - 1), u_alpha)); + return; + } + + for (int i = 0; i < MAX_COLOR_STOPS; i++) { + curr_offset = next_offset; + next_offset = get_offset(i + 1); + + if (offset < next_offset) { + float f = (offset - curr_offset) / (next_offset - curr_offset); + vec4 curr_color = gsk_premultiply(get_color(i)); + vec4 next_color = gsk_premultiply(get_color(i + 1)); + vec4 color = mix(curr_color, next_color, f); + gskSetScaledOutputColor(color, u_alpha); + return; + } + } +} + diff --git a/shaders/gtk4/111.shader_test b/shaders/gtk4/111.shader_test new file mode 100644 index 0000000..42a65cf --- /dev/null +++ b/shaders/gtk4/111.shader_test @@ -0,0 +1,392 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// outset_shadow.glsl + +uniform vec4[3] u_outline_rect; + +_OUT_ vec4 final_color; +_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outline; + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + vUv = vec2(aUv.x, aUv.y); + + final_color = gsk_scaled_premultiply(aColor, u_alpha); + + GskRoundedRect outline = gsk_create_rect(u_outline_rect); + gsk_rounded_rect_transform(outline, u_modelview); + gsk_rounded_rect_encode(outline, transformed_outline); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// outset_shadow.glsl + +_IN_ vec4 final_color; +_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outline; + +void main() { + vec2 frag = gsk_get_frag_coord(); + float alpha = GskTexture(u_source, vUv).a; + + alpha *= (1.0 - clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outline), frag), 0.0, 1.0)); + + gskSetScaledOutputColor(final_color, alpha); +} + diff --git a/shaders/gtk4/114.shader_test b/shaders/gtk4/114.shader_test new file mode 100644 index 0000000..3bbb8c5 --- /dev/null +++ b/shaders/gtk4/114.shader_test @@ -0,0 +1,392 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// outset_shadow.glsl + +uniform vec4[3] u_outline_rect; + +_OUT_ vec4 final_color; +_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outline; + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + vUv = vec2(aUv.x, aUv.y); + + final_color = gsk_scaled_premultiply(aColor, u_alpha); + + GskRoundedRect outline = gsk_create_rect(u_outline_rect); + gsk_rounded_rect_transform(outline, u_modelview); + gsk_rounded_rect_encode(outline, transformed_outline); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// outset_shadow.glsl + +_IN_ vec4 final_color; +_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outline; + +void main() { + vec2 frag = gsk_get_frag_coord(); + float alpha = GskTexture(u_source, vUv).a; + + alpha *= (1.0 - clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outline), frag), 0.0, 1.0)); + + gskSetScaledOutputColor(final_color, alpha); +} + diff --git a/shaders/gtk4/117.shader_test b/shaders/gtk4/117.shader_test new file mode 100644 index 0000000..c0cc165 --- /dev/null +++ b/shaders/gtk4/117.shader_test @@ -0,0 +1,390 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// outset_shadow.glsl + +uniform vec4[3] u_outline_rect; + +_OUT_ vec4 final_color; +_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outline; + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + vUv = vec2(aUv.x, aUv.y); + + final_color = gsk_scaled_premultiply(aColor, u_alpha); + + GskRoundedRect outline = gsk_create_rect(u_outline_rect); + gsk_rounded_rect_transform(outline, u_modelview); + gsk_rounded_rect_encode(outline, transformed_outline); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// outset_shadow.glsl + +_IN_ vec4 final_color; +_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outline; + +void main() { + vec2 frag = gsk_get_frag_coord(); + float alpha = GskTexture(u_source, vUv).a; + + alpha *= (1.0 - clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outline), frag), 0.0, 1.0)); + + gskSetScaledOutputColor(final_color, alpha); +} + diff --git a/shaders/gtk4/12.shader_test b/shaders/gtk4/12.shader_test new file mode 100644 index 0000000..fc62790 --- /dev/null +++ b/shaders/gtk4/12.shader_test @@ -0,0 +1,375 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// blit.glsl + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + vUv = vec2(aUv.x, aUv.y); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// blit.glsl + +void main() { + vec4 diffuse = GskTexture(u_source, vUv); + + gskSetScaledOutputColor(diffuse, u_alpha); +} + diff --git a/shaders/gtk4/120.shader_test b/shaders/gtk4/120.shader_test new file mode 100644 index 0000000..e8d623d --- /dev/null +++ b/shaders/gtk4/120.shader_test @@ -0,0 +1,445 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// radial_gradient.glsl + +uniform vec4 u_geometry; + +_OUT_ vec2 coord; + +void main() { + gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0)); + + vec2 mv0 = u_modelview[0].xy; + vec2 mv1 = u_modelview[1].xy; + vec2 offset = aPosition - u_geometry.xy; + vec2 dir = vec2(dot(mv0, offset), + dot(mv1, offset)); + + coord = dir * u_geometry.zw; +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// radial_gradient.glsl + +#define MAX_COLOR_STOPS 6 + +#ifdef GSK_LEGACY +uniform int u_num_color_stops; +#else +uniform highp int u_num_color_stops; +#endif + +uniform bool u_repeat; +uniform vec2 u_range; +uniform float u_color_stops[MAX_COLOR_STOPS * 5]; + +_IN_ vec2 coord; + +float get_offset(int index) { + // u_color_stops[5 * index] makes Intel Windows driver crash. + // See https://gitlab.gnome.org/GNOME/gtk/-/issues/3783 + int base = 5 * index; + return u_color_stops[base]; +} + +vec4 get_color(int index) { + int base = 5 * index + 1; + + return vec4(u_color_stops[base], + u_color_stops[base + 1], + u_color_stops[base + 2], + u_color_stops[base + 3]); +} + +void main() { + // Reverse scale + float offset = length(coord) * u_range.x + u_range.y; + float curr_offset; + float next_offset; + + if (u_repeat) { + offset = fract(offset); + } + + next_offset = get_offset(0); + if (offset < next_offset) { + gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha)); + return; + } + + if (offset >= get_offset(u_num_color_stops - 1)) { + gskSetOutputColor(gsk_scaled_premultiply(get_color(u_num_color_stops - 1), u_alpha)); + return; + } + + for (int i = 0; i < MAX_COLOR_STOPS; i++) { + curr_offset = next_offset; + next_offset = get_offset(i + 1); + + if (offset < next_offset) { + float f = (offset - curr_offset) / (next_offset - curr_offset); + vec4 curr_color = gsk_premultiply(get_color(i)); + vec4 next_color = gsk_premultiply(get_color(i + 1)); + vec4 color = mix(curr_color, next_color, f); + gskSetScaledOutputColor(color, u_alpha); + return; + } + } +} + diff --git a/shaders/gtk4/123.shader_test b/shaders/gtk4/123.shader_test new file mode 100644 index 0000000..bec58bb --- /dev/null +++ b/shaders/gtk4/123.shader_test @@ -0,0 +1,445 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// radial_gradient.glsl + +uniform vec4 u_geometry; + +_OUT_ vec2 coord; + +void main() { + gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0)); + + vec2 mv0 = u_modelview[0].xy; + vec2 mv1 = u_modelview[1].xy; + vec2 offset = aPosition - u_geometry.xy; + vec2 dir = vec2(dot(mv0, offset), + dot(mv1, offset)); + + coord = dir * u_geometry.zw; +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// radial_gradient.glsl + +#define MAX_COLOR_STOPS 6 + +#ifdef GSK_LEGACY +uniform int u_num_color_stops; +#else +uniform highp int u_num_color_stops; +#endif + +uniform bool u_repeat; +uniform vec2 u_range; +uniform float u_color_stops[MAX_COLOR_STOPS * 5]; + +_IN_ vec2 coord; + +float get_offset(int index) { + // u_color_stops[5 * index] makes Intel Windows driver crash. + // See https://gitlab.gnome.org/GNOME/gtk/-/issues/3783 + int base = 5 * index; + return u_color_stops[base]; +} + +vec4 get_color(int index) { + int base = 5 * index + 1; + + return vec4(u_color_stops[base], + u_color_stops[base + 1], + u_color_stops[base + 2], + u_color_stops[base + 3]); +} + +void main() { + // Reverse scale + float offset = length(coord) * u_range.x + u_range.y; + float curr_offset; + float next_offset; + + if (u_repeat) { + offset = fract(offset); + } + + next_offset = get_offset(0); + if (offset < next_offset) { + gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha)); + return; + } + + if (offset >= get_offset(u_num_color_stops - 1)) { + gskSetOutputColor(gsk_scaled_premultiply(get_color(u_num_color_stops - 1), u_alpha)); + return; + } + + for (int i = 0; i < MAX_COLOR_STOPS; i++) { + curr_offset = next_offset; + next_offset = get_offset(i + 1); + + if (offset < next_offset) { + float f = (offset - curr_offset) / (next_offset - curr_offset); + vec4 curr_color = gsk_premultiply(get_color(i)); + vec4 next_color = gsk_premultiply(get_color(i + 1)); + vec4 color = mix(curr_color, next_color, f); + gskSetScaledOutputColor(color, u_alpha); + return; + } + } +} + diff --git a/shaders/gtk4/126.shader_test b/shaders/gtk4/126.shader_test new file mode 100644 index 0000000..f64432d --- /dev/null +++ b/shaders/gtk4/126.shader_test @@ -0,0 +1,443 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// radial_gradient.glsl + +uniform vec4 u_geometry; + +_OUT_ vec2 coord; + +void main() { + gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0)); + + vec2 mv0 = u_modelview[0].xy; + vec2 mv1 = u_modelview[1].xy; + vec2 offset = aPosition - u_geometry.xy; + vec2 dir = vec2(dot(mv0, offset), + dot(mv1, offset)); + + coord = dir * u_geometry.zw; +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// radial_gradient.glsl + +#define MAX_COLOR_STOPS 6 + +#ifdef GSK_LEGACY +uniform int u_num_color_stops; +#else +uniform highp int u_num_color_stops; +#endif + +uniform bool u_repeat; +uniform vec2 u_range; +uniform float u_color_stops[MAX_COLOR_STOPS * 5]; + +_IN_ vec2 coord; + +float get_offset(int index) { + // u_color_stops[5 * index] makes Intel Windows driver crash. + // See https://gitlab.gnome.org/GNOME/gtk/-/issues/3783 + int base = 5 * index; + return u_color_stops[base]; +} + +vec4 get_color(int index) { + int base = 5 * index + 1; + + return vec4(u_color_stops[base], + u_color_stops[base + 1], + u_color_stops[base + 2], + u_color_stops[base + 3]); +} + +void main() { + // Reverse scale + float offset = length(coord) * u_range.x + u_range.y; + float curr_offset; + float next_offset; + + if (u_repeat) { + offset = fract(offset); + } + + next_offset = get_offset(0); + if (offset < next_offset) { + gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha)); + return; + } + + if (offset >= get_offset(u_num_color_stops - 1)) { + gskSetOutputColor(gsk_scaled_premultiply(get_color(u_num_color_stops - 1), u_alpha)); + return; + } + + for (int i = 0; i < MAX_COLOR_STOPS; i++) { + curr_offset = next_offset; + next_offset = get_offset(i + 1); + + if (offset < next_offset) { + float f = (offset - curr_offset) / (next_offset - curr_offset); + vec4 curr_color = gsk_premultiply(get_color(i)); + vec4 next_color = gsk_premultiply(get_color(i + 1)); + vec4 color = mix(curr_color, next_color, f); + gskSetScaledOutputColor(color, u_alpha); + return; + } + } +} + diff --git a/shaders/gtk4/129.shader_test b/shaders/gtk4/129.shader_test new file mode 100644 index 0000000..d5e3525 --- /dev/null +++ b/shaders/gtk4/129.shader_test @@ -0,0 +1,402 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// repeat.glsl + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + vUv = vec2(aUv.x, aUv.y); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// repeat.glsl + +uniform vec4 u_child_bounds; +uniform vec4 u_texture_rect; + +float wrap(float f, float wrap_for) { + return mod(f, wrap_for); +} + +/* We get the texture coordinates via vUv, + * but that might be on a texture atlas, so we need to do the + * wrapping ourselves. + */ +void main() { + + /* We map the texture coordinate to [1;0], then wrap it and scale the result again */ + + float tw = u_texture_rect.z - u_texture_rect.x; + float th = u_texture_rect.w - u_texture_rect.y; + + float mapped_x = (vUv.x - u_texture_rect.x) / tw; + float mapped_y = (vUv.y - u_texture_rect.y) / th; + + float wrapped_x = wrap(u_child_bounds.x + mapped_x * u_child_bounds.z, 1.0); + float wrapped_y = wrap(u_child_bounds.y + mapped_y * u_child_bounds.w, 1.0); + + vec2 tp; + tp.x = u_texture_rect.x + (wrapped_x * tw); + tp.y = u_texture_rect.y + (wrapped_y * th); + + vec4 diffuse = GskTexture(u_source, tp); + + gskSetScaledOutputColor(diffuse, u_alpha); +} + diff --git a/shaders/gtk4/132.shader_test b/shaders/gtk4/132.shader_test new file mode 100644 index 0000000..73e1911 --- /dev/null +++ b/shaders/gtk4/132.shader_test @@ -0,0 +1,402 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// repeat.glsl + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + vUv = vec2(aUv.x, aUv.y); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// repeat.glsl + +uniform vec4 u_child_bounds; +uniform vec4 u_texture_rect; + +float wrap(float f, float wrap_for) { + return mod(f, wrap_for); +} + +/* We get the texture coordinates via vUv, + * but that might be on a texture atlas, so we need to do the + * wrapping ourselves. + */ +void main() { + + /* We map the texture coordinate to [1;0], then wrap it and scale the result again */ + + float tw = u_texture_rect.z - u_texture_rect.x; + float th = u_texture_rect.w - u_texture_rect.y; + + float mapped_x = (vUv.x - u_texture_rect.x) / tw; + float mapped_y = (vUv.y - u_texture_rect.y) / th; + + float wrapped_x = wrap(u_child_bounds.x + mapped_x * u_child_bounds.z, 1.0); + float wrapped_y = wrap(u_child_bounds.y + mapped_y * u_child_bounds.w, 1.0); + + vec2 tp; + tp.x = u_texture_rect.x + (wrapped_x * tw); + tp.y = u_texture_rect.y + (wrapped_y * th); + + vec4 diffuse = GskTexture(u_source, tp); + + gskSetScaledOutputColor(diffuse, u_alpha); +} + diff --git a/shaders/gtk4/135.shader_test b/shaders/gtk4/135.shader_test new file mode 100644 index 0000000..87d53ab --- /dev/null +++ b/shaders/gtk4/135.shader_test @@ -0,0 +1,400 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// repeat.glsl + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + vUv = vec2(aUv.x, aUv.y); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// repeat.glsl + +uniform vec4 u_child_bounds; +uniform vec4 u_texture_rect; + +float wrap(float f, float wrap_for) { + return mod(f, wrap_for); +} + +/* We get the texture coordinates via vUv, + * but that might be on a texture atlas, so we need to do the + * wrapping ourselves. + */ +void main() { + + /* We map the texture coordinate to [1;0], then wrap it and scale the result again */ + + float tw = u_texture_rect.z - u_texture_rect.x; + float th = u_texture_rect.w - u_texture_rect.y; + + float mapped_x = (vUv.x - u_texture_rect.x) / tw; + float mapped_y = (vUv.y - u_texture_rect.y) / th; + + float wrapped_x = wrap(u_child_bounds.x + mapped_x * u_child_bounds.z, 1.0); + float wrapped_y = wrap(u_child_bounds.y + mapped_y * u_child_bounds.w, 1.0); + + vec2 tp; + tp.x = u_texture_rect.x + (wrapped_x * tw); + tp.y = u_texture_rect.y + (wrapped_y * th); + + vec4 diffuse = GskTexture(u_source, tp); + + gskSetScaledOutputColor(diffuse, u_alpha); +} + diff --git a/shaders/gtk4/138.shader_test b/shaders/gtk4/138.shader_test new file mode 100644 index 0000000..8daf069 --- /dev/null +++ b/shaders/gtk4/138.shader_test @@ -0,0 +1,402 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// unblurred_outset_shadow.glsl + +uniform float u_spread; +uniform vec2 u_offset; +uniform vec4[3] u_outline_rect; + +_OUT_ vec4 final_color; +_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + final_color = gsk_premultiply(aColor) * u_alpha; + + GskRoundedRect inside = gsk_create_rect(u_outline_rect); + GskRoundedRect outside = gsk_rounded_rect_shrink(inside, vec4(- u_spread)); + + gsk_rounded_rect_offset(outside, u_offset); + + gsk_rounded_rect_transform(outside, u_modelview); + gsk_rounded_rect_transform(inside, u_modelview); + + gsk_rounded_rect_encode(outside, transformed_outside_outline); + gsk_rounded_rect_encode(inside, transformed_inside_outline); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// unblurred_outset_shadow.glsl +_IN_ vec4 final_color; +_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; + +void main() { + vec2 frag = gsk_get_frag_coord(); + + float alpha = clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outside_outline), frag) - + gsk_rounded_rect_coverage(gsk_decode_rect(transformed_inside_outline), frag), + 0.0, 1.0); + + gskSetScaledOutputColor(final_color, alpha); +} + + diff --git a/shaders/gtk4/141.shader_test b/shaders/gtk4/141.shader_test new file mode 100644 index 0000000..736a291 --- /dev/null +++ b/shaders/gtk4/141.shader_test @@ -0,0 +1,402 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// unblurred_outset_shadow.glsl + +uniform float u_spread; +uniform vec2 u_offset; +uniform vec4[3] u_outline_rect; + +_OUT_ vec4 final_color; +_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + final_color = gsk_premultiply(aColor) * u_alpha; + + GskRoundedRect inside = gsk_create_rect(u_outline_rect); + GskRoundedRect outside = gsk_rounded_rect_shrink(inside, vec4(- u_spread)); + + gsk_rounded_rect_offset(outside, u_offset); + + gsk_rounded_rect_transform(outside, u_modelview); + gsk_rounded_rect_transform(inside, u_modelview); + + gsk_rounded_rect_encode(outside, transformed_outside_outline); + gsk_rounded_rect_encode(inside, transformed_inside_outline); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// unblurred_outset_shadow.glsl +_IN_ vec4 final_color; +_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; + +void main() { + vec2 frag = gsk_get_frag_coord(); + + float alpha = clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outside_outline), frag) - + gsk_rounded_rect_coverage(gsk_decode_rect(transformed_inside_outline), frag), + 0.0, 1.0); + + gskSetScaledOutputColor(final_color, alpha); +} + + diff --git a/shaders/gtk4/144.shader_test b/shaders/gtk4/144.shader_test new file mode 100644 index 0000000..1fc4e32 --- /dev/null +++ b/shaders/gtk4/144.shader_test @@ -0,0 +1,400 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// unblurred_outset_shadow.glsl + +uniform float u_spread; +uniform vec2 u_offset; +uniform vec4[3] u_outline_rect; + +_OUT_ vec4 final_color; +_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + final_color = gsk_premultiply(aColor) * u_alpha; + + GskRoundedRect inside = gsk_create_rect(u_outline_rect); + GskRoundedRect outside = gsk_rounded_rect_shrink(inside, vec4(- u_spread)); + + gsk_rounded_rect_offset(outside, u_offset); + + gsk_rounded_rect_transform(outside, u_modelview); + gsk_rounded_rect_transform(inside, u_modelview); + + gsk_rounded_rect_encode(outside, transformed_outside_outline); + gsk_rounded_rect_encode(inside, transformed_inside_outline); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// unblurred_outset_shadow.glsl +_IN_ vec4 final_color; +_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; + +void main() { + vec2 frag = gsk_get_frag_coord(); + + float alpha = clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outside_outline), frag) - + gsk_rounded_rect_coverage(gsk_decode_rect(transformed_inside_outline), frag), + 0.0, 1.0); + + gskSetScaledOutputColor(final_color, alpha); +} + + diff --git a/shaders/gtk4/146.shader_test b/shaders/gtk4/146.shader_test new file mode 100644 index 0000000..6d7a623 --- /dev/null +++ b/shaders/gtk4/146.shader_test @@ -0,0 +1,54 @@ +[require] +GLSL >= 3.30 + +[vertex shader] +#version 330 core +in vec4 a_position; +in vec2 a_texcoord; +out vec2 v_texcoord; +void main() +{ + gl_Position = a_position; + v_texcoord = a_texcoord; +} + +[fragment shader] +#version 330 core +uniform vec2 tex_scale0; +uniform vec2 tex_scale1; +uniform vec2 tex_scale2; +uniform float width; +uniform float height; +uniform float poffset_x; +uniform float poffset_y; +uniform vec3 offset; +uniform vec3 coeff1; +uniform vec3 coeff2; +uniform vec3 coeff3; +uniform sampler2D Ytex, Utex, Vtex; + +layout (location = 0) out vec4 fragColor; + +vec3 yuv_to_rgb (vec3 val, vec3 offset, vec3 ycoeff, vec3 ucoeff, vec3 vcoeff) { + vec3 rgb; + val += offset; + rgb.r = dot(val, ycoeff); + rgb.g = dot(val, ucoeff); + rgb.b = dot(val, vcoeff); + return rgb; +} + + +in vec2 v_texcoord; +void main (void) { +vec2 texcoord; +texcoord = v_texcoord; +vec4 texel, rgba; +texel.x = texture(Ytex, texcoord * tex_scale0).r; +texel.y = texture(Utex, texcoord * tex_scale1).r; +texel.z = texture(Vtex, texcoord * tex_scale2).r; +rgba.rgb = yuv_to_rgb (texel.xyz, offset, coeff1, coeff2, coeff3); +rgba.a = 1.0; +fragColor=vec4(rgba.r,rgba.g,rgba.b,rgba.a); + +} diff --git a/shaders/gtk4/15.shader_test b/shaders/gtk4/15.shader_test new file mode 100644 index 0000000..d4b808f --- /dev/null +++ b/shaders/gtk4/15.shader_test @@ -0,0 +1,375 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// blit.glsl + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + vUv = vec2(aUv.x, aUv.y); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// blit.glsl + +void main() { + vec4 diffuse = GskTexture(u_source, vUv); + + gskSetScaledOutputColor(diffuse, u_alpha); +} + diff --git a/shaders/gtk4/18.shader_test b/shaders/gtk4/18.shader_test new file mode 100644 index 0000000..27dfe83 --- /dev/null +++ b/shaders/gtk4/18.shader_test @@ -0,0 +1,373 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// blit.glsl + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + vUv = vec2(aUv.x, aUv.y); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// blit.glsl + +void main() { + vec4 diffuse = GskTexture(u_source, vUv); + + gskSetScaledOutputColor(diffuse, u_alpha); +} + diff --git a/shaders/gtk4/21.shader_test b/shaders/gtk4/21.shader_test new file mode 100644 index 0000000..790282d --- /dev/null +++ b/shaders/gtk4/21.shader_test @@ -0,0 +1,417 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// blur.glsl + +uniform float u_blur_radius; +uniform vec2 u_blur_size; +uniform vec2 u_blur_dir; + +_OUT_ vec2 pixel_step; +_OUT_ float pixels_per_side; +_OUT_ vec3 initial_gaussian; + +const float PI = 3.14159265; +const float RADIUS_MULTIPLIER = 2.0; + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + vUv = vec2(aUv.x, aUv.y); + + pixel_step = (vec2(1.0) / u_blur_size) * u_blur_dir; + pixels_per_side = floor(u_blur_radius * RADIUS_MULTIPLIER / 2.0); + + float sigma = u_blur_radius / 2.0; // *shrug* + initial_gaussian.x = 1.0 / (sqrt(2.0 * PI) * sigma); + initial_gaussian.y = exp(-0.5 / (sigma * sigma)); + initial_gaussian.z = initial_gaussian.y * initial_gaussian.y; +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// blur.glsl + +_IN_ vec2 pixel_step; +_IN_ float pixels_per_side; +_IN_ vec3 initial_gaussian; + +// blur_radius 0 is NOT supported and MUST be caught before. + +// Partially from http://callumhay.blogspot.com/2010/09/gaussian-blur-shader-glsl.html +void main() { + vec3 incrementalGaussian = initial_gaussian; + + float coefficientSum = 0.0; + vec4 sum = GskTexture(u_source, vUv) * incrementalGaussian.x; + coefficientSum += incrementalGaussian.x; + incrementalGaussian.xy *= incrementalGaussian.yz; + + vec2 p = pixel_step; + for (int i = 1; i <= int(pixels_per_side); i++) { + sum += GskTexture(u_source, vUv - p) * incrementalGaussian.x; + sum += GskTexture(u_source, vUv + p) * incrementalGaussian.x; + + coefficientSum += 2.0 * incrementalGaussian.x; + incrementalGaussian.xy *= incrementalGaussian.yz; + + p += pixel_step; + } + + gskSetOutputColor(sum / coefficientSum); +} + diff --git a/shaders/gtk4/24.shader_test b/shaders/gtk4/24.shader_test new file mode 100644 index 0000000..fdcfd45 --- /dev/null +++ b/shaders/gtk4/24.shader_test @@ -0,0 +1,417 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// blur.glsl + +uniform float u_blur_radius; +uniform vec2 u_blur_size; +uniform vec2 u_blur_dir; + +_OUT_ vec2 pixel_step; +_OUT_ float pixels_per_side; +_OUT_ vec3 initial_gaussian; + +const float PI = 3.14159265; +const float RADIUS_MULTIPLIER = 2.0; + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + vUv = vec2(aUv.x, aUv.y); + + pixel_step = (vec2(1.0) / u_blur_size) * u_blur_dir; + pixels_per_side = floor(u_blur_radius * RADIUS_MULTIPLIER / 2.0); + + float sigma = u_blur_radius / 2.0; // *shrug* + initial_gaussian.x = 1.0 / (sqrt(2.0 * PI) * sigma); + initial_gaussian.y = exp(-0.5 / (sigma * sigma)); + initial_gaussian.z = initial_gaussian.y * initial_gaussian.y; +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// blur.glsl + +_IN_ vec2 pixel_step; +_IN_ float pixels_per_side; +_IN_ vec3 initial_gaussian; + +// blur_radius 0 is NOT supported and MUST be caught before. + +// Partially from http://callumhay.blogspot.com/2010/09/gaussian-blur-shader-glsl.html +void main() { + vec3 incrementalGaussian = initial_gaussian; + + float coefficientSum = 0.0; + vec4 sum = GskTexture(u_source, vUv) * incrementalGaussian.x; + coefficientSum += incrementalGaussian.x; + incrementalGaussian.xy *= incrementalGaussian.yz; + + vec2 p = pixel_step; + for (int i = 1; i <= int(pixels_per_side); i++) { + sum += GskTexture(u_source, vUv - p) * incrementalGaussian.x; + sum += GskTexture(u_source, vUv + p) * incrementalGaussian.x; + + coefficientSum += 2.0 * incrementalGaussian.x; + incrementalGaussian.xy *= incrementalGaussian.yz; + + p += pixel_step; + } + + gskSetOutputColor(sum / coefficientSum); +} + diff --git a/shaders/gtk4/27.shader_test b/shaders/gtk4/27.shader_test new file mode 100644 index 0000000..732dbc3 --- /dev/null +++ b/shaders/gtk4/27.shader_test @@ -0,0 +1,415 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// blur.glsl + +uniform float u_blur_radius; +uniform vec2 u_blur_size; +uniform vec2 u_blur_dir; + +_OUT_ vec2 pixel_step; +_OUT_ float pixels_per_side; +_OUT_ vec3 initial_gaussian; + +const float PI = 3.14159265; +const float RADIUS_MULTIPLIER = 2.0; + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + vUv = vec2(aUv.x, aUv.y); + + pixel_step = (vec2(1.0) / u_blur_size) * u_blur_dir; + pixels_per_side = floor(u_blur_radius * RADIUS_MULTIPLIER / 2.0); + + float sigma = u_blur_radius / 2.0; // *shrug* + initial_gaussian.x = 1.0 / (sqrt(2.0 * PI) * sigma); + initial_gaussian.y = exp(-0.5 / (sigma * sigma)); + initial_gaussian.z = initial_gaussian.y * initial_gaussian.y; +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// blur.glsl + +_IN_ vec2 pixel_step; +_IN_ float pixels_per_side; +_IN_ vec3 initial_gaussian; + +// blur_radius 0 is NOT supported and MUST be caught before. + +// Partially from http://callumhay.blogspot.com/2010/09/gaussian-blur-shader-glsl.html +void main() { + vec3 incrementalGaussian = initial_gaussian; + + float coefficientSum = 0.0; + vec4 sum = GskTexture(u_source, vUv) * incrementalGaussian.x; + coefficientSum += incrementalGaussian.x; + incrementalGaussian.xy *= incrementalGaussian.yz; + + vec2 p = pixel_step; + for (int i = 1; i <= int(pixels_per_side); i++) { + sum += GskTexture(u_source, vUv - p) * incrementalGaussian.x; + sum += GskTexture(u_source, vUv + p) * incrementalGaussian.x; + + coefficientSum += 2.0 * incrementalGaussian.x; + incrementalGaussian.xy *= incrementalGaussian.yz; + + p += pixel_step; + } + + gskSetOutputColor(sum / coefficientSum); +} + diff --git a/shaders/gtk4/3.shader_test b/shaders/gtk4/3.shader_test new file mode 100644 index 0000000..60736a5 --- /dev/null +++ b/shaders/gtk4/3.shader_test @@ -0,0 +1,672 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// blend.glsl + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + vUv = vec2(aUv.x, aUv.y); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// blend.glsl + +uniform int u_mode; +uniform sampler2D u_source2; + +float +combine (float source, float backdrop) +{ + return source + backdrop * (1.0 - source); +} + +vec4 +composite (vec4 Cs, vec4 Cb, vec3 B) +{ + float ao = Cs.a + Cb.a * (1.0 - Cs.a); + vec3 Co = (Cs.a*(1.0 - Cb.a)*Cs.rgb + Cs.a*Cb.a*B + (1.0 - 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.0 * backdrop * source; + else + return 2.0 * (backdrop + source - backdrop * source) - 1.0; +} + +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.0 * backdrop - 12.0) * backdrop + 4.0) * backdrop; + else + db = sqrt (backdrop); + + if (source <= 0.5) + return backdrop - (1.0 - 2.0 * source) * backdrop * (1.0 - backdrop); + else + return backdrop + (2.0 * source - 1.0) * (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.0) c = l + (((c - l) * l) / (l - n)); + if (x > 1.0) c = l + (((c - l) * (1.0 - 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.0; + } + else + { + res.g = ((c.g - cmin) * s) / (cmax - cmin); + res.b = 0.0; + } + res.r = s; + } + else if (c.g == cmax) + { + if (c.r == cmin) + { + res.b = ((c.b - cmin) * s) / (cmax - cmin); + res.r = 0.0; + } + else + { + res.r = ((c.r - cmin) * s) / (cmax - cmin); + res.b = 0.0; + } + res.g = s; + } + else + { + if (c.r == cmin) + { + res.g = ((c.g - cmin) * s) / (cmax - cmin); + res.r = 0.0; + } + else + { + res.r = ((c.r - cmin) * s) / (cmax - cmin); + res.g = 0.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 = GskTexture(u_source, vUv); + vec4 top_color = GskTexture(u_source2, vUv); + + vec4 result; + if (u_mode == 0) + result = normal(top_color, bottom_color); + else if (u_mode == 1) + result = multiply(top_color, bottom_color); + else if (u_mode == 2) + result = screen(top_color, bottom_color); + else if (u_mode == 3) + result = overlay(top_color, bottom_color); + else if (u_mode == 4) + result = darken(top_color, bottom_color); + else if (u_mode == 5) + result = lighten(top_color, bottom_color); + else if (u_mode == 6) + result = color_dodge(top_color, bottom_color); + else if (u_mode == 7) + result = color_burn(top_color, bottom_color); + else if (u_mode == 8) + result = hard_light(top_color, bottom_color); + else if (u_mode == 9) + result = soft_light(top_color, bottom_color); + else if (u_mode == 10) + result = difference(top_color, bottom_color); + else if (u_mode == 11) + result = exclusion(top_color, bottom_color); + else if (u_mode == 12) + result = color(top_color, bottom_color); + else if (u_mode == 13) + result = hue(top_color, bottom_color); + else if (u_mode == 14) + result = saturation(top_color, bottom_color); + else if (u_mode == 15) + result = luminosity(top_color, bottom_color); + else + discard; + + gskSetScaledOutputColor(result, u_alpha); +} + diff --git a/shaders/gtk4/30.shader_test b/shaders/gtk4/30.shader_test new file mode 100644 index 0000000..77f5b88 --- /dev/null +++ b/shaders/gtk4/30.shader_test @@ -0,0 +1,401 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// border.glsl + +uniform vec4 u_widths; +uniform vec4[3] u_outline_rect; + +_OUT_ vec4 final_color; +_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + final_color = gsk_scaled_premultiply(aColor, u_alpha); + + GskRoundedRect outside = gsk_create_rect(u_outline_rect); + GskRoundedRect inside = gsk_rounded_rect_shrink (outside, u_widths); + + gsk_rounded_rect_transform(outside, u_modelview); + gsk_rounded_rect_transform(inside, u_modelview); + + gsk_rounded_rect_encode(outside, transformed_outside_outline); + gsk_rounded_rect_encode(inside, transformed_inside_outline); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// border.glsl + +uniform vec4[3] u_outline_rect; + +_IN_ vec4 final_color; +_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; + +void main() { + vec2 frag = gsk_get_frag_coord(); + + float alpha = clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outside_outline), frag) - + gsk_rounded_rect_coverage(gsk_decode_rect(transformed_inside_outline), frag), + 0.0, 1.0); + + gskSetScaledOutputColor(final_color, alpha); +} + diff --git a/shaders/gtk4/33.shader_test b/shaders/gtk4/33.shader_test new file mode 100644 index 0000000..85bf20b --- /dev/null +++ b/shaders/gtk4/33.shader_test @@ -0,0 +1,401 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// border.glsl + +uniform vec4 u_widths; +uniform vec4[3] u_outline_rect; + +_OUT_ vec4 final_color; +_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + final_color = gsk_scaled_premultiply(aColor, u_alpha); + + GskRoundedRect outside = gsk_create_rect(u_outline_rect); + GskRoundedRect inside = gsk_rounded_rect_shrink (outside, u_widths); + + gsk_rounded_rect_transform(outside, u_modelview); + gsk_rounded_rect_transform(inside, u_modelview); + + gsk_rounded_rect_encode(outside, transformed_outside_outline); + gsk_rounded_rect_encode(inside, transformed_inside_outline); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// border.glsl + +uniform vec4[3] u_outline_rect; + +_IN_ vec4 final_color; +_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; + +void main() { + vec2 frag = gsk_get_frag_coord(); + + float alpha = clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outside_outline), frag) - + gsk_rounded_rect_coverage(gsk_decode_rect(transformed_inside_outline), frag), + 0.0, 1.0); + + gskSetScaledOutputColor(final_color, alpha); +} + diff --git a/shaders/gtk4/36.shader_test b/shaders/gtk4/36.shader_test new file mode 100644 index 0000000..a878b1c --- /dev/null +++ b/shaders/gtk4/36.shader_test @@ -0,0 +1,399 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// border.glsl + +uniform vec4 u_widths; +uniform vec4[3] u_outline_rect; + +_OUT_ vec4 final_color; +_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + final_color = gsk_scaled_premultiply(aColor, u_alpha); + + GskRoundedRect outside = gsk_create_rect(u_outline_rect); + GskRoundedRect inside = gsk_rounded_rect_shrink (outside, u_widths); + + gsk_rounded_rect_transform(outside, u_modelview); + gsk_rounded_rect_transform(inside, u_modelview); + + gsk_rounded_rect_encode(outside, transformed_outside_outline); + gsk_rounded_rect_encode(inside, transformed_inside_outline); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// border.glsl + +uniform vec4[3] u_outline_rect; + +_IN_ vec4 final_color; +_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; + +void main() { + vec2 frag = gsk_get_frag_coord(); + + float alpha = clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outside_outline), frag) - + gsk_rounded_rect_coverage(gsk_decode_rect(transformed_inside_outline), frag), + 0.0, 1.0); + + gskSetScaledOutputColor(final_color, alpha); +} + diff --git a/shaders/gtk4/39.shader_test b/shaders/gtk4/39.shader_test new file mode 100644 index 0000000..b28d6e1 --- /dev/null +++ b/shaders/gtk4/39.shader_test @@ -0,0 +1,378 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// color.glsl + +_OUT_ vec4 final_color; + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + final_color = gsk_scaled_premultiply(aColor, u_alpha); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// color.glsl + +_IN_ vec4 final_color; + +void main() { + gskSetOutputColor(final_color); +} + + diff --git a/shaders/gtk4/42.shader_test b/shaders/gtk4/42.shader_test new file mode 100644 index 0000000..68074ec --- /dev/null +++ b/shaders/gtk4/42.shader_test @@ -0,0 +1,378 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// color.glsl + +_OUT_ vec4 final_color; + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + final_color = gsk_scaled_premultiply(aColor, u_alpha); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// color.glsl + +_IN_ vec4 final_color; + +void main() { + gskSetOutputColor(final_color); +} + + diff --git a/shaders/gtk4/45.shader_test b/shaders/gtk4/45.shader_test new file mode 100644 index 0000000..6d75cdf --- /dev/null +++ b/shaders/gtk4/45.shader_test @@ -0,0 +1,376 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// color.glsl + +_OUT_ vec4 final_color; + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + final_color = gsk_scaled_premultiply(aColor, u_alpha); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// color.glsl + +_IN_ vec4 final_color; + +void main() { + gskSetOutputColor(final_color); +} + + diff --git a/shaders/gtk4/48.shader_test b/shaders/gtk4/48.shader_test new file mode 100644 index 0000000..fa63ae3 --- /dev/null +++ b/shaders/gtk4/48.shader_test @@ -0,0 +1,391 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// coloring.glsl + +_OUT_ vec4 final_color; +_OUT_ float use_color; + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + vUv = vec2(aUv.x, aUv.y); + + // We use this shader for both plain glyphs (used as mask) + // and color glpyhs (used as source). The renderer sets + // aColor to vec4(-1) for color glyhs. + if (distance(aColor,vec4(-1)) < 0.1) + use_color = 0.0; + else + use_color = 1.0; + + final_color = gsk_scaled_premultiply(aColor, u_alpha); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// coloring.glsl + +_IN_ vec4 final_color; +_IN_ float use_color; + +void main() { + vec4 diffuse = GskTexture(u_source, vUv); + + gskSetOutputColor(mix(diffuse * u_alpha, final_color * diffuse.a, use_color)); +} + diff --git a/shaders/gtk4/51.shader_test b/shaders/gtk4/51.shader_test new file mode 100644 index 0000000..58b3a04 --- /dev/null +++ b/shaders/gtk4/51.shader_test @@ -0,0 +1,391 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// coloring.glsl + +_OUT_ vec4 final_color; +_OUT_ float use_color; + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + vUv = vec2(aUv.x, aUv.y); + + // We use this shader for both plain glyphs (used as mask) + // and color glpyhs (used as source). The renderer sets + // aColor to vec4(-1) for color glyhs. + if (distance(aColor,vec4(-1)) < 0.1) + use_color = 0.0; + else + use_color = 1.0; + + final_color = gsk_scaled_premultiply(aColor, u_alpha); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// coloring.glsl + +_IN_ vec4 final_color; +_IN_ float use_color; + +void main() { + vec4 diffuse = GskTexture(u_source, vUv); + + gskSetOutputColor(mix(diffuse * u_alpha, final_color * diffuse.a, use_color)); +} + diff --git a/shaders/gtk4/54.shader_test b/shaders/gtk4/54.shader_test new file mode 100644 index 0000000..c62fc1c --- /dev/null +++ b/shaders/gtk4/54.shader_test @@ -0,0 +1,389 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// coloring.glsl + +_OUT_ vec4 final_color; +_OUT_ float use_color; + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + vUv = vec2(aUv.x, aUv.y); + + // We use this shader for both plain glyphs (used as mask) + // and color glpyhs (used as source). The renderer sets + // aColor to vec4(-1) for color glyhs. + if (distance(aColor,vec4(-1)) < 0.1) + use_color = 0.0; + else + use_color = 1.0; + + final_color = gsk_scaled_premultiply(aColor, u_alpha); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// coloring.glsl + +_IN_ vec4 final_color; +_IN_ float use_color; + +void main() { + vec4 diffuse = GskTexture(u_source, vUv); + + gskSetOutputColor(mix(diffuse * u_alpha, final_color * diffuse.a, use_color)); +} + diff --git a/shaders/gtk4/57.shader_test b/shaders/gtk4/57.shader_test new file mode 100644 index 0000000..241bdf0 --- /dev/null +++ b/shaders/gtk4/57.shader_test @@ -0,0 +1,385 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// color_matrix.glsl + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + vUv = vec2(aUv.x, aUv.y); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// color_matrix.glsl + +uniform mat4 u_color_matrix; +uniform vec4 u_color_offset; + +void main() { + vec4 color = GskTexture(u_source, vUv); + + // Un-premultilpy + if (color.a != 0.0) + color.rgb /= color.a; + + color = u_color_matrix * color + u_color_offset; + color = clamp(color, 0.0, 1.0); + + gskSetOutputColor(gsk_scaled_premultiply(color, u_alpha)); +} + diff --git a/shaders/gtk4/6.shader_test b/shaders/gtk4/6.shader_test new file mode 100644 index 0000000..16287d8 --- /dev/null +++ b/shaders/gtk4/6.shader_test @@ -0,0 +1,672 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// blend.glsl + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + vUv = vec2(aUv.x, aUv.y); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// blend.glsl + +uniform int u_mode; +uniform sampler2D u_source2; + +float +combine (float source, float backdrop) +{ + return source + backdrop * (1.0 - source); +} + +vec4 +composite (vec4 Cs, vec4 Cb, vec3 B) +{ + float ao = Cs.a + Cb.a * (1.0 - Cs.a); + vec3 Co = (Cs.a*(1.0 - Cb.a)*Cs.rgb + Cs.a*Cb.a*B + (1.0 - 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.0 * backdrop * source; + else + return 2.0 * (backdrop + source - backdrop * source) - 1.0; +} + +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.0 * backdrop - 12.0) * backdrop + 4.0) * backdrop; + else + db = sqrt (backdrop); + + if (source <= 0.5) + return backdrop - (1.0 - 2.0 * source) * backdrop * (1.0 - backdrop); + else + return backdrop + (2.0 * source - 1.0) * (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.0) c = l + (((c - l) * l) / (l - n)); + if (x > 1.0) c = l + (((c - l) * (1.0 - 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.0; + } + else + { + res.g = ((c.g - cmin) * s) / (cmax - cmin); + res.b = 0.0; + } + res.r = s; + } + else if (c.g == cmax) + { + if (c.r == cmin) + { + res.b = ((c.b - cmin) * s) / (cmax - cmin); + res.r = 0.0; + } + else + { + res.r = ((c.r - cmin) * s) / (cmax - cmin); + res.b = 0.0; + } + res.g = s; + } + else + { + if (c.r == cmin) + { + res.g = ((c.g - cmin) * s) / (cmax - cmin); + res.r = 0.0; + } + else + { + res.r = ((c.r - cmin) * s) / (cmax - cmin); + res.g = 0.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 = GskTexture(u_source, vUv); + vec4 top_color = GskTexture(u_source2, vUv); + + vec4 result; + if (u_mode == 0) + result = normal(top_color, bottom_color); + else if (u_mode == 1) + result = multiply(top_color, bottom_color); + else if (u_mode == 2) + result = screen(top_color, bottom_color); + else if (u_mode == 3) + result = overlay(top_color, bottom_color); + else if (u_mode == 4) + result = darken(top_color, bottom_color); + else if (u_mode == 5) + result = lighten(top_color, bottom_color); + else if (u_mode == 6) + result = color_dodge(top_color, bottom_color); + else if (u_mode == 7) + result = color_burn(top_color, bottom_color); + else if (u_mode == 8) + result = hard_light(top_color, bottom_color); + else if (u_mode == 9) + result = soft_light(top_color, bottom_color); + else if (u_mode == 10) + result = difference(top_color, bottom_color); + else if (u_mode == 11) + result = exclusion(top_color, bottom_color); + else if (u_mode == 12) + result = color(top_color, bottom_color); + else if (u_mode == 13) + result = hue(top_color, bottom_color); + else if (u_mode == 14) + result = saturation(top_color, bottom_color); + else if (u_mode == 15) + result = luminosity(top_color, bottom_color); + else + discard; + + gskSetScaledOutputColor(result, u_alpha); +} + diff --git a/shaders/gtk4/60.shader_test b/shaders/gtk4/60.shader_test new file mode 100644 index 0000000..851bdfd --- /dev/null +++ b/shaders/gtk4/60.shader_test @@ -0,0 +1,385 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// color_matrix.glsl + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + vUv = vec2(aUv.x, aUv.y); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// color_matrix.glsl + +uniform mat4 u_color_matrix; +uniform vec4 u_color_offset; + +void main() { + vec4 color = GskTexture(u_source, vUv); + + // Un-premultilpy + if (color.a != 0.0) + color.rgb /= color.a; + + color = u_color_matrix * color + u_color_offset; + color = clamp(color, 0.0, 1.0); + + gskSetOutputColor(gsk_scaled_premultiply(color, u_alpha)); +} + diff --git a/shaders/gtk4/63.shader_test b/shaders/gtk4/63.shader_test new file mode 100644 index 0000000..346ec78 --- /dev/null +++ b/shaders/gtk4/63.shader_test @@ -0,0 +1,383 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// color_matrix.glsl + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + vUv = vec2(aUv.x, aUv.y); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// color_matrix.glsl + +uniform mat4 u_color_matrix; +uniform vec4 u_color_offset; + +void main() { + vec4 color = GskTexture(u_source, vUv); + + // Un-premultilpy + if (color.a != 0.0) + color.rgb /= color.a; + + color = u_color_matrix * color + u_color_offset; + color = clamp(color, 0.0, 1.0); + + gskSetOutputColor(gsk_scaled_premultiply(color, u_alpha)); +} + diff --git a/shaders/gtk4/66.shader_test b/shaders/gtk4/66.shader_test new file mode 100644 index 0000000..71cbdaf --- /dev/null +++ b/shaders/gtk4/66.shader_test @@ -0,0 +1,443 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// conic_gradient.glsl + +uniform vec4 u_geometry; + +_OUT_ vec2 coord; + +void main() { + gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0)); + + vec2 mv0 = u_modelview[0].xy; + vec2 mv1 = u_modelview[1].xy; + vec2 offset = aPosition - u_geometry.xy; + + coord = vec2(dot(mv0, offset), dot(mv1, offset)); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// conic_gradient.glsl + +#define MAX_COLOR_STOPS 6 + +#ifdef GSK_LEGACY +uniform int u_num_color_stops; +#else +uniform highp int u_num_color_stops; // Why? Because it works like this. +#endif + +uniform vec4 u_geometry; +uniform float u_color_stops[MAX_COLOR_STOPS * 5]; + +_IN_ vec2 coord; + +float get_offset(int index) { + // u_color_stops[5 * index] makes Intel Windows driver crash. + // See https://gitlab.gnome.org/GNOME/gtk/-/issues/3783 + int base = 5 * index; + return u_color_stops[base]; +} + +vec4 get_color(int index) { + int base = 5 * index + 1; + + return vec4(u_color_stops[base], + u_color_stops[base + 1], + u_color_stops[base + 2], + u_color_stops[base + 3]); +} + +void main() { + // direction of point in range [-PI, PI] + vec2 pos = floor(coord); + float angle = atan(pos.y, pos.x); + + // fract() does the modulo here, so now we have progress + // into the current conic + float offset = fract(angle * u_geometry.z + u_geometry.w); + float curr_offset; + float next_offset; + + next_offset = get_offset(0); + if (offset < next_offset) { + gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha)); + return; + } + + if (offset >= get_offset(u_num_color_stops - 1)) { + gskSetOutputColor(gsk_scaled_premultiply(get_color(u_num_color_stops - 1), u_alpha)); + return; + } + + for (int i = 0; i < MAX_COLOR_STOPS; i++) { + curr_offset = next_offset; + next_offset = get_offset(i + 1); + + if (offset < next_offset) { + float f = (offset - curr_offset) / (next_offset - curr_offset); + vec4 curr_color = gsk_premultiply(get_color(i)); + vec4 next_color = gsk_premultiply(get_color(i + 1)); + vec4 color = mix(curr_color, next_color, f); + gskSetScaledOutputColor(color, u_alpha); + return; + } + } +} + diff --git a/shaders/gtk4/69.shader_test b/shaders/gtk4/69.shader_test new file mode 100644 index 0000000..bad2c31 --- /dev/null +++ b/shaders/gtk4/69.shader_test @@ -0,0 +1,443 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// conic_gradient.glsl + +uniform vec4 u_geometry; + +_OUT_ vec2 coord; + +void main() { + gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0)); + + vec2 mv0 = u_modelview[0].xy; + vec2 mv1 = u_modelview[1].xy; + vec2 offset = aPosition - u_geometry.xy; + + coord = vec2(dot(mv0, offset), dot(mv1, offset)); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// conic_gradient.glsl + +#define MAX_COLOR_STOPS 6 + +#ifdef GSK_LEGACY +uniform int u_num_color_stops; +#else +uniform highp int u_num_color_stops; // Why? Because it works like this. +#endif + +uniform vec4 u_geometry; +uniform float u_color_stops[MAX_COLOR_STOPS * 5]; + +_IN_ vec2 coord; + +float get_offset(int index) { + // u_color_stops[5 * index] makes Intel Windows driver crash. + // See https://gitlab.gnome.org/GNOME/gtk/-/issues/3783 + int base = 5 * index; + return u_color_stops[base]; +} + +vec4 get_color(int index) { + int base = 5 * index + 1; + + return vec4(u_color_stops[base], + u_color_stops[base + 1], + u_color_stops[base + 2], + u_color_stops[base + 3]); +} + +void main() { + // direction of point in range [-PI, PI] + vec2 pos = floor(coord); + float angle = atan(pos.y, pos.x); + + // fract() does the modulo here, so now we have progress + // into the current conic + float offset = fract(angle * u_geometry.z + u_geometry.w); + float curr_offset; + float next_offset; + + next_offset = get_offset(0); + if (offset < next_offset) { + gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha)); + return; + } + + if (offset >= get_offset(u_num_color_stops - 1)) { + gskSetOutputColor(gsk_scaled_premultiply(get_color(u_num_color_stops - 1), u_alpha)); + return; + } + + for (int i = 0; i < MAX_COLOR_STOPS; i++) { + curr_offset = next_offset; + next_offset = get_offset(i + 1); + + if (offset < next_offset) { + float f = (offset - curr_offset) / (next_offset - curr_offset); + vec4 curr_color = gsk_premultiply(get_color(i)); + vec4 next_color = gsk_premultiply(get_color(i + 1)); + vec4 color = mix(curr_color, next_color, f); + gskSetScaledOutputColor(color, u_alpha); + return; + } + } +} + diff --git a/shaders/gtk4/72.shader_test b/shaders/gtk4/72.shader_test new file mode 100644 index 0000000..a0a382d --- /dev/null +++ b/shaders/gtk4/72.shader_test @@ -0,0 +1,441 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// conic_gradient.glsl + +uniform vec4 u_geometry; + +_OUT_ vec2 coord; + +void main() { + gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0)); + + vec2 mv0 = u_modelview[0].xy; + vec2 mv1 = u_modelview[1].xy; + vec2 offset = aPosition - u_geometry.xy; + + coord = vec2(dot(mv0, offset), dot(mv1, offset)); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// conic_gradient.glsl + +#define MAX_COLOR_STOPS 6 + +#ifdef GSK_LEGACY +uniform int u_num_color_stops; +#else +uniform highp int u_num_color_stops; // Why? Because it works like this. +#endif + +uniform vec4 u_geometry; +uniform float u_color_stops[MAX_COLOR_STOPS * 5]; + +_IN_ vec2 coord; + +float get_offset(int index) { + // u_color_stops[5 * index] makes Intel Windows driver crash. + // See https://gitlab.gnome.org/GNOME/gtk/-/issues/3783 + int base = 5 * index; + return u_color_stops[base]; +} + +vec4 get_color(int index) { + int base = 5 * index + 1; + + return vec4(u_color_stops[base], + u_color_stops[base + 1], + u_color_stops[base + 2], + u_color_stops[base + 3]); +} + +void main() { + // direction of point in range [-PI, PI] + vec2 pos = floor(coord); + float angle = atan(pos.y, pos.x); + + // fract() does the modulo here, so now we have progress + // into the current conic + float offset = fract(angle * u_geometry.z + u_geometry.w); + float curr_offset; + float next_offset; + + next_offset = get_offset(0); + if (offset < next_offset) { + gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha)); + return; + } + + if (offset >= get_offset(u_num_color_stops - 1)) { + gskSetOutputColor(gsk_scaled_premultiply(get_color(u_num_color_stops - 1), u_alpha)); + return; + } + + for (int i = 0; i < MAX_COLOR_STOPS; i++) { + curr_offset = next_offset; + next_offset = get_offset(i + 1); + + if (offset < next_offset) { + float f = (offset - curr_offset) / (next_offset - curr_offset); + vec4 curr_color = gsk_premultiply(get_color(i)); + vec4 next_color = gsk_premultiply(get_color(i + 1)); + vec4 color = mix(curr_color, next_color, f); + gskSetScaledOutputColor(color, u_alpha); + return; + } + } +} + diff --git a/shaders/gtk4/75.shader_test b/shaders/gtk4/75.shader_test new file mode 100644 index 0000000..d1529bc --- /dev/null +++ b/shaders/gtk4/75.shader_test @@ -0,0 +1,382 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// cross_fade.glsl + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + vUv = vec2(aUv.x, aUv.y); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// cross_fade.glsl + +uniform float u_progress; +uniform sampler2D u_source2; + +void main() { + vec4 source1 = GskTexture(u_source, vUv); // start child + vec4 source2 = GskTexture(u_source2, vUv); // end child + + float p_start = (1.0 - u_progress) * u_alpha; + float p_end = u_progress * u_alpha; + vec4 color = (p_start * source1) + (p_end * source2); + gskSetOutputColor(color); +} + diff --git a/shaders/gtk4/78.shader_test b/shaders/gtk4/78.shader_test new file mode 100644 index 0000000..d9ccdb8 --- /dev/null +++ b/shaders/gtk4/78.shader_test @@ -0,0 +1,382 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// cross_fade.glsl + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + vUv = vec2(aUv.x, aUv.y); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// cross_fade.glsl + +uniform float u_progress; +uniform sampler2D u_source2; + +void main() { + vec4 source1 = GskTexture(u_source, vUv); // start child + vec4 source2 = GskTexture(u_source2, vUv); // end child + + float p_start = (1.0 - u_progress) * u_alpha; + float p_end = u_progress * u_alpha; + vec4 color = (p_start * source1) + (p_end * source2); + gskSetOutputColor(color); +} + diff --git a/shaders/gtk4/81.shader_test b/shaders/gtk4/81.shader_test new file mode 100644 index 0000000..284dab6 --- /dev/null +++ b/shaders/gtk4/81.shader_test @@ -0,0 +1,380 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// cross_fade.glsl + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + vUv = vec2(aUv.x, aUv.y); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// cross_fade.glsl + +uniform float u_progress; +uniform sampler2D u_source2; + +void main() { + vec4 source1 = GskTexture(u_source, vUv); // start child + vec4 source2 = GskTexture(u_source2, vUv); // end child + + float p_start = (1.0 - u_progress) * u_alpha; + float p_end = u_progress * u_alpha; + vec4 color = (p_start * source1) + (p_end * source2); + gskSetOutputColor(color); +} + diff --git a/shaders/gtk4/84.shader_test b/shaders/gtk4/84.shader_test new file mode 100644 index 0000000..af9464a --- /dev/null +++ b/shaders/gtk4/84.shader_test @@ -0,0 +1,405 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// filled_border.glsl + +uniform vec4 u_widths; +uniform vec4[3] u_outline_rect; + +_OUT_ vec4 outer_color; +_OUT_ vec4 inner_color; +_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + outer_color = gsk_scaled_premultiply(aColor, u_alpha); + inner_color = gsk_scaled_premultiply(aColor2, u_alpha); + + GskRoundedRect outside = gsk_create_rect(u_outline_rect); + GskRoundedRect inside = gsk_rounded_rect_shrink (outside, u_widths); + + gsk_rounded_rect_transform(outside, u_modelview); + gsk_rounded_rect_transform(inside, u_modelview); + + gsk_rounded_rect_encode(outside, transformed_outside_outline); + gsk_rounded_rect_encode(inside, transformed_inside_outline); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// filled_border.glsl + +uniform vec4[3] u_outline_rect; + +_IN_ vec4 outer_color; +_IN_ vec4 inner_color; +_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; + +void main() { + vec2 frag = gsk_get_frag_coord(); + float outer_coverage = gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outside_outline), frag); + float inner_coverage = gsk_rounded_rect_coverage(gsk_decode_rect(transformed_inside_outline), frag); + + float alpha = clamp(outer_coverage - inner_coverage, 0.0, 1.0); + float alpha2 = clamp(inner_coverage, 0.0, 1.0); + + gskSetOutputColor((outer_color * alpha) + (inner_color * alpha2)); +} + diff --git a/shaders/gtk4/87.shader_test b/shaders/gtk4/87.shader_test new file mode 100644 index 0000000..abba338 --- /dev/null +++ b/shaders/gtk4/87.shader_test @@ -0,0 +1,405 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// filled_border.glsl + +uniform vec4 u_widths; +uniform vec4[3] u_outline_rect; + +_OUT_ vec4 outer_color; +_OUT_ vec4 inner_color; +_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + outer_color = gsk_scaled_premultiply(aColor, u_alpha); + inner_color = gsk_scaled_premultiply(aColor2, u_alpha); + + GskRoundedRect outside = gsk_create_rect(u_outline_rect); + GskRoundedRect inside = gsk_rounded_rect_shrink (outside, u_widths); + + gsk_rounded_rect_transform(outside, u_modelview); + gsk_rounded_rect_transform(inside, u_modelview); + + gsk_rounded_rect_encode(outside, transformed_outside_outline); + gsk_rounded_rect_encode(inside, transformed_inside_outline); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// filled_border.glsl + +uniform vec4[3] u_outline_rect; + +_IN_ vec4 outer_color; +_IN_ vec4 inner_color; +_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; + +void main() { + vec2 frag = gsk_get_frag_coord(); + float outer_coverage = gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outside_outline), frag); + float inner_coverage = gsk_rounded_rect_coverage(gsk_decode_rect(transformed_inside_outline), frag); + + float alpha = clamp(outer_coverage - inner_coverage, 0.0, 1.0); + float alpha2 = clamp(inner_coverage, 0.0, 1.0); + + gskSetOutputColor((outer_color * alpha) + (inner_color * alpha2)); +} + diff --git a/shaders/gtk4/9.shader_test b/shaders/gtk4/9.shader_test new file mode 100644 index 0000000..418a21e --- /dev/null +++ b/shaders/gtk4/9.shader_test @@ -0,0 +1,670 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// blend.glsl + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + vUv = vec2(aUv.x, aUv.y); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// blend.glsl + +uniform int u_mode; +uniform sampler2D u_source2; + +float +combine (float source, float backdrop) +{ + return source + backdrop * (1.0 - source); +} + +vec4 +composite (vec4 Cs, vec4 Cb, vec3 B) +{ + float ao = Cs.a + Cb.a * (1.0 - Cs.a); + vec3 Co = (Cs.a*(1.0 - Cb.a)*Cs.rgb + Cs.a*Cb.a*B + (1.0 - 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.0 * backdrop * source; + else + return 2.0 * (backdrop + source - backdrop * source) - 1.0; +} + +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.0 * backdrop - 12.0) * backdrop + 4.0) * backdrop; + else + db = sqrt (backdrop); + + if (source <= 0.5) + return backdrop - (1.0 - 2.0 * source) * backdrop * (1.0 - backdrop); + else + return backdrop + (2.0 * source - 1.0) * (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.0) c = l + (((c - l) * l) / (l - n)); + if (x > 1.0) c = l + (((c - l) * (1.0 - 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.0; + } + else + { + res.g = ((c.g - cmin) * s) / (cmax - cmin); + res.b = 0.0; + } + res.r = s; + } + else if (c.g == cmax) + { + if (c.r == cmin) + { + res.b = ((c.b - cmin) * s) / (cmax - cmin); + res.r = 0.0; + } + else + { + res.r = ((c.r - cmin) * s) / (cmax - cmin); + res.b = 0.0; + } + res.g = s; + } + else + { + if (c.r == cmin) + { + res.g = ((c.g - cmin) * s) / (cmax - cmin); + res.r = 0.0; + } + else + { + res.r = ((c.r - cmin) * s) / (cmax - cmin); + res.g = 0.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 = GskTexture(u_source, vUv); + vec4 top_color = GskTexture(u_source2, vUv); + + vec4 result; + if (u_mode == 0) + result = normal(top_color, bottom_color); + else if (u_mode == 1) + result = multiply(top_color, bottom_color); + else if (u_mode == 2) + result = screen(top_color, bottom_color); + else if (u_mode == 3) + result = overlay(top_color, bottom_color); + else if (u_mode == 4) + result = darken(top_color, bottom_color); + else if (u_mode == 5) + result = lighten(top_color, bottom_color); + else if (u_mode == 6) + result = color_dodge(top_color, bottom_color); + else if (u_mode == 7) + result = color_burn(top_color, bottom_color); + else if (u_mode == 8) + result = hard_light(top_color, bottom_color); + else if (u_mode == 9) + result = soft_light(top_color, bottom_color); + else if (u_mode == 10) + result = difference(top_color, bottom_color); + else if (u_mode == 11) + result = exclusion(top_color, bottom_color); + else if (u_mode == 12) + result = color(top_color, bottom_color); + else if (u_mode == 13) + result = hue(top_color, bottom_color); + else if (u_mode == 14) + result = saturation(top_color, bottom_color); + else if (u_mode == 15) + result = luminosity(top_color, bottom_color); + else + discard; + + gskSetScaledOutputColor(result, u_alpha); +} + diff --git a/shaders/gtk4/90.shader_test b/shaders/gtk4/90.shader_test new file mode 100644 index 0000000..8e820ba --- /dev/null +++ b/shaders/gtk4/90.shader_test @@ -0,0 +1,403 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// filled_border.glsl + +uniform vec4 u_widths; +uniform vec4[3] u_outline_rect; + +_OUT_ vec4 outer_color; +_OUT_ vec4 inner_color; +_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + outer_color = gsk_scaled_premultiply(aColor, u_alpha); + inner_color = gsk_scaled_premultiply(aColor2, u_alpha); + + GskRoundedRect outside = gsk_create_rect(u_outline_rect); + GskRoundedRect inside = gsk_rounded_rect_shrink (outside, u_widths); + + gsk_rounded_rect_transform(outside, u_modelview); + gsk_rounded_rect_transform(inside, u_modelview); + + gsk_rounded_rect_encode(outside, transformed_outside_outline); + gsk_rounded_rect_encode(inside, transformed_inside_outline); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// filled_border.glsl + +uniform vec4[3] u_outline_rect; + +_IN_ vec4 outer_color; +_IN_ vec4 inner_color; +_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; + +void main() { + vec2 frag = gsk_get_frag_coord(); + float outer_coverage = gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outside_outline), frag); + float inner_coverage = gsk_rounded_rect_coverage(gsk_decode_rect(transformed_inside_outline), frag); + + float alpha = clamp(outer_coverage - inner_coverage, 0.0, 1.0); + float alpha2 = clamp(inner_coverage, 0.0, 1.0); + + gskSetOutputColor((outer_color * alpha) + (inner_color * alpha2)); +} + diff --git a/shaders/gtk4/93.shader_test b/shaders/gtk4/93.shader_test new file mode 100644 index 0000000..91128de --- /dev/null +++ b/shaders/gtk4/93.shader_test @@ -0,0 +1,402 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// inset_shadow.glsl + +uniform float u_spread; +uniform vec2 u_offset; +uniform vec4[3] u_outline_rect; + +_OUT_ vec4 final_color; +_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + final_color = gsk_scaled_premultiply(aColor, u_alpha); + + GskRoundedRect outside = gsk_create_rect(u_outline_rect); + GskRoundedRect inside = gsk_rounded_rect_shrink(outside, vec4(u_spread)); + + gsk_rounded_rect_offset(inside, u_offset); + + gsk_rounded_rect_transform(outside, u_modelview); + gsk_rounded_rect_transform(inside, u_modelview); + + gsk_rounded_rect_encode(outside, transformed_outside_outline); + gsk_rounded_rect_encode(inside, transformed_inside_outline); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define NO_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// inset_shadow.glsl + +_IN_ vec4 final_color; +_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; + +void main() { + vec2 frag = gsk_get_frag_coord(); + + float alpha = clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outside_outline), frag) - + gsk_rounded_rect_coverage(gsk_decode_rect(transformed_inside_outline), frag), + 0.0, 1.0); + + gskSetScaledOutputColor(final_color, alpha); +} + diff --git a/shaders/gtk4/96.shader_test b/shaders/gtk4/96.shader_test new file mode 100644 index 0000000..453c171 --- /dev/null +++ b/shaders/gtk4/96.shader_test @@ -0,0 +1,402 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// inset_shadow.glsl + +uniform float u_spread; +uniform vec2 u_offset; +uniform vec4[3] u_outline_rect; + +_OUT_ vec4 final_color; +_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + final_color = gsk_scaled_premultiply(aColor, u_alpha); + + GskRoundedRect outside = gsk_create_rect(u_outline_rect); + GskRoundedRect inside = gsk_rounded_rect_shrink(outside, vec4(u_spread)); + + gsk_rounded_rect_offset(inside, u_offset); + + gsk_rounded_rect_transform(outside, u_modelview); + gsk_rounded_rect_transform(inside, u_modelview); + + gsk_rounded_rect_encode(outside, transformed_outside_outline); + gsk_rounded_rect_encode(inside, transformed_inside_outline); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#define RECT_CLIP 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// inset_shadow.glsl + +_IN_ vec4 final_color; +_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; + +void main() { + vec2 frag = gsk_get_frag_coord(); + + float alpha = clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outside_outline), frag) - + gsk_rounded_rect_coverage(gsk_decode_rect(transformed_inside_outline), frag), + 0.0, 1.0); + + gskSetScaledOutputColor(final_color, alpha); +} + diff --git a/shaders/gtk4/99.shader_test b/shaders/gtk4/99.shader_test new file mode 100644 index 0000000..604eb93 --- /dev/null +++ b/shaders/gtk4/99.shader_test @@ -0,0 +1,400 @@ +[require] +GLSL >= 1.50 + +[vertex shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +attribute vec2 aPosition; +attribute vec2 aUv; +attribute vec4 aColor; +attribute vec4 aColor2; +_OUT_ vec2 vUv; +#else +_IN_ vec2 aPosition; +_IN_ vec2 aUv; +_IN_ vec4 aColor; +_IN_ vec4 aColor2; +_OUT_ vec2 vUv; +#endif + +// amount is: top, right, bottom, left +GskRoundedRect +gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif + +// inset_shadow.glsl + +uniform float u_spread; +uniform vec2 u_offset; +uniform vec4[3] u_outline_rect; + +_OUT_ vec4 final_color; +_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + final_color = gsk_scaled_premultiply(aColor, u_alpha); + + GskRoundedRect outside = gsk_create_rect(u_outline_rect); + GskRoundedRect inside = gsk_rounded_rect_shrink(outside, vec4(u_spread)); + + gsk_rounded_rect_offset(inside, u_offset); + + gsk_rounded_rect_transform(outside, u_modelview); + gsk_rounded_rect_transform(inside, u_modelview); + + gsk_rounded_rect_encode(outside, transformed_outside_outline); + gsk_rounded_rect_encode(inside, transformed_inside_outline); +} + +// FRAGMENT_SHADER: +[fragment shader] +#version 150 +#define GSK_GL3 1 +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect +#endif + + +struct GskRoundedRect +{ + vec4 bounds; // Top left and bottom right + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a C GskRoundedRect to what we need. +GskRoundedRect +gsk_create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return GskRoundedRect(bounds, corner_points1, corner_points2); +} + +vec4 +gsk_get_bounds(vec4[3] data) +{ + return vec4(data[0].xy, data[0].xy + data[0].zw); +} + +vec4 gsk_premultiply(vec4 c) { + return vec4(c.rgb * c.a, c.a); +} + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} +uniform sampler2D u_source; +uniform mat4 u_projection; +uniform mat4 u_modelview; +uniform float u_alpha; +uniform vec4 u_viewport; +uniform vec4[3] u_clip_rect; + +#if defined(GSK_LEGACY) +_OUT_ vec4 outputColor; +#elif !defined(GSK_GLES) +_OUT_ vec4 outputColor; +#endif + +_IN_ vec2 vUv; + + +GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) +{ +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return GskRoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif +} + +float +gsk_ellipsis_dist (vec2 p, vec2 radius) +{ + if (radius == vec2(0, 0)) + return 0.0; + + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = gsk_ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +gsk_rounded_rect_coverage (GskRoundedRect 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 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; + + if (p.x >= ref_tl.x && p.x >= ref_bl.x && + p.x <= ref_tr.x && p.x <= ref_br.x) + return 1.0; + + if (p.y >= ref_tl.y && p.y >= ref_tr.y && + p.y <= ref_bl.y && p.y <= ref_br.y) + return 1.0; + + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; + + float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); + float d_bl = gsk_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); +} + +float +gsk_rect_coverage (vec4 r, vec2 p) +{ + if (p.x < r.x || p.y < r.y || + p.x >= r.z || p.y >= r.w) + return 0.0; + + return 1.0; +} + +vec4 GskTexture(sampler2D sampler, vec2 texCoords) { +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return texture2D(sampler, texCoords); +#else + return texture(sampler, texCoords); +#endif +} + +#ifdef GSK_GL3 +layout(origin_upper_left) in vec4 gl_FragCoord; +#endif + +vec2 gsk_get_frag_coord() { + vec2 fc = gl_FragCoord.xy; + +#ifdef GSK_GL3 + fc += u_viewport.xy; +#else + fc.x += u_viewport.x; + fc.y = (u_viewport.y + u_viewport.w) - fc.y; +#endif + + return fc; +} + +void gskSetOutputColor(vec4 color) { + vec4 result; + +#if defined(NO_CLIP) + result = color; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * coverage; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +void gskSetScaledOutputColor(vec4 color, float alpha) { + vec4 result; + +#if defined(NO_CLIP) + result = color * alpha; +#elif defined(RECT_CLIP) + float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#else + float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), + gsk_get_frag_coord()); + result = color * (alpha * coverage); +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) + gl_FragColor = result; +#else + outputColor = result; +#endif +} + +// inset_shadow.glsl + +_IN_ vec4 final_color; +_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; + +void main() { + vec2 frag = gsk_get_frag_coord(); + + float alpha = clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outside_outline), frag) - + gsk_rounded_rect_coverage(gsk_decode_rect(transformed_inside_outline), frag), + 0.0, 1.0); + + gskSetScaledOutputColor(final_color, alpha); +} + |