gtk/gsk/gpu/shaders/pattern.glsl
2024-01-07 07:22:50 +01:00

369 lines
9.1 KiB
GLSL

#ifndef _PATTERN_
#define _PATTERN_
#include "common.glsl"
#include "gradient.glsl"
#include "rect.glsl"
#ifdef GSK_FRAGMENT_SHADER
vec4 stack[GSK_GPU_PATTERN_STACK_SIZE];
uint stack_size = 0u;
void
stack_push (vec4 data)
{
stack[stack_size] = data;
stack_size++;
}
vec4
stack_pop (void)
{
stack_size--;
return stack[stack_size];
}
uint
read_uint (inout uint reader)
{
uint result = gsk_get_uint (reader);
reader++;
return result;
}
float
read_float (inout uint reader)
{
float result = gsk_get_float (reader);
reader++;
return result;
}
vec2
read_vec2 (inout uint reader)
{
return vec2 (read_float (reader), read_float (reader));
}
vec4
read_vec4 (inout uint reader)
{
return vec4 (read_float (reader), read_float (reader), read_float (reader), read_float (reader));
}
Rect
read_rect (inout uint reader)
{
return rect_from_gsk (read_vec4 (reader));
}
mat4
read_mat4 (inout uint reader)
{
mat4 result = mat4 (gsk_get_float (reader + 0u), gsk_get_float (reader + 1u),
gsk_get_float (reader + 2u), gsk_get_float (reader + 3u),
gsk_get_float (reader + 4u), gsk_get_float (reader + 5u),
gsk_get_float (reader + 6u), gsk_get_float (reader + 7u),
gsk_get_float (reader + 8u), gsk_get_float (reader + 9u),
gsk_get_float (reader + 10u), gsk_get_float (reader + 11u),
gsk_get_float (reader + 12u), gsk_get_float (reader + 13u),
gsk_get_float (reader + 14u), gsk_get_float (reader + 15u));
reader += 16u;
return result;
}
Gradient
read_gradient (inout uint reader)
{
Gradient gradient = gradient_new (reader);
reader += gradient_get_size (gradient);
return gradient;
}
void
clip_pattern (inout uint reader,
inout vec4 color,
vec2 pos)
{
Rect clip = read_rect (reader);
float alpha = rect_coverage (clip, pos);
color *= alpha;
}
void
opacity_pattern (inout uint reader,
inout vec4 color,
vec2 pos)
{
float opacity = read_float (reader);
color *= opacity;
}
void
color_matrix_pattern (inout uint reader,
inout vec4 color,
vec2 pos)
{
mat4 matrix = read_mat4 (reader);
vec4 offset = read_vec4 (reader);
color = color_unpremultiply (color);
color = matrix * color + offset;
color = clamp(color, 0.0, 1.0);
color = color_premultiply (color);
}
void
repeat_push_pattern (inout uint reader,
inout vec2 pos)
{
stack_push (vec4 (pos, 0.0, 0.0));
Rect bounds = read_rect (reader);
vec2 size = rect_size (bounds);
pos = mod (pos - bounds.bounds.xy, size);
/* make sure we have a positive result */
pos = mix (pos, pos + size, lessThan (pos, vec2 (0.0)));
pos += bounds.bounds.xy;
}
void
position_pop_pattern (inout uint reader,
inout vec2 pos)
{
pos = stack_pop ().xy;
}
void
cross_fade_pattern (inout uint reader,
inout vec4 color)
{
vec4 start = stack_pop ();
float progress = read_float (reader);
color = mix (start, color, progress);
}
void
mask_alpha_pattern (inout uint reader,
inout vec4 color)
{
vec4 source = stack_pop ();
color = source * color.a;
}
void
mask_inverted_alpha_pattern (inout uint reader,
inout vec4 color)
{
vec4 source = stack_pop ();
color = source * (1.0 - color.a);
}
void
mask_luminance_pattern (inout uint reader,
inout vec4 color)
{
vec4 source = stack_pop ();
color = source * luminance (color.rgb);
}
void
mask_inverted_luminance_pattern (inout uint reader,
inout vec4 color)
{
vec4 source = stack_pop ();
color = source * (color.a - luminance (color.rgb));
}
vec4
glyphs_pattern (inout uint reader,
vec2 pos)
{
float opacity = 0.0;
vec4 color = color_premultiply (read_vec4 (reader));
uint num_glyphs = read_uint (reader);
uint i;
for (i = 0u; i < num_glyphs; i++)
{
uint tex_id = read_uint (reader);
Rect glyph_bounds = read_rect (reader);
vec4 tex_rect = read_vec4 (reader);
float coverage = rect_coverage (glyph_bounds, pos);
if (coverage > 0.0)
opacity += coverage * gsk_texture (tex_id, (pos - push.scale * tex_rect.xy) / (push.scale * tex_rect.zw)).a;
}
return color * opacity;
}
vec4
texture_pattern (inout uint reader,
vec2 pos)
{
uint tex_id = read_uint (reader);
vec4 tex_rect = read_vec4 (reader);
return gsk_texture (tex_id, (pos - push.scale * tex_rect.xy) / (push.scale * tex_rect.zw));
}
vec4
linear_gradient_pattern (inout uint reader,
vec2 pos,
bool repeating)
{
vec2 start = read_vec2 (reader) * push.scale;
vec2 end = read_vec2 (reader) * push.scale;
Gradient gradient = read_gradient (reader);
vec2 line = end - start;
float line_length = dot (line, line);
float offset = dot (pos - start, line) / line_length;
float d_offset = 0.5 * fwidth (offset);
if (repeating)
return gradient_get_color_repeating (gradient, offset - d_offset, offset + d_offset);
else
return gradient_get_color (gradient, offset - d_offset, offset + d_offset);
}
vec4
radial_gradient_pattern (inout uint reader,
vec2 pos,
bool repeating)
{
vec2 center = read_vec2 (reader) * push.scale;
vec2 radius = read_vec2 (reader) * push.scale;
float start = read_float (reader);
float end = read_float (reader);
Gradient gradient = read_gradient (reader);
float offset = length ((pos - center) / radius);
offset = (offset - start) / (end - start);
float d_offset = 0.5 * fwidth (offset);
if (repeating)
return gradient_get_color_repeating (gradient, offset - d_offset, offset + d_offset);
else
return gradient_get_color (gradient, offset - d_offset, offset + d_offset);
}
vec4
conic_gradient_pattern (inout uint reader,
vec2 pos)
{
vec2 center = read_vec2 (reader);
float angle = read_float (reader);
Gradient gradient = read_gradient (reader);
/* scaling modifies angles, so be sure to use right coordinate system */
pos = pos / push.scale - center;
float offset = atan (pos.y, pos.x);
offset = degrees (offset + angle) / 360.0;
float overflow = fract (offset + 0.5);
offset = fract (offset);
float d_offset = max (0.00001, 0.5 * min (fwidth (offset), fwidth (overflow)));
return gradient_get_color_repeating (gradient, offset - d_offset, offset + d_offset);
}
vec4
color_pattern (inout uint reader)
{
vec4 color = read_vec4 (reader);
return color_premultiply (color);
}
vec4
pattern (uint reader,
vec2 pos)
{
vec4 color = vec4 (1.0, 0.0, 0.8, 1.0); /* pink */
for(;;)
{
uint type = read_uint (reader);
switch (type)
{
default:
case GSK_GPU_PATTERN_DONE:
return color;
case GSK_GPU_PATTERN_COLOR:
color = color_pattern (reader);
break;
case GSK_GPU_PATTERN_TEXTURE:
color = texture_pattern (reader, pos);
break;
case GSK_GPU_PATTERN_GLYPHS:
color = glyphs_pattern (reader, pos);
break;
case GSK_GPU_PATTERN_COLOR_MATRIX:
color_matrix_pattern (reader, color, pos);
break;
case GSK_GPU_PATTERN_OPACITY:
opacity_pattern (reader, color, pos);
break;
case GSK_GPU_PATTERN_LINEAR_GRADIENT:
color = linear_gradient_pattern (reader, pos, false);
break;
case GSK_GPU_PATTERN_REPEATING_LINEAR_GRADIENT:
color = linear_gradient_pattern (reader, pos, true);
break;
case GSK_GPU_PATTERN_RADIAL_GRADIENT:
color = radial_gradient_pattern (reader, pos, false);
break;
case GSK_GPU_PATTERN_REPEATING_RADIAL_GRADIENT:
color = radial_gradient_pattern (reader, pos, true);
break;
case GSK_GPU_PATTERN_CONIC_GRADIENT:
color = conic_gradient_pattern (reader, pos);
break;
case GSK_GPU_PATTERN_CLIP:
clip_pattern (reader, color, pos);
break;
case GSK_GPU_PATTERN_REPEAT_PUSH:
repeat_push_pattern (reader, pos);
break;
case GSK_GPU_PATTERN_POSITION_POP:
position_pop_pattern (reader, pos);
break;
case GSK_GPU_PATTERN_PUSH_COLOR:
stack_push (color);
color = vec4 (0.0);
break;
case GSK_GPU_PATTERN_POP_CROSS_FADE:
cross_fade_pattern (reader, color);
break;
case GSK_GPU_PATTERN_POP_MASK_ALPHA:
mask_alpha_pattern (reader, color);
break;
case GSK_GPU_PATTERN_POP_MASK_INVERTED_ALPHA:
mask_inverted_alpha_pattern (reader, color);
break;
case GSK_GPU_PATTERN_POP_MASK_LUMINANCE:
mask_luminance_pattern (reader, color);
break;
case GSK_GPU_PATTERN_POP_MASK_INVERTED_LUMINANCE:
mask_inverted_luminance_pattern (reader, color);
break;
}
}
}
#endif
#endif