Skip to content

Commit 8474e51

Browse files
committed
Add back gridmode and do some clippy lints.
1 parent 989e391 commit 8474e51

35 files changed

+372
-246
lines changed

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
{
22
"rust-analyzer.cargo.targetDir": true,
3+
//"rust-analyzer.check.command": "clippy",
34
}

Cargo.toml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,29 @@ opt-level = 3
5151
opt-level = 0
5252

5353
[workspace.lints.clippy]
54+
# disabled because shader code does this often
55+
cast_precision_loss = "allow"
56+
cast_possible_truncation = "allow"
57+
excessive_precision = "allow"
58+
missing_const_for_fn = "allow"
59+
many_single_char_names = "allow"
60+
similar_names = "allow"
61+
too_many_arguments = "allow"
62+
suboptimal_flops = "allow"
63+
too_many_lines = "allow"
64+
cognitive_complexity = "allow"
65+
# disabled because of rust gpu limitatoins
66+
manual_range_contains = "allow" # Rust gpu does not like the core range checks
67+
needless_range_loop = "allow" # Rust gpu does not like iterators very much
68+
manual_swap = "allow" # Rust gpu does not like the core swap function
69+
# temporarily disabled rules
70+
inline_always = "allow" # need some hard numbers for this
71+
unreadable_literal = "allow" # Maybe fix this?
72+
useless_let_if_seq = "allow" # Maybe fix this?
73+
used_underscore_items = "allow" # Maybe fix this?
74+
no_effect_underscore_binding = "allow" # Maybe fix this?
75+
76+
# standard rules for idiomatic Rust code
5477
let_and_return = "allow"
5578
needless_lifetimes = "allow"
5679
option_if_let_else = "allow"

shaders/src/lib.rs

Lines changed: 97 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,42 +5,120 @@ use shader_prelude::*;
55
pub mod shaders;
66
pub mod shared_data;
77

8+
// Compute optimal grid layout (rows, cols) for cell count while attempting to keep the aspect ratio close to the provided aspect ratio.
9+
fn optimal_grid(cell_count: usize, aspect: Vec2) -> (usize, usize) {
10+
// Handle edge cases for 0 or 1 cells.
11+
if cell_count == 0 {
12+
return (0, 0);
13+
}
14+
if cell_count == 1 {
15+
return (1, 1);
16+
}
17+
18+
// The target aspect ratio (width / height). Add a small epsilon to avoid division by zero.
19+
let target_aspect = aspect.x / (aspect.y + f32::EPSILON);
20+
21+
let mut best_layout = (1, cell_count);
22+
let mut min_aspect_diff = f32::INFINITY;
23+
24+
// Iterate through all possible row counts from 1 to cell_count.
25+
// This is a simple and robust way to find the global optimum.
26+
for rows in 1..=cell_count {
27+
// Calculate the number of columns needed to fit all cells for the current row count.
28+
// This is equivalent to `ceil(cell_count / rows)`.
29+
let cols = cell_count.div_ceil(rows);
30+
31+
// The aspect ratio of the current grid layout.
32+
let grid_aspect = cols as f32 / rows as f32;
33+
34+
// Calculate the difference from the target aspect ratio.
35+
let diff = (grid_aspect - target_aspect).abs();
36+
37+
// If this layout is better than the best one we've found so far, update it.
38+
if diff < min_aspect_diff {
39+
min_aspect_diff = diff;
40+
best_layout = (rows, cols);
41+
}
42+
}
43+
44+
best_layout
45+
}
46+
847
#[inline(always)]
48+
#[must_use]
949
pub fn fs(constants: &ShaderConstants, mut frag_coord: Vec2) -> Vec4 {
10-
let resolution = vec3(
11-
constants.width as f32 as f32,
12-
constants.height as f32 as f32,
13-
0.0,
14-
);
50+
let resolution = vec3(constants.width as f32, constants.height as f32, 0.0);
1551
let time = constants.time;
1652
let mut mouse = vec4(
17-
constants.drag_end_x as f32,
18-
constants.drag_end_y as f32,
19-
constants.drag_start_x as f32,
20-
constants.drag_start_y as f32,
53+
constants.drag_end_x,
54+
constants.drag_end_y,
55+
constants.drag_start_x,
56+
constants.drag_start_y,
2157
);
2258
if mouse != Vec4::ZERO {
2359
mouse.y = resolution.y - mouse.y;
2460
mouse.w = resolution.y - mouse.w;
2561
}
26-
if !(constants.mouse_left_pressed == 1) {
62+
if constants.mouse_left_pressed != 1 {
2763
mouse.z *= -1.0;
2864
}
29-
if !(constants.mouse_left_clicked == 1) {
65+
if constants.mouse_left_clicked != 1 {
3066
mouse.w *= -1.0;
3167
}
3268

3369
frag_coord.x %= resolution.x;
3470
frag_coord.y = resolution.y - frag_coord.y % resolution.y;
3571

36-
let shader_input = ShaderInput {
37-
resolution,
38-
time,
39-
frag_coord,
40-
mouse,
41-
};
42-
let mut shader_output = &mut ShaderResult { color: Vec4::ZERO };
43-
shaders::render_shader(constants.shader_to_show, &shader_input, &mut shader_output);
72+
let shader_count = shaders::SHADER_DEFINITIONS.len();
73+
74+
let shader_index;
75+
let shader_input: ShaderInput;
76+
let shader_output = &mut ShaderResult { color: Vec4::ZERO };
77+
78+
if constants.grid == 0 {
79+
shader_input = ShaderInput {
80+
resolution,
81+
time,
82+
frag_coord,
83+
mouse,
84+
};
85+
shader_index = constants.shader_to_show as usize;
86+
} else {
87+
// Render all shaders in a grid layout
88+
// ignore shader_to_show
89+
let (rows, cols) = optimal_grid(shader_count, vec2(resolution.x, resolution.y));
90+
91+
let cell_width = resolution.x / cols as f32;
92+
let cell_height = resolution.y / rows as f32;
93+
94+
#[expect(clippy::cast_sign_loss)]
95+
let col = (frag_coord.x / cell_width).floor() as usize;
96+
#[expect(clippy::cast_sign_loss)]
97+
let row = (frag_coord.y / cell_height).floor() as usize;
98+
shader_index = row + col * rows;
99+
100+
let cell_resolution = vec3(cell_width, cell_height, 0.0);
101+
let cell_frag_coord = vec2(
102+
(col as f32).mul_add(-cell_width, frag_coord.x),
103+
(row as f32).mul_add(-cell_height, frag_coord.y),
104+
);
105+
let cell_mouse = mouse / vec4(cols as f32, rows as f32, cols as f32, rows as f32);
106+
107+
shader_input = ShaderInput {
108+
resolution: cell_resolution,
109+
time,
110+
frag_coord: cell_frag_coord,
111+
mouse: cell_mouse,
112+
};
113+
}
114+
115+
if shader_index < shader_count {
116+
shaders::render_shader(shader_index as u32, &shader_input, shader_output);
117+
} else {
118+
// If the shader index is out of bounds, just return a default color
119+
shader_output.color = Vec4::new(0.0, 0.0, 0.0, 1.0);
120+
}
121+
44122
let color = shader_output.color;
45123
Vec3::powf(color.truncate(), 2.2).extend(color.w)
46124
}

shaders/src/shader_prelude.rs

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
pub use core::f32::consts::{FRAC_1_PI, FRAC_PI_2, PI};
22
use core::ops::{Add, Mul, Sub};
33
pub const TWO_PI: f32 = 2.0 * PI;
4-
pub const SQRT3: f32 = 1.7320508075688772;
4+
/// We can't use the `f32::consts::SQRT_3` constant here because it is an unstable library feature
5+
pub const SQRT_3: f32 = 1.732_050_807_568_877_2;
56

67
pub use crate::shared_data::ShaderConstants;
78
pub use spirv_std::{
@@ -82,7 +83,7 @@ pub fn saturate(a: f32) -> f32 {
8283
#[must_use]
8384
pub fn acos_approx(v: f32) -> f32 {
8485
let x = v.abs();
85-
let mut res = -0.155972 * x + 1.56467; // p(x)
86+
let mut res = (-0.155_972_f32).mul_add(x, 1.56467); // p(x)
8687
res *= (1.0f32 - x).sqrt();
8788

8889
if v >= 0.0 {
@@ -98,7 +99,7 @@ pub fn smoothstep(edge0: f32, edge1: f32, x: f32) -> f32 {
9899
// Scale, bias and saturate x to 0..1 range
99100
let x = saturate((x - edge0) / (edge1 - edge0));
100101
// Evaluate polynomial
101-
x * x * (3.0 - 2.0 * x)
102+
x * x * 2.0f32.mul_add(-x, 3.0)
102103
}
103104

104105
#[inline(always)]
@@ -136,12 +137,12 @@ pub trait FloatExt {
136137

137138
impl FloatExt for f32 {
138139
#[inline]
139-
fn fract_gl(self) -> f32 {
140+
fn fract_gl(self) -> Self {
140141
self - self.floor()
141142
}
142143

143144
#[inline]
144-
fn rem_euclid(self, rhs: f32) -> f32 {
145+
fn rem_euclid(self, rhs: Self) -> Self {
145146
let r = self % rhs;
146147
if r < 0.0 {
147148
r + rhs.abs()
@@ -151,7 +152,7 @@ impl FloatExt for f32 {
151152
}
152153

153154
#[inline]
154-
fn sign_gl(self) -> f32 {
155+
fn sign_gl(self) -> Self {
155156
if self < 0.0 {
156157
-1.0
157158
} else if self == 0.0 {
@@ -162,7 +163,7 @@ impl FloatExt for f32 {
162163
}
163164

164165
#[inline]
165-
fn step(self, x: f32) -> f32 {
166+
fn step(self, x: Self) -> Self {
166167
if x < self {
167168
0.0
168169
} else {
@@ -190,69 +191,69 @@ pub trait VecExt {
190191

191192
impl VecExt for Vec2 {
192193
#[inline]
193-
fn sin(self) -> Vec2 {
194+
fn sin(self) -> Self {
194195
vec2(self.x.sin(), self.y.sin())
195196
}
196197

197198
#[inline]
198-
fn cos(self) -> Vec2 {
199+
fn cos(self) -> Self {
199200
vec2(self.x.cos(), self.y.cos())
200201
}
201202

202203
#[inline]
203-
fn powf_vec(self, p: Vec2) -> Vec2 {
204+
fn powf_vec(self, p: Self) -> Self {
204205
vec2(self.x.powf(p.x), self.y.powf(p.y))
205206
}
206207

207208
#[inline]
208-
fn sqrt(self) -> Vec2 {
209+
fn sqrt(self) -> Self {
209210
vec2(self.x.sqrt(), self.y.sqrt())
210211
}
211212

212213
#[inline]
213-
fn ln(self) -> Vec2 {
214+
fn ln(self) -> Self {
214215
vec2(self.x.ln(), self.y.ln())
215216
}
216217

217218
#[inline]
218-
fn step(self, other: Vec2) -> Vec2 {
219+
fn step(self, other: Self) -> Self {
219220
vec2(self.x.step(other.x), self.y.step(other.y))
220221
}
221222

222223
#[inline]
223-
fn sign_gl(self) -> Vec2 {
224+
fn sign_gl(self) -> Self {
224225
vec2(self.x.sign_gl(), self.y.sign_gl())
225226
}
226227
}
227228

228229
impl VecExt for Vec3 {
229230
#[inline]
230-
fn sin(self) -> Vec3 {
231+
fn sin(self) -> Self {
231232
vec3(self.x.sin(), self.y.sin(), self.z.sin())
232233
}
233234

234235
#[inline]
235-
fn cos(self) -> Vec3 {
236+
fn cos(self) -> Self {
236237
vec3(self.x.cos(), self.y.cos(), self.z.cos())
237238
}
238239

239240
#[inline]
240-
fn powf_vec(self, p: Vec3) -> Vec3 {
241+
fn powf_vec(self, p: Self) -> Self {
241242
vec3(self.x.powf(p.x), self.y.powf(p.y), self.z.powf(p.z))
242243
}
243244

244245
#[inline]
245-
fn sqrt(self) -> Vec3 {
246+
fn sqrt(self) -> Self {
246247
vec3(self.x.sqrt(), self.y.sqrt(), self.z.sqrt())
247248
}
248249

249250
#[inline]
250-
fn ln(self) -> Vec3 {
251+
fn ln(self) -> Self {
251252
vec3(self.x.ln(), self.y.ln(), self.z.ln())
252253
}
253254

254255
#[inline]
255-
fn step(self, other: Vec3) -> Vec3 {
256+
fn step(self, other: Self) -> Self {
256257
vec3(
257258
self.x.step(other.x),
258259
self.y.step(other.y),
@@ -261,24 +262,24 @@ impl VecExt for Vec3 {
261262
}
262263

263264
#[inline]
264-
fn sign_gl(self) -> Vec3 {
265+
fn sign_gl(self) -> Self {
265266
vec3(self.x.sign_gl(), self.y.sign_gl(), self.z.sign_gl())
266267
}
267268
}
268269

269270
impl VecExt for Vec4 {
270271
#[inline]
271-
fn sin(self) -> Vec4 {
272+
fn sin(self) -> Self {
272273
vec4(self.x.sin(), self.y.sin(), self.z.sin(), self.w.sin())
273274
}
274275

275276
#[inline]
276-
fn cos(self) -> Vec4 {
277+
fn cos(self) -> Self {
277278
vec4(self.x.cos(), self.y.cos(), self.z.cos(), self.w.cos())
278279
}
279280

280281
#[inline]
281-
fn powf_vec(self, p: Vec4) -> Vec4 {
282+
fn powf_vec(self, p: Self) -> Self {
282283
vec4(
283284
self.x.powf(p.x),
284285
self.y.powf(p.y),
@@ -288,17 +289,17 @@ impl VecExt for Vec4 {
288289
}
289290

290291
#[inline]
291-
fn sqrt(self) -> Vec4 {
292+
fn sqrt(self) -> Self {
292293
vec4(self.x.sqrt(), self.y.sqrt(), self.z.sqrt(), self.w.sqrt())
293294
}
294295

295296
#[inline]
296-
fn ln(self) -> Vec4 {
297+
fn ln(self) -> Self {
297298
vec4(self.x.ln(), self.y.ln(), self.z.ln(), self.w.ln())
298299
}
299300

300301
#[inline]
301-
fn step(self, other: Vec4) -> Vec4 {
302+
fn step(self, other: Self) -> Self {
302303
vec4(
303304
self.x.step(other.x),
304305
self.y.step(other.y),
@@ -308,7 +309,7 @@ impl VecExt for Vec4 {
308309
}
309310

310311
#[inline]
311-
fn sign_gl(self) -> Vec4 {
312+
fn sign_gl(self) -> Self {
312313
vec4(
313314
self.x.sign_gl(),
314315
self.y.sign_gl(),

shaders/src/shaders/a_lot_of_spheres.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderRes
2525
frag_coord,
2626
..
2727
} = render_instruction;
28-
Inputs { resolution, time }.main_image(color, frag_coord)
28+
Inputs { resolution, time }.main_image(color, frag_coord);
2929
}
3030

3131
pub struct Inputs {
@@ -77,7 +77,7 @@ fn intersect_plane(ro: Vec3, rd: Vec3, height: f32, dist: &mut f32) -> bool {
7777
}
7878

7979
let mut d: f32 = -(ro.y - height) / rd.y;
80-
d = d.min(100000.0);
80+
d = d.min(100_000.0);
8181
if d > 0.0 {
8282
*dist = d;
8383
return true;

0 commit comments

Comments
 (0)