Seregon/StratoSDK

StratoSDK is a framework with a declarative approach similar to Flutter/React, written and designed entirely for Rust.

Rust/27.3 KB/No license
crates/strato-renderer/src/shaders/ui.wgsl
1// === STRUCTS & BINDINGS ===
2 
3struct Uniforms {
4 projection: mat4x4<f32>,
5 // You could also add `resolution: vec2<f32>` for shaders needing the window size
6}
7 
8struct VertexInput {
9 @location(0) position: vec2<f32>, // 2D position is sufficient
10 @location(1) color: vec4<f32>, // Primary color
11 @location(2) uv: vec2<f32>, // UV coordinates or geometric data
12 @location(3) params: vec4<f32>, // Additional parameters (e.g., corner radius)
13 @location(4) flags: u32, // Bitmask for the rendering type
14}
15 
16struct VertexOutput {
17 @builtin(position) clip_position: vec4<f32>,
18 @location(0) @interpolate(flat) flags: u32, // Use 'flat' for flags; they don't need interpolation
19 @location(1) @interpolate(perspective) color: vec4<f32>,
20 @location(2) @interpolate(perspective) uv: vec2<f32>,
21 @location(3) @interpolate(perspective) params: vec4<f32>,
22 @location(4) @interpolate(perspective) world_position: vec2<f32>, // Original position in pixels for geometric calculations
23}
24 
25@group(0) @binding(0) var<uniform> uniforms: Uniforms;
26@group(0) @binding(1) var main_sampler: sampler;
27@group(0) @binding(2) var main_texture: texture_2d<f32>; // Texture Atlas for text, icons, etc.
28 
29// === BITMASK FLAGS ===
30// (These should also be defined as constants in your Rust code)
31const FLAG_TYPE_SOLID: u32 = 0u;
32const FLAG_TYPE_TEXTURED: u32 = 1u;
33const FLAG_TYPE_SDF_TEXT: u32 = 2u;
34const FLAG_TYPE_ROUNDED_RECT: u32 = 3u;
35const FLAG_TYPE_MASK: u32 = 3u; // Mask to extract the type (first 2 bits)
36 
37 
38// === HELPER FUNCTIONS ===
39 
40// Renders a rounded rectangle using a Signed Distance Function
41fn sdf_rounded_box(point: vec2<f32>, size: vec2<f32>, radius: f32) -> f32 {
42 let q = abs(point) - size + vec2<f32>(radius);
43 return min(max(q.x, q.y), 0.0) + length(max(q, vec2<f32>(0.0))) - radius;
44}
45 
46 
47// === VERTEX SHADER ===
48 
49@vertex
50fn vs_main(in: VertexInput) -> VertexOutput {
51 var out: VertexOutput;
52 out.clip_position = uniforms.projection * vec4<f32>(in.position, 0.0, 1.0);
53 out.world_position = in.position;
54 out.flags = in.flags;
55 out.color = in.color;
56 out.uv = in.uv;
57 out.params = in.params;
58 return out;
59}
60 
61 
62// === FRAGMENT SHADER ===
63 
64@fragment
65fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
66 let render_type = in.flags & FLAG_TYPE_MASK;
67 var final_color: vec4<f32>;
68 
69 switch (render_type) {
70 // --- Path 1: Solid color shapes ---
71 case FLAG_TYPE_SOLID: {
72 final_color = in.color;
73 }
74 
75 // --- Path 2: Simple textured shapes (images, icons) ---
76 case FLAG_TYPE_TEXTURED: {
77 let texture_color = textureSample(main_texture, main_sampler, in.uv);
78 final_color = in.color * texture_color;
79 }
80 
81 // --- Path 3: Text rendered with Signed Distance Fields (SDF) ---
82 case FLAG_TYPE_SDF_TEXT: {
83 // Sample the distance value from the glyph atlas (stored in the 'r' channel)
84 let distance = textureSample(main_texture, main_sampler, in.uv).r;
85 // `smoothstep` creates a soft, antialiased edge
86 // `in.params.x` can hold the font's edge "width" or "smoothing" factor
87 let edge_width = in.params.x;
88 let alpha = smoothstep(0.5 - edge_width, 0.5 + edge_width, distance);
89 final_color = vec4<f32>(in.color.rgb, in.color.a * alpha);
90 }
91 
92 // --- Path 4: Rounded rectangles ---
93 case FLAG_TYPE_ROUNDED_RECT: {
94 // Necessary parameters are passed via vertex fields
95 let rect_size = in.params.xy;
96 let corner_radius = in.params.z;
97
98 // Calculate the distance from the rounded rectangle's border
99 let dist = sdf_rounded_box(in.world_position - rect_size * 0.5, rect_size * 0.5, corner_radius);
100 
101 // `smoothstep` provides high-quality antialiasing
102 // A value of 1.0 represents a 1-pixel feather.
103 let alpha = 1.0 - smoothstep(0.0, 1.0, dist);
104 final_color = vec4<f32>(in.color.rgb, in.color.a * alpha);
105 }
106 
107 default: {
108 // Fallback color for debugging (e.g., magenta)
109 final_color = vec4<f32>(1.0, 0.0, 1.0, 1.0);
110 }
111 }
112 
113 // No premult multiplied alpha conversion - blend mode handles this
114 return final_color;
115}