summaryrefslogtreecommitdiffstats
path: root/glow/src/shader/common/gradient.frag
blob: 9af0cb6e36d3dead7b34d4b8768b9509c9400f24 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#ifdef GL_ES
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
#endif

#ifdef HIGHER_THAN_300
layout (location = 0) out vec4 fragColor;
#define gl_FragColor fragColor
#endif

in vec2 raw_position;

uniform vec4 gradient_direction;
uniform int color_stops_size;
// GLSL does not support dynamically sized arrays without SSBOs so this is capped to 16 stops
//stored as color(vec4) -> offset(vec4) sequentially;
uniform vec4 color_stops[32];

//TODO: rewrite without branching to make ALUs happy
void main() {
    vec2 start = gradient_direction.xy;
    vec2 end = gradient_direction.zw;
    vec2 gradient_vec = vec2(end - start);
    vec2 current_vec = vec2(raw_position.xy - start);
    vec2 unit = normalize(gradient_vec);
    float coord_offset = dot(unit, current_vec) / length(gradient_vec);
    //if a gradient has a start/end stop that is identical, the mesh will have a transparent fill
    gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);

    float min_offset = color_stops[1].x;
    float max_offset = color_stops[color_stops_size - 1].x;

    for (int i = 0; i < color_stops_size - 2; i += 2) {
        float curr_offset = color_stops[i+1].x;
        float next_offset = color_stops[i+3].x;

        if (coord_offset <= min_offset) {
            //current coordinate is before the first defined offset, set it to the start color
            gl_FragColor = color_stops[0];
        }

        if (curr_offset <= coord_offset && coord_offset <= next_offset) {
            //current fragment is between the current offset processing & the next one, interpolate colors
            gl_FragColor = mix(color_stops[i], color_stops[i+2], smoothstep(
                curr_offset,
                next_offset,
                coord_offset
            ));
        }

        if (coord_offset >= max_offset) {
            //current coordinate is before the last defined offset, set it to the last color
            gl_FragColor = color_stops[color_stops_size - 2];
        }
    }
}