summaryrefslogtreecommitdiffstats
path: root/wgpu/src/shader/triangle_gradient.wgsl
blob: cb35b61c4d14c90c2d973e58cd908331a8fdeaa3 (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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
// uniforms
struct GradientUniforms {
    transform: mat4x4<f32>,
    @size(16) start: vec2<f32>,
    @size(16) end: vec2<f32>,
    @size(16) start_stop: i32,
    @size(16) end_stop: i32,
}

struct Stop {
    color: vec4<f32>,
    offset: f32,
};

@group(0) @binding(0)
var<uniform> gradient_uniforms: GradientUniforms;

@group(0) @binding(1)
var<storage, read> color_stops: array<Stop>;

struct VertexOutput {
    @builtin(position) position: vec4<f32>,
    @location(0) raw_position: vec2<f32>
}

@vertex
fn vs_main(@location(0) input: vec2<f32>) -> VertexOutput {
    var output: VertexOutput;
    output.position = gradient_uniforms.transform * vec4<f32>(input.xy, 0.0, 1.0);
    output.raw_position = input;

    return output;
}

@fragment
fn fs_gradient(input: VertexOutput) -> @location(0) vec4<f32> {
    let v1 = gradient_uniforms.end - gradient_uniforms.start;
    let v2 = input.raw_position.xy - gradient_uniforms.start;
    let unit = normalize(v1);
    let offset = dot(unit, v2) / length(v1);

    let min_stop = color_stops[gradient_uniforms.start_stop];
    let max_stop = color_stops[gradient_uniforms.end_stop];

    var color: vec4<f32>;

    if (offset <= min_stop.offset) {
        color = min_stop.color;
    } else if (offset >= max_stop.offset) {
        color = max_stop.color;
    } else {
        var min = min_stop;
        var max = max_stop;
        var min_index = gradient_uniforms.start_stop;
        var max_index = gradient_uniforms.end_stop;

        loop {
            if (min_index >= max_index - 1) {
                break;
            }

            let index = min_index + (max_index - min_index) / 2;

            let stop = color_stops[index];

            if (offset <= stop.offset) {
                max = stop;
                max_index = index;
            } else {
                min = stop;
                min_index = index;
            }
        }

        color = mix(min.color, max.color, smoothstep(
            min.offset,
            max.offset,
            offset
        ));
    }

    return color;
}