diff options
| author | 2023-07-12 12:23:18 -0700 | |
|---|---|---|
| committer | 2023-07-12 12:23:18 -0700 | |
| commit | 633f405f3f78bc7f82d2b2061491b0e011137451 (patch) | |
| tree | 5ebfc1f45d216a5c14a90492563599e6969eab4d /wgpu/src/shader/quad | |
| parent | 41836dd80d0534608e7aedfbf2319c540a23de1a (diff) | |
| parent | 21bd51426d900e271206f314e0c915dd41065521 (diff) | |
| download | iced-633f405f3f78bc7f82d2b2061491b0e011137451.tar.gz iced-633f405f3f78bc7f82d2b2061491b0e011137451.tar.bz2 iced-633f405f3f78bc7f82d2b2061491b0e011137451.zip | |
Merge remote-tracking branch 'origin/master' into feat/multi-window-support
# Conflicts:
#	Cargo.toml
#	core/src/window/icon.rs
#	core/src/window/id.rs
#	core/src/window/position.rs
#	core/src/window/settings.rs
#	examples/integration/src/main.rs
#	examples/integration_opengl/src/main.rs
#	glutin/src/application.rs
#	native/src/subscription.rs
#	native/src/window.rs
#	runtime/src/window/action.rs
#	src/lib.rs
#	src/window.rs
#	winit/Cargo.toml
#	winit/src/application.rs
#	winit/src/icon.rs
#	winit/src/settings.rs
#	winit/src/window.rs
Diffstat (limited to '')
| -rw-r--r-- | wgpu/src/shader/quad.wgsl | 293 | 
1 files changed, 249 insertions, 44 deletions
| diff --git a/wgpu/src/shader/quad.wgsl b/wgpu/src/shader/quad.wgsl index cf4f7e4d..fb402158 100644 --- a/wgpu/src/shader/quad.wgsl +++ b/wgpu/src/shader/quad.wgsl @@ -5,17 +5,57 @@ struct Globals {  @group(0) @binding(0) var<uniform> globals: Globals; -struct VertexInput { +fn distance_alg( +    frag_coord: vec2<f32>, +    position: vec2<f32>, +    size: vec2<f32>, +    radius: f32 +) -> f32 { +    var inner_size: vec2<f32> = size - vec2<f32>(radius, radius) * 2.0; +    var top_left: vec2<f32> = position + vec2<f32>(radius, radius); +    var bottom_right: vec2<f32> = top_left + inner_size; + +    var top_left_distance: vec2<f32> = top_left - frag_coord; +    var bottom_right_distance: vec2<f32> = frag_coord - bottom_right; + +    var dist: vec2<f32> = vec2<f32>( +        max(max(top_left_distance.x, bottom_right_distance.x), 0.0), +        max(max(top_left_distance.y, bottom_right_distance.y), 0.0) +    ); + +    return sqrt(dist.x * dist.x + dist.y * dist.y); +} + +// Based on the fragement position and the center of the quad, select one of the 4 radi. +// Order matches CSS border radius attribute: +// radi.x = top-left, radi.y = top-right, radi.z = bottom-right, radi.w = bottom-left +fn select_border_radius(radi: vec4<f32>, position: vec2<f32>, center: vec2<f32>) -> f32 { +    var rx = radi.x; +    var ry = radi.y; +    rx = select(radi.x, radi.y, position.x > center.x); +    ry = select(radi.w, radi.z, position.x > center.x); +    rx = select(rx, ry, position.y > center.y); +    return rx; +} + +fn unpack_u32(color: vec2<u32>) -> vec4<f32> { +    let rg: vec2<f32> = unpack2x16float(color.x); +    let ba: vec2<f32> = unpack2x16float(color.y); + +    return vec4<f32>(rg.y, rg.x, ba.y, ba.x); +} + +struct SolidVertexInput {      @location(0) v_pos: vec2<f32>, -    @location(1) pos: vec2<f32>, -    @location(2) scale: vec2<f32>, -    @location(3) color: vec4<f32>, +    @location(1) color: vec4<f32>, +    @location(2) pos: vec2<f32>, +    @location(3) scale: vec2<f32>,      @location(4) border_color: vec4<f32>,      @location(5) border_radius: vec4<f32>,      @location(6) border_width: f32,  } -struct VertexOutput { +struct SolidVertexOutput {      @builtin(position) position: vec4<f32>,      @location(0) color: vec4<f32>,      @location(1) border_color: vec4<f32>, @@ -26,8 +66,8 @@ struct VertexOutput {  }  @vertex -fn vs_main(input: VertexInput) -> VertexOutput { -    var out: VertexOutput; +fn solid_vs_main(input: SolidVertexInput) -> SolidVertexOutput { +    var out: SolidVertexOutput;      var pos: vec2<f32> = input.pos * globals.scale;      var scale: vec2<f32> = input.scale * globals.scale; @@ -47,54 +87,20 @@ fn vs_main(input: VertexInput) -> VertexOutput {          vec4<f32>(pos - vec2<f32>(0.5, 0.5), 0.0, 1.0)      ); +    out.position = globals.transform * transform * vec4<f32>(input.v_pos, 0.0, 1.0);      out.color = input.color;      out.border_color = input.border_color;      out.pos = pos;      out.scale = scale;      out.border_radius = border_radius * globals.scale;      out.border_width = input.border_width * globals.scale; -    out.position = globals.transform * transform * vec4<f32>(input.v_pos, 0.0, 1.0);      return out;  } -fn distance_alg( -    frag_coord: vec2<f32>, -    position: vec2<f32>, -    size: vec2<f32>, -    radius: f32 -) -> f32 { -    var inner_size: vec2<f32> = size - vec2<f32>(radius, radius) * 2.0; -    var top_left: vec2<f32> = position + vec2<f32>(radius, radius); -    var bottom_right: vec2<f32> = top_left + inner_size; - -    var top_left_distance: vec2<f32> = top_left - frag_coord; -    var bottom_right_distance: vec2<f32> = frag_coord - bottom_right; - -    var dist: vec2<f32> = vec2<f32>( -        max(max(top_left_distance.x, bottom_right_distance.x), 0.0), -        max(max(top_left_distance.y, bottom_right_distance.y), 0.0) -    ); - -    return sqrt(dist.x * dist.x + dist.y * dist.y); -} - -// Based on the fragement position and the center of the quad, select one of the 4 radi. -// Order matches CSS border radius attribute: -// radi.x = top-left, radi.y = top-right, radi.z = bottom-right, radi.w = bottom-left -fn select_border_radius(radi: vec4<f32>, position: vec2<f32>, center: vec2<f32>) -> f32 { -    var rx = radi.x; -    var ry = radi.y; -    rx = select(radi.x, radi.y, position.x > center.x); -    ry = select(radi.w, radi.z, position.x > center.x); -    rx = select(rx, ry, position.y > center.y); -    return rx; -} - -  @fragment -fn fs_main( -    input: VertexOutput +fn solid_fs_main( +    input: SolidVertexOutput  ) -> @location(0) vec4<f32> {      var mixed_color: vec4<f32> = input.color; @@ -138,3 +144,202 @@ fn fs_main(      return vec4<f32>(mixed_color.x, mixed_color.y, mixed_color.z, mixed_color.w * radius_alpha);  } + +struct GradientVertexInput { +    @location(0) v_pos: vec2<f32>, +    @location(1) colors_1: vec4<u32>, +    @location(2) colors_2: vec4<u32>, +    @location(3) colors_3: vec4<u32>, +    @location(4) colors_4: vec4<u32>, +    @location(5) offsets: vec4<u32>, +    @location(6) direction: vec4<f32>, +    @location(7) position_and_scale: vec4<f32>, +    @location(8) border_color: vec4<f32>, +    @location(9) border_radius: vec4<f32>, +    @location(10) border_width: f32, +} + +struct GradientVertexOutput { +    @builtin(position) position: vec4<f32>, +    @location(1) colors_1: vec4<u32>, +    @location(2) colors_2: vec4<u32>, +    @location(3) colors_3: vec4<u32>, +    @location(4) colors_4: vec4<u32>, +    @location(5) offsets: vec4<u32>, +    @location(6) direction: vec4<f32>, +    @location(7) position_and_scale: vec4<f32>, +    @location(8) border_color: vec4<f32>, +    @location(9) border_radius: vec4<f32>, +    @location(10) border_width: f32, +} + +@vertex +fn gradient_vs_main(input: GradientVertexInput) -> GradientVertexOutput { +    var out: GradientVertexOutput; + +    var pos: vec2<f32> = input.position_and_scale.xy * globals.scale; +    var scale: vec2<f32> = input.position_and_scale.zw * globals.scale; + +    var min_border_radius = min(input.position_and_scale.z, input.position_and_scale.w) * 0.5; +    var border_radius: vec4<f32> = vec4<f32>( +        min(input.border_radius.x, min_border_radius), +        min(input.border_radius.y, min_border_radius), +        min(input.border_radius.z, min_border_radius), +        min(input.border_radius.w, min_border_radius) +    ); + +    var transform: mat4x4<f32> = mat4x4<f32>( +        vec4<f32>(scale.x + 1.0, 0.0, 0.0, 0.0), +        vec4<f32>(0.0, scale.y + 1.0, 0.0, 0.0), +        vec4<f32>(0.0, 0.0, 1.0, 0.0), +        vec4<f32>(pos - vec2<f32>(0.5, 0.5), 0.0, 1.0) +    ); + +    out.position = globals.transform * transform * vec4<f32>(input.v_pos, 0.0, 1.0); +    out.colors_1 = input.colors_1; +    out.colors_2 = input.colors_2; +    out.colors_3 = input.colors_3; +    out.colors_4 = input.colors_4; +    out.offsets = input.offsets; +    out.direction = input.direction * globals.scale; +    out.position_and_scale = vec4<f32>(pos, scale); +    out.border_color = input.border_color; +    out.border_radius = border_radius * globals.scale; +    out.border_width = input.border_width * globals.scale; + +    return out; +} + +fn random(coords: vec2<f32>) -> f32 { +    return fract(sin(dot(coords, vec2(12.9898,78.233))) * 43758.5453); +} + +/// Returns the current interpolated color with a max 8-stop gradient +fn gradient( +    raw_position: vec2<f32>, +    direction: vec4<f32>, +    colors: array<vec4<f32>, 8>, +    offsets: array<f32, 8>, +    last_index: i32 +) -> vec4<f32> { +    let start = direction.xy; +    let end = direction.zw; + +    let v1 = end - start; +    let v2 = raw_position - start; +    let unit = normalize(v1); +    let coord_offset = dot(unit, v2) / length(v1); + +    //need to store these as a var to use dynamic indexing in a loop +    //this is already added to wgsl spec but not in wgpu yet +    var colors_arr = colors; +    var offsets_arr = offsets; + +    var color: vec4<f32>; + +    let noise_granularity: f32 = 0.3/255.0; + +    for (var i: i32 = 0; i < last_index; i++) { +        let curr_offset = offsets_arr[i]; +        let next_offset = offsets_arr[i+1]; + +        if (coord_offset <= offsets_arr[0]) { +            color = colors_arr[0]; +        } + +        if (curr_offset <= coord_offset && coord_offset <= next_offset) { +            color = mix(colors_arr[i], colors_arr[i+1], smoothstep( +                curr_offset, +                next_offset, +                coord_offset, +            )); +        } + +        if (coord_offset >= offsets_arr[last_index]) { +            color = colors_arr[last_index]; +        } +    } + +    return color + mix(-noise_granularity, noise_granularity, random(raw_position)); +} + +@fragment +fn gradient_fs_main(input: GradientVertexOutput) -> @location(0) vec4<f32> { +    let colors = array<vec4<f32>, 8>( +        unpack_u32(input.colors_1.xy), +        unpack_u32(input.colors_1.zw), +        unpack_u32(input.colors_2.xy), +        unpack_u32(input.colors_2.zw), +        unpack_u32(input.colors_3.xy), +        unpack_u32(input.colors_3.zw), +        unpack_u32(input.colors_4.xy), +        unpack_u32(input.colors_4.zw), +    ); + +    let offsets_1: vec4<f32> = unpack_u32(input.offsets.xy); +    let offsets_2: vec4<f32> = unpack_u32(input.offsets.zw); + +    var offsets = array<f32, 8>( +        offsets_1.x, +        offsets_1.y, +        offsets_1.z, +        offsets_1.w, +        offsets_2.x, +        offsets_2.y, +        offsets_2.z, +        offsets_2.w, +    ); + +    //TODO could just pass this in to the shader but is probably more performant to just check it here +    var last_index = 7; +    for (var i: i32 = 0; i <= 7; i++) { +        if (offsets[i] > 1.0) { +            last_index = i - 1; +            break; +        } +    } + +    var mixed_color: vec4<f32> = gradient(input.position.xy, input.direction, colors, offsets, last_index); + +    let pos = input.position_and_scale.xy; +    let scale = input.position_and_scale.zw; + +    var border_radius = select_border_radius( +        input.border_radius, +        input.position.xy, +        (pos + scale * 0.5).xy +    ); + +    if (input.border_width > 0.0) { +        var internal_border: f32 = max(border_radius - input.border_width, 0.0); + +        var internal_distance: f32 = distance_alg( +            input.position.xy, +            pos + vec2<f32>(input.border_width, input.border_width), +            scale - vec2<f32>(input.border_width * 2.0, input.border_width * 2.0), +            internal_border +        ); + +        var border_mix: f32 = smoothstep( +            max(internal_border - 0.5, 0.0), +            internal_border + 0.5, +            internal_distance +        ); + +        mixed_color = mix(mixed_color, input.border_color, vec4<f32>(border_mix, border_mix, border_mix, border_mix)); +    } + +    var dist: f32 = distance_alg( +        input.position.xy, +        pos, +        scale, +        border_radius +    ); + +    var radius_alpha: f32 = 1.0 - smoothstep( +        max(border_radius - 0.5, 0.0), +        border_radius + 0.5, +        dist); + +    return vec4<f32>(mixed_color.x, mixed_color.y, mixed_color.z, mixed_color.w * radius_alpha); +} | 
