diff options
Diffstat (limited to 'shaders/gtk4/69.shader_test')
-rw-r--r-- | shaders/gtk4/69.shader_test | 443 |
1 files changed, 443 insertions, 0 deletions
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; + } + } +} + |