git.lucas.co / cce-ui
GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git

src/draw/scene3d_image.wgsl (2.4K)

 1 // A textured quad in the 3D scene pass: `SceneImage`. The uniform block is
 2 // scene3d.wgsl's own, slot for slot — image draws take their uniforms from
 3 // the same per-frame buffer the mesh draws do — and the texture is a user
 4 // image's descriptor set, the one the 2D pass draws it with.
 5 struct Uniforms {
 6     mvp: mat4x4<f32>,
 7     window_size: vec2<f32>,
 8     window_radius: f32,
 9     corner_shape: f32,
10     wire_tint: vec4<f32>,
11     opacity: f32,
12     is_wire: f32,
13     prelit: f32,
14 }
15 
16 @group(0) @binding(0) var<uniform> uniforms: Uniforms;
17 @group(1) @binding(0) var t_image: texture_2d<f32>;
18 @group(1) @binding(1) var s_image: sampler;
19 
20 // scene3d.wgsl's window_corner_distance, kept in lockstep with it.
21 fn window_corner_distance(pos: vec2<f32>) -> f32 {
22     let w = uniforms.window_size.x;
23     let h = uniforms.window_size.y;
24     let r = uniforms.window_radius;
25 
26     if (pos.x < 0.0 || pos.x > w || pos.y < 0.0 || pos.y > h) {
27         return 1e5;
28     }
29     if (r <= 0.0) {
30         return -1e5;
31     }
32     let q = abs(pos - vec2f(w * 0.5, h * 0.5)) - vec2f(w * 0.5 - r, h * 0.5 - r);
33     if (q.x > 0.0 && q.y > 0.0) {
34         let shape = uniforms.corner_shape;
35         if (shape > 2.001) {
36             let lp = max(pow(pow(q.x, shape) + pow(q.y, shape), 1.0 / shape), 1e-4);
37             let g = vec2f(pow(q.x / lp, shape - 1.0), pow(q.y / lp, shape - 1.0));
38             return (lp - r) / max(length(g), 1e-4);
39         }
40         return length(q) - r;
41     }
42     return -1e5;
43 }
44 
45 struct VertexOutput {
46     @builtin(position) position: vec4f,
47     @location(0) uv: vec2f,
48 };
49 
50 @vertex
51 fn vs_main(
52     @location(0) position: vec3f,
53     @location(1) uv: vec2f,
54 ) -> VertexOutput {
55     var out: VertexOutput;
56     out.position = uniforms.mvp * vec4f(position, 1.0);
57     out.uv = uv;
58     return out;
59 }
60 
61 @fragment
62 fn fs_main(in: VertexOutput) -> @location(0) vec4f {
63     // Sampled ahead of any discard: implicit derivatives are undefined after
64     // non-uniform control flow.
65     let texel = textureSample(t_image, s_image, in.uv);
66     let cov = 1.0 - smoothstep(-0.5, 0.5, window_corner_distance(in.position.xy));
67     let alpha = texel.a * cov * uniforms.opacity;
68     // The pipeline writes depth, and a texel that shows nothing must not
69     // hide what is drawn behind it afterwards.
70     if (alpha <= 0.002) {
71         discard;
72     }
73     // Unlit: a picture carries its own light.
74     return vec4f(texel.rgb, alpha);
75 }