runmat_plot/gpu/shaders/vertex/
point_direct.rs1pub const SHADER: &str = r#"// Direct point shader: expands each input point into a screen-space quad
2
3struct Uniforms {
4 data_min: vec2<f32>,
5 data_max: vec2<f32>,
6 viewport_min: vec2<f32>,
7 viewport_max: vec2<f32>,
8 viewport_px: vec2<f32>,
9 log_flags: vec2<u32>,
10 _pad: vec2<u32>,
11}
12
13struct PointStyleUniforms {
14 face_color: vec4<f32>,
15 edge_color: vec4<f32>,
16 edge_thickness_px: f32,
17 marker_shape: u32,
18 _pad: vec2<f32>,
19}
20
21@group(0) @binding(0)
22var<uniform> uniforms: Uniforms;
23@group(1) @binding(0)
24var<uniform> styleU: PointStyleUniforms;
25
26struct VertexInput {
27 @location(0) position: vec3<f32>,
28 @location(1) color: vec4<f32>,
29 @location(2) normal: vec3<f32>,
30 @location(3) tex_coords: vec2<f32>,
31}
32
33struct VSOut {
34 @builtin(position) clip_position: vec4<f32>,
35 @location(0) color: vec4<f32>,
36 @location(1) uv: vec2<f32>,
37 @location(2) center_ndc: vec2<f32>,
38 @location(3) half_ndc: vec2<f32>,
39 @location(4) size_px: f32,
40}
41
42fn transform_axis(value: f32, is_log: u32) -> f32 {
43 if (is_log != 0u) {
44 if (value <= 0.0) {
45 return 1e30;
46 }
47 return log(value) / log(10.0);
48 }
49 return value;
50}
51
52@vertex
53fn vs_main(input: VertexInput) -> VSOut {
54 var out: VSOut;
55
56 let data_min = vec2<f32>(
57 transform_axis(uniforms.data_min.x, uniforms.log_flags.x),
58 transform_axis(uniforms.data_min.y, uniforms.log_flags.y)
59 );
60 let data_max = vec2<f32>(
61 transform_axis(uniforms.data_max.x, uniforms.log_flags.x),
62 transform_axis(uniforms.data_max.y, uniforms.log_flags.y)
63 );
64 let position = vec2<f32>(
65 transform_axis(input.position.x, uniforms.log_flags.x),
66 transform_axis(input.position.y, uniforms.log_flags.y)
67 );
68 let data_range = data_max - data_min;
69 let viewport_range = uniforms.viewport_max - uniforms.viewport_min;
70 let normalized = (position - data_min) / data_range;
71 let center = uniforms.viewport_min + normalized * viewport_range;
72
73 let size_px = max(2.0, input.normal.z);
74 let half_w_ndc = (0.5 * size_px) / uniforms.viewport_px.x * viewport_range.x;
75 let half_h_ndc = (0.5 * size_px) / uniforms.viewport_px.y * viewport_range.y;
76
77 let corner = input.tex_coords;
78 let offset_ndc = vec2<f32>(corner.x * half_w_ndc, corner.y * half_h_ndc);
79
80 let ndc = center + offset_ndc;
81 out.clip_position = vec4<f32>(ndc, 0.0, 1.0);
82 out.color = input.color;
83 out.uv = (corner + vec2<f32>(1.0, 1.0)) * 0.5;
84 out.center_ndc = center;
85 out.half_ndc = vec2<f32>(half_w_ndc, half_h_ndc);
86 out.size_px = size_px;
87 return out;
88}
89
90fn inside_triangle(pt: vec2<f32>) -> bool {
91 let a = vec2<f32>(-1.0, -1.0);
92 let b = vec2<f32>(1.0, -1.0);
93 let c = vec2<f32>(0.0, 1.0);
94 let v0 = c - a;
95 let v1 = b - a;
96 let v2 = pt - a;
97 let d00 = dot(v0, v0);
98 let d01 = dot(v0, v1);
99 let d11 = dot(v1, v1);
100 let d20 = dot(v2, v0);
101 let d21 = dot(v2, v1);
102 let denom = d00 * d11 - d01 * d01;
103 if (denom == 0.0) { return false; }
104 let v = (d11 * d20 - d01 * d21) / denom;
105 let w = (d00 * d21 - d01 * d20) / denom;
106 let u = 1.0 - v - w;
107 return (u >= 0.0) && (v >= 0.0) && (w >= 0.0);
108}
109
110fn inside_hexagon(pt: vec2<f32>) -> bool {
111 let a = vec2<f32>(1.0, 0.0);
112 let b = vec2<f32>(0.5, 0.8660254);
113 let c = vec2<f32>(-0.5, 0.8660254);
114 let da = abs(dot(pt, a));
115 let db = abs(dot(pt, b));
116 let dc = abs(dot(pt, c));
117 return max(da, max(db, dc)) <= 1.0;
118}
119
120@fragment
121fn fs_main(input: VSOut) -> @location(0) vec4<f32> {
122 let p = input.uv * 2.0 - vec2<f32>(1.0, 1.0);
123 let r = length(p);
124
125 var inside: bool;
126 switch (styleU.marker_shape) {
127 case 0u: { inside = r <= 1.0; }
128 case 1u: { inside = true; }
129 case 2u: { inside = inside_triangle(p); }
130 case 3u: { inside = (abs(p.x) + abs(p.y)) <= 1.0; }
131 case 4u: {
132 let w = 0.35;
133 inside = (abs(p.x) <= w) || (abs(p.y) <= w);
134 }
135 case 5u: {
136 let w = 0.30;
137 inside = min(abs(p.x - p.y), abs(p.x + p.y)) <= w;
138 }
139 case 6u: {
140 let w1 = 0.30;
141 let w2 = 0.25;
142 let plus = (abs(p.x) <= w1) || (abs(p.y) <= w1);
143 let cross = min(abs(p.x - p.y), abs(p.x + p.y)) <= w2;
144 inside = plus || cross;
145 }
146 case 7u: {
147 inside = inside_hexagon(p);
148 }
149 default: {
150 inside = true;
151 }
152 }
153 if (!inside) {
154 discard;
155 }
156
157 let edge_norm = clamp(2.0 * styleU.edge_thickness_px / max(input.size_px, 1.0), 0.0, 1.0);
158 let face_rgb = mix(input.color.rgb, styleU.face_color.rgb, styleU.face_color.a);
159 let edge_mix = clamp(styleU.edge_color.a, 0.0, 1.0);
160 let edge_rgb = mix(input.color.rgb, styleU.edge_color.rgb, edge_mix);
161
162 if (styleU.marker_shape == 0u) {
163 if (edge_norm > 0.0 && r > (1.0 - edge_norm)) {
164 return vec4<f32>(edge_rgb, input.color.a);
165 }
166 }
167
168 return vec4<f32>(face_rgb, input.color.a);
169}
170"#;