diff options
author | 2022-12-13 09:31:57 +0100 | |
---|---|---|
committer | 2022-12-13 09:31:57 +0100 | |
commit | 2e6d90f141217bad83eacd392562c13d7485881f (patch) | |
tree | baa2c507076073aed4fd24abc9c7a7949d85c039 /wgpu/src/shader | |
parent | ba95042fff378213f5029b2b164d79e768482a47 (diff) | |
parent | 02182eea45537c9eb5b2bddfdff822bb8a3d143d (diff) | |
download | iced-2e6d90f141217bad83eacd392562c13d7485881f.tar.gz iced-2e6d90f141217bad83eacd392562c13d7485881f.tar.bz2 iced-2e6d90f141217bad83eacd392562c13d7485881f.zip |
Merge branch 'master' into feat/slider-orientation
Diffstat (limited to 'wgpu/src/shader')
-rw-r--r-- | wgpu/src/shader/gradient.wgsl | 88 | ||||
-rw-r--r-- | wgpu/src/shader/quad.wgsl | 47 | ||||
-rw-r--r-- | wgpu/src/shader/solid.wgsl (renamed from wgpu/src/shader/triangle.wgsl) | 0 |
3 files changed, 121 insertions, 14 deletions
diff --git a/wgpu/src/shader/gradient.wgsl b/wgpu/src/shader/gradient.wgsl new file mode 100644 index 00000000..63825aec --- /dev/null +++ b/wgpu/src/shader/gradient.wgsl @@ -0,0 +1,88 @@ +struct Uniforms { + transform: mat4x4<f32>, + //xy = start, wz = end + position: vec4<f32>, + //x = start stop, y = end stop, zw = padding + stop_range: vec4<i32>, +} + +struct Stop { + color: vec4<f32>, + offset: f32, +}; + +@group(0) @binding(0) +var<uniform> uniforms: Uniforms; + +@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 = uniforms.transform * vec4<f32>(input.xy, 0.0, 1.0); + output.raw_position = input; + + return output; +} + +//TODO: rewrite without branching +@fragment +fn fs_main(input: VertexOutput) -> @location(0) vec4<f32> { + let start = uniforms.position.xy; + let end = uniforms.position.zw; + let start_stop = uniforms.stop_range.x; + let end_stop = uniforms.stop_range.y; + + let v1 = end - start; + let v2 = input.raw_position.xy - start; + let unit = normalize(v1); + let offset = dot(unit, v2) / length(v1); + + let min_stop = color_stops[start_stop]; + let max_stop = color_stops[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 = start_stop; + var max_index = 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; +} diff --git a/wgpu/src/shader/quad.wgsl b/wgpu/src/shader/quad.wgsl index 73edd97c..cf4f7e4d 100644 --- a/wgpu/src/shader/quad.wgsl +++ b/wgpu/src/shader/quad.wgsl @@ -11,7 +11,7 @@ struct VertexInput { @location(2) scale: vec2<f32>, @location(3) color: vec4<f32>, @location(4) border_color: vec4<f32>, - @location(5) border_radius: f32, + @location(5) border_radius: vec4<f32>, @location(6) border_width: f32, } @@ -21,7 +21,7 @@ struct VertexOutput { @location(1) border_color: vec4<f32>, @location(2) pos: vec2<f32>, @location(3) scale: vec2<f32>, - @location(4) border_radius: f32, + @location(4) border_radius: vec4<f32>, @location(5) border_width: f32, } @@ -32,9 +32,12 @@ fn vs_main(input: VertexInput) -> VertexOutput { var pos: vec2<f32> = input.pos * globals.scale; var scale: vec2<f32> = input.scale * globals.scale; - var border_radius: f32 = min( - input.border_radius, - min(input.scale.x, input.scale.y) / 2.0 + var min_border_radius = min(input.scale.x, input.scale.y) * 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>( @@ -76,6 +79,18 @@ fn distance_alg( 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( @@ -83,14 +98,17 @@ fn fs_main( ) -> @location(0) vec4<f32> { var mixed_color: vec4<f32> = input.color; + var border_radius = select_border_radius( + input.border_radius, + input.position.xy, + (input.pos + input.scale * 0.5).xy + ); + if (input.border_width > 0.0) { - var internal_border: f32 = max( - input.border_radius - input.border_width, - 0.0 - ); + var internal_border: f32 = max(border_radius - input.border_width, 0.0); var internal_distance: f32 = distance_alg( - vec2<f32>(input.position.x, input.position.y), + input.position.xy, input.pos + vec2<f32>(input.border_width, input.border_width), input.scale - vec2<f32>(input.border_width * 2.0, input.border_width * 2.0), internal_border @@ -109,13 +127,14 @@ fn fs_main( vec2<f32>(input.position.x, input.position.y), input.pos, input.scale, - input.border_radius + border_radius ); var radius_alpha: f32 = 1.0 - smoothstep( - max(input.border_radius - 0.5, 0.0), - input.border_radius + 0.5, - dist); + 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); } diff --git a/wgpu/src/shader/triangle.wgsl b/wgpu/src/shader/solid.wgsl index b24402f8..b24402f8 100644 --- a/wgpu/src/shader/triangle.wgsl +++ b/wgpu/src/shader/solid.wgsl |