From b1b79219437cf40bc0434805574f62022e3f3296 Mon Sep 17 00:00:00 2001 From: raldone01 Date: Sat, 7 Jun 2025 14:15:37 +0200 Subject: [PATCH 1/7] Move shaders into subfolder. --- shaders/src/lib.rs | 30 ++----------------- shaders/src/{ => shaders}/a_lot_of_spheres.rs | 0 .../src/{ => shaders}/a_question_of_time.rs | 0 shaders/src/{ => shaders}/apollonian.rs | 0 .../{ => shaders}/atmosphere_system_test.rs | 0 .../src/{ => shaders}/bubble_buckey_balls.rs | 0 shaders/src/{ => shaders}/clouds.rs | 0 .../{ => shaders}/filtering_procedurals.rs | 0 shaders/src/{ => shaders}/flappy_bird.rs | 0 .../src/{ => shaders}/galaxy_of_universes.rs | 0 shaders/src/{ => shaders}/geodesic_tiling.rs | 0 shaders/src/{ => shaders}/heart.rs | 0 shaders/src/{ => shaders}/luminescence.rs | 0 .../src/{ => shaders}/mandelbrot_smooth.rs | 0 .../src/{ => shaders}/miracle_snowflakes.rs | 0 shaders/src/shaders/mod.rs | 28 +++++++++++++++++ shaders/src/{ => shaders}/morphing.rs | 0 shaders/src/{ => shaders}/moving_square.rs | 0 shaders/src/{ => shaders}/on_off_spikes.rs | 0 shaders/src/{ => shaders}/phantom_star.rs | 0 shaders/src/{ => shaders}/playing_marble.rs | 0 shaders/src/{ => shaders}/protean_clouds.rs | 0 .../{ => shaders}/raymarching_primitives.rs | 0 shaders/src/{ => shaders}/seascape.rs | 0 shaders/src/{ => shaders}/skyline.rs | 0 .../{ => shaders}/soft_shadow_variation.rs | 0 .../{ => shaders}/tileable_water_caustic.rs | 0 shaders/src/{ => shaders}/tokyo.rs | 0 shaders/src/{ => shaders}/two_tweets.rs | 0 shaders/src/{ => shaders}/voxel_pac_man.rs | 0 30 files changed, 30 insertions(+), 28 deletions(-) rename shaders/src/{ => shaders}/a_lot_of_spheres.rs (100%) rename shaders/src/{ => shaders}/a_question_of_time.rs (100%) rename shaders/src/{ => shaders}/apollonian.rs (100%) rename shaders/src/{ => shaders}/atmosphere_system_test.rs (100%) rename shaders/src/{ => shaders}/bubble_buckey_balls.rs (100%) rename shaders/src/{ => shaders}/clouds.rs (100%) rename shaders/src/{ => shaders}/filtering_procedurals.rs (100%) rename shaders/src/{ => shaders}/flappy_bird.rs (100%) rename shaders/src/{ => shaders}/galaxy_of_universes.rs (100%) rename shaders/src/{ => shaders}/geodesic_tiling.rs (100%) rename shaders/src/{ => shaders}/heart.rs (100%) rename shaders/src/{ => shaders}/luminescence.rs (100%) rename shaders/src/{ => shaders}/mandelbrot_smooth.rs (100%) rename shaders/src/{ => shaders}/miracle_snowflakes.rs (100%) create mode 100644 shaders/src/shaders/mod.rs rename shaders/src/{ => shaders}/morphing.rs (100%) rename shaders/src/{ => shaders}/moving_square.rs (100%) rename shaders/src/{ => shaders}/on_off_spikes.rs (100%) rename shaders/src/{ => shaders}/phantom_star.rs (100%) rename shaders/src/{ => shaders}/playing_marble.rs (100%) rename shaders/src/{ => shaders}/protean_clouds.rs (100%) rename shaders/src/{ => shaders}/raymarching_primitives.rs (100%) rename shaders/src/{ => shaders}/seascape.rs (100%) rename shaders/src/{ => shaders}/skyline.rs (100%) rename shaders/src/{ => shaders}/soft_shadow_variation.rs (100%) rename shaders/src/{ => shaders}/tileable_water_caustic.rs (100%) rename shaders/src/{ => shaders}/tokyo.rs (100%) rename shaders/src/{ => shaders}/two_tweets.rs (100%) rename shaders/src/{ => shaders}/voxel_pac_man.rs (100%) diff --git a/shaders/src/lib.rs b/shaders/src/lib.rs index bd959aa..e84e94e 100644 --- a/shaders/src/lib.rs +++ b/shaders/src/lib.rs @@ -4,34 +4,8 @@ use shared::*; use spirv_std::glam::{vec2, vec3, vec4, Vec2, Vec3, Vec4}; use spirv_std::spirv; -pub mod a_lot_of_spheres; -pub mod a_question_of_time; -pub mod apollonian; -pub mod atmosphere_system_test; -pub mod bubble_buckey_balls; -pub mod clouds; -pub mod filtering_procedurals; -pub mod flappy_bird; -pub mod galaxy_of_universes; -pub mod geodesic_tiling; -pub mod heart; -pub mod luminescence; -pub mod mandelbrot_smooth; -pub mod miracle_snowflakes; -pub mod morphing; -pub mod moving_square; -pub mod on_off_spikes; -pub mod phantom_star; -pub mod playing_marble; -pub mod protean_clouds; -pub mod raymarching_primitives; -pub mod seascape; -pub mod skyline; -pub mod soft_shadow_variation; -pub mod tileable_water_caustic; -pub mod tokyo; -pub mod two_tweets; -pub mod voxel_pac_man; +mod shaders; +use shaders::*; pub trait SampleCube: Copy { fn sample_cube(self, p: Vec3) -> Vec4; diff --git a/shaders/src/a_lot_of_spheres.rs b/shaders/src/shaders/a_lot_of_spheres.rs similarity index 100% rename from shaders/src/a_lot_of_spheres.rs rename to shaders/src/shaders/a_lot_of_spheres.rs diff --git a/shaders/src/a_question_of_time.rs b/shaders/src/shaders/a_question_of_time.rs similarity index 100% rename from shaders/src/a_question_of_time.rs rename to shaders/src/shaders/a_question_of_time.rs diff --git a/shaders/src/apollonian.rs b/shaders/src/shaders/apollonian.rs similarity index 100% rename from shaders/src/apollonian.rs rename to shaders/src/shaders/apollonian.rs diff --git a/shaders/src/atmosphere_system_test.rs b/shaders/src/shaders/atmosphere_system_test.rs similarity index 100% rename from shaders/src/atmosphere_system_test.rs rename to shaders/src/shaders/atmosphere_system_test.rs diff --git a/shaders/src/bubble_buckey_balls.rs b/shaders/src/shaders/bubble_buckey_balls.rs similarity index 100% rename from shaders/src/bubble_buckey_balls.rs rename to shaders/src/shaders/bubble_buckey_balls.rs diff --git a/shaders/src/clouds.rs b/shaders/src/shaders/clouds.rs similarity index 100% rename from shaders/src/clouds.rs rename to shaders/src/shaders/clouds.rs diff --git a/shaders/src/filtering_procedurals.rs b/shaders/src/shaders/filtering_procedurals.rs similarity index 100% rename from shaders/src/filtering_procedurals.rs rename to shaders/src/shaders/filtering_procedurals.rs diff --git a/shaders/src/flappy_bird.rs b/shaders/src/shaders/flappy_bird.rs similarity index 100% rename from shaders/src/flappy_bird.rs rename to shaders/src/shaders/flappy_bird.rs diff --git a/shaders/src/galaxy_of_universes.rs b/shaders/src/shaders/galaxy_of_universes.rs similarity index 100% rename from shaders/src/galaxy_of_universes.rs rename to shaders/src/shaders/galaxy_of_universes.rs diff --git a/shaders/src/geodesic_tiling.rs b/shaders/src/shaders/geodesic_tiling.rs similarity index 100% rename from shaders/src/geodesic_tiling.rs rename to shaders/src/shaders/geodesic_tiling.rs diff --git a/shaders/src/heart.rs b/shaders/src/shaders/heart.rs similarity index 100% rename from shaders/src/heart.rs rename to shaders/src/shaders/heart.rs diff --git a/shaders/src/luminescence.rs b/shaders/src/shaders/luminescence.rs similarity index 100% rename from shaders/src/luminescence.rs rename to shaders/src/shaders/luminescence.rs diff --git a/shaders/src/mandelbrot_smooth.rs b/shaders/src/shaders/mandelbrot_smooth.rs similarity index 100% rename from shaders/src/mandelbrot_smooth.rs rename to shaders/src/shaders/mandelbrot_smooth.rs diff --git a/shaders/src/miracle_snowflakes.rs b/shaders/src/shaders/miracle_snowflakes.rs similarity index 100% rename from shaders/src/miracle_snowflakes.rs rename to shaders/src/shaders/miracle_snowflakes.rs diff --git a/shaders/src/shaders/mod.rs b/shaders/src/shaders/mod.rs new file mode 100644 index 0000000..8a48999 --- /dev/null +++ b/shaders/src/shaders/mod.rs @@ -0,0 +1,28 @@ +pub mod a_lot_of_spheres; +pub mod a_question_of_time; +pub mod apollonian; +pub mod atmosphere_system_test; +pub mod bubble_buckey_balls; +pub mod clouds; +pub mod filtering_procedurals; +pub mod flappy_bird; +pub mod galaxy_of_universes; +pub mod geodesic_tiling; +pub mod heart; +pub mod luminescence; +pub mod mandelbrot_smooth; +pub mod miracle_snowflakes; +pub mod morphing; +pub mod moving_square; +pub mod on_off_spikes; +pub mod phantom_star; +pub mod playing_marble; +pub mod protean_clouds; +pub mod raymarching_primitives; +pub mod seascape; +pub mod skyline; +pub mod soft_shadow_variation; +pub mod tileable_water_caustic; +pub mod tokyo; +pub mod two_tweets; +pub mod voxel_pac_man; diff --git a/shaders/src/morphing.rs b/shaders/src/shaders/morphing.rs similarity index 100% rename from shaders/src/morphing.rs rename to shaders/src/shaders/morphing.rs diff --git a/shaders/src/moving_square.rs b/shaders/src/shaders/moving_square.rs similarity index 100% rename from shaders/src/moving_square.rs rename to shaders/src/shaders/moving_square.rs diff --git a/shaders/src/on_off_spikes.rs b/shaders/src/shaders/on_off_spikes.rs similarity index 100% rename from shaders/src/on_off_spikes.rs rename to shaders/src/shaders/on_off_spikes.rs diff --git a/shaders/src/phantom_star.rs b/shaders/src/shaders/phantom_star.rs similarity index 100% rename from shaders/src/phantom_star.rs rename to shaders/src/shaders/phantom_star.rs diff --git a/shaders/src/playing_marble.rs b/shaders/src/shaders/playing_marble.rs similarity index 100% rename from shaders/src/playing_marble.rs rename to shaders/src/shaders/playing_marble.rs diff --git a/shaders/src/protean_clouds.rs b/shaders/src/shaders/protean_clouds.rs similarity index 100% rename from shaders/src/protean_clouds.rs rename to shaders/src/shaders/protean_clouds.rs diff --git a/shaders/src/raymarching_primitives.rs b/shaders/src/shaders/raymarching_primitives.rs similarity index 100% rename from shaders/src/raymarching_primitives.rs rename to shaders/src/shaders/raymarching_primitives.rs diff --git a/shaders/src/seascape.rs b/shaders/src/shaders/seascape.rs similarity index 100% rename from shaders/src/seascape.rs rename to shaders/src/shaders/seascape.rs diff --git a/shaders/src/skyline.rs b/shaders/src/shaders/skyline.rs similarity index 100% rename from shaders/src/skyline.rs rename to shaders/src/shaders/skyline.rs diff --git a/shaders/src/soft_shadow_variation.rs b/shaders/src/shaders/soft_shadow_variation.rs similarity index 100% rename from shaders/src/soft_shadow_variation.rs rename to shaders/src/shaders/soft_shadow_variation.rs diff --git a/shaders/src/tileable_water_caustic.rs b/shaders/src/shaders/tileable_water_caustic.rs similarity index 100% rename from shaders/src/tileable_water_caustic.rs rename to shaders/src/shaders/tileable_water_caustic.rs diff --git a/shaders/src/tokyo.rs b/shaders/src/shaders/tokyo.rs similarity index 100% rename from shaders/src/tokyo.rs rename to shaders/src/shaders/tokyo.rs diff --git a/shaders/src/two_tweets.rs b/shaders/src/shaders/two_tweets.rs similarity index 100% rename from shaders/src/two_tweets.rs rename to shaders/src/shaders/two_tweets.rs diff --git a/shaders/src/voxel_pac_man.rs b/shaders/src/shaders/voxel_pac_man.rs similarity index 100% rename from shaders/src/voxel_pac_man.rs rename to shaders/src/shaders/voxel_pac_man.rs From 443de1387ebd4d7f5bafd9bd2aedb2a844701224 Mon Sep 17 00:00:00 2001 From: raldone01 Date: Sat, 7 Jun 2025 14:50:17 +0200 Subject: [PATCH 2/7] * Get rid of shared crate. * Add lint rules. * Add `rustfmt.toml` for predictable formatting. * Update dependencies. * Add a shader prelude. --- .gitattributes | 11 + .gitignore | 1 + .vscode/settings.json | 4 + Cargo.lock | 16 +- Cargo.toml | 82 +++++- clippy.toml | 1 + rustfmt.toml | 13 + shaders/Cargo.toml | 2 +- shaders/src/lib.rs | 257 ++++++------------ .../lib.rs => shaders/src/shader_prelude.rs | 194 +++++++++---- shaders/src/shaders/a_lot_of_spheres.rs | 31 ++- shaders/src/shaders/a_question_of_time.rs | 39 ++- shaders/src/shaders/apollonian.rs | 50 ++-- shaders/src/shaders/atmosphere_system_test.rs | 45 ++- shaders/src/shaders/bubble_buckey_balls.rs | 61 +++-- shaders/src/shaders/clouds.rs | 24 +- shaders/src/shaders/filtering_procedurals.rs | 42 ++- shaders/src/shaders/flappy_bird.rs | 37 ++- shaders/src/shaders/galaxy_of_universes.rs | 29 +- shaders/src/shaders/geodesic_tiling.rs | 48 ++-- shaders/src/shaders/heart.rs | 27 +- shaders/src/shaders/luminescence.rs | 46 +++- shaders/src/shaders/mandelbrot_smooth.rs | 29 +- shaders/src/shaders/miracle_snowflakes.rs | 44 ++- shaders/src/shaders/mod.rs | 117 ++++++-- shaders/src/shaders/morphing.rs | 46 ++-- shaders/src/shaders/moving_square.rs | 30 +- shaders/src/shaders/on_off_spikes.rs | 44 ++- shaders/src/shaders/phantom_star.rs | 32 ++- shaders/src/shaders/playing_marble.rs | 48 +++- shaders/src/shaders/protean_clouds.rs | 44 ++- shaders/src/shaders/raymarching_primitives.rs | 38 ++- shaders/src/shaders/seascape.rs | 39 ++- shaders/src/shaders/skyline.rs | 53 ++-- shaders/src/shaders/soft_shadow_variation.rs | 31 ++- shaders/src/shaders/tileable_water_caustic.rs | 29 +- shaders/src/shaders/tokyo.rs | 36 ++- shaders/src/shaders/two_tweets.rs | 26 +- shaders/src/shaders/voxel_pac_man.rs | 48 ++-- shaders/src/shared_data.rs | 21 ++ shared/Cargo.toml | 12 - src/main.rs | 97 +++++-- 42 files changed, 1246 insertions(+), 678 deletions(-) create mode 100644 .gitattributes create mode 100644 .vscode/settings.json create mode 100644 clippy.toml create mode 100644 rustfmt.toml rename shared/src/lib.rs => shaders/src/shader_prelude.rs (54%) create mode 100644 shaders/src/shared_data.rs delete mode 100644 shared/Cargo.toml diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..e7254ec --- /dev/null +++ b/.gitattributes @@ -0,0 +1,11 @@ +# From: https://docs.github.com/en/github/getting-started-with-github/configuring-git-to-handle-line-endings +# Set the default behavior for line endings. +* text=auto eol=lf + +# Declare files that will always have CRLF line endings on checkout. +*.sln text eol=crlf + +# Denote all files that are truly binary and should not be modified. +*.png binary +*.jpg binary +*.ttf binary diff --git a/.gitignore b/.gitignore index ea8c4bf..fac57f6 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +rustc-ice-*.txt diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..65980e2 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "rust-analyzer.cargo.targetDir": true, + //"rust-analyzer.check.command": "clippy", +} diff --git a/Cargo.lock b/Cargo.lock index 3f6a7b2..84f0bbf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -251,9 +251,9 @@ checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "bytemuck" -version = "1.22.0" +version = "1.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540" +checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c" dependencies = [ "bytemuck_derive", ] @@ -1869,7 +1869,7 @@ dependencies = [ name = "shadertoys-shaders" version = "0.0.0" dependencies = [ - "shared", + "bytemuck", "spirv-std", ] @@ -1881,7 +1881,7 @@ dependencies = [ "env_logger", "futures", "ouroboros", - "shared", + "shadertoys-shaders", "spirv-builder", "wgpu", "winit", @@ -1896,14 +1896,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "shared" -version = "0.0.0" -dependencies = [ - "bytemuck", - "spirv-std", -] - [[package]] name = "shlex" version = "1.3.0" diff --git a/Cargo.toml b/Cargo.toml index 6683f46..26afd70 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,17 +11,14 @@ use-installed-tools = ["spirv-builder/use-installed-tools"] use-compiled-tools = ["spirv-builder/use-compiled-tools"] [dependencies] -shared = { path = "shared" } +shadertoys-shaders = { path = "shaders" } futures = { version = "0.3", default-features = false, features = [ "std", - "executor" -] } -wgpu = { version = "25.0.0", features = [ - "spirv", - "vulkan-portability" + "executor", ] } +wgpu = { version = "25.0.0", features = ["spirv", "vulkan-portability"] } winit = { git = "https://github.com/rust-windowing/winit.git", rev = "cdbdd974fbf79b82b3fb1a4bc84ed717312a3bd2" } -bytemuck = "1.20.0" +bytemuck = "1.23.0" env_logger = "0.11.6" ouroboros = "0.18.5" @@ -29,7 +26,7 @@ ouroboros = "0.18.5" spirv-builder.workspace = true [workspace] -members = ["shaders", "shared"] +members = ["shaders"] [workspace.dependencies] spirv-builder = { git = "https://github.com/Rust-GPU/rust-gpu", rev = "0b37696e9f5edde8fa0c1363a88e6c8cb8e6ff68", default-features = false } @@ -53,7 +50,74 @@ opt-level = 3 [profile.release.package."shadertoys-shaders"] opt-level = 0 +[workspace.lints.clippy] +# disabled because shader code does this often +cast_precision_loss = "allow" +cast_possible_truncation = "allow" +excessive_precision = "allow" +missing_const_for_fn = "allow" +many_single_char_names = "allow" +similar_names = "allow" +too_many_arguments = "allow" +suboptimal_flops = "allow" +too_many_lines = "allow" +cognitive_complexity = "allow" +# disabled because of rust gpu limitatoins +manual_range_contains = "allow" # Rust gpu does not like the core range checks +needless_range_loop = "allow" # Rust gpu does not like iterators very much +manual_swap = "allow" # Rust gpu does not like the core swap function +# temporarily disabled rules +inline_always = "allow" # need some hard numbers for this +unreadable_literal = "allow" # Maybe fix this? +useless_let_if_seq = "allow" # Maybe fix this? +used_underscore_items = "allow" # Maybe fix this? +no_effect_underscore_binding = "allow" # Maybe fix this? + +# standard rules for idiomatic Rust code +let_and_return = "allow" +needless_lifetimes = "allow" +option_if_let_else = "allow" +# see: https://github.com/bevyengine/bevy/pull/15375#issuecomment-2366966219 +too_long_first_doc_paragraph = "allow" +missing_panics_doc = "allow" +doc-markdown = "allow" + +nursery = { priority = -1, level = "warn" } +pedantic = { priority = -1, level = "warn" } +doc_markdown = "warn" +manual_let_else = "warn" +match_same_arms = "warn" +redundant_closure_for_method_calls = "warn" +redundant_else = "warn" +semicolon_if_nothing_returned = "warn" +type_complexity = "allow" +undocumented_unsafe_blocks = "warn" +unwrap_or_default = "warn" + +ptr_as_ptr = "warn" +ptr_cast_constness = "warn" +ref_as_ptr = "warn" + +std_instead_of_core = "warn" +std_instead_of_alloc = "warn" +alloc_instead_of_core = "warn" + [workspace.lints.rust] +nonstandard-style = "warn" +future-incompatible = "warn" +missing_docs = "allow" # TODO: warn +unused = { priority = -1, level = "warn" } +rust_2018_idioms = { priority = -1, level = "warn" } +rust-2024-compatibility = "warn" +array-into-iter = "warn" +bare-trait-objects = "warn" +ellipsis-inclusive-range-patterns = "warn" +non-fmt-panics = "warn" +explicit-outlives-requirements = "warn" +unused-extern-crates = "warn" +unsafe_code = "allow" # TODO: forbid +unsafe_op_in_unsafe_fn = "warn" +unused_qualifications = "warn" unexpected_cfgs = { level = "allow", check-cfg = [ - 'cfg(target_arch, values("spirv"))' + 'cfg(target_arch, values("spirv"))', ] } diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 0000000..8483b87 --- /dev/null +++ b/clippy.toml @@ -0,0 +1 @@ +check-private-items = true diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..a75a460 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,13 @@ +match_block_trailing_comma = true +tab_spaces = 4 +condense_wildcard_suffixes = false +newline_style = "Unix" + +# The options below are unstable +unstable_features = true +imports_granularity = "Crate" +normalize_comments = false # Often doesn't do what you want + +# these options seem poorly implemented and cause churn, so, try to avoid them +# wrap_comments = true +# comment_width = 100 diff --git a/shaders/Cargo.toml b/shaders/Cargo.toml index 7640fd6..0db5533 100644 --- a/shaders/Cargo.toml +++ b/shaders/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["dylib"] [dependencies] spirv-std.workspace = true -shared = { path = "../shared" } +bytemuck = { version = "1.23.0", features = ["derive"] } [lints] workspace = true diff --git a/shaders/src/lib.rs b/shaders/src/lib.rs index e84e94e..7946058 100644 --- a/shaders/src/lib.rs +++ b/shaders/src/lib.rs @@ -1,202 +1,125 @@ #![cfg_attr(target_arch = "spirv", no_std)] -use shared::*; -use spirv_std::glam::{vec2, vec3, vec4, Vec2, Vec3, Vec4}; -use spirv_std::spirv; +pub mod shader_prelude; +use shader_prelude::*; +pub mod shaders; +pub mod shared_data; -mod shaders; -use shaders::*; +// Compute optimal grid layout (rows, cols) for cell count while attempting to keep the aspect ratio close to the provided aspect ratio. +fn optimal_grid(cell_count: usize, aspect: Vec2) -> (usize, usize) { + // Handle edge cases for 0 or 1 cells. + if cell_count == 0 { + return (0, 0); + } + if cell_count == 1 { + return (1, 1); + } -pub trait SampleCube: Copy { - fn sample_cube(self, p: Vec3) -> Vec4; -} + // The target aspect ratio (width / height). Add a small epsilon to avoid division by zero. + let target_aspect = aspect.x / (aspect.y + f32::EPSILON); -#[derive(Copy, Clone)] -struct ConstantColor { - color: Vec4, -} + let mut best_layout = (1, cell_count); + let mut min_aspect_diff = f32::INFINITY; -impl SampleCube for ConstantColor { - fn sample_cube(self, _: Vec3) -> Vec4 { - self.color - } -} + // Iterate through all possible row counts from 1 to cell_count. + // This is a simple and robust way to find the global optimum. + for rows in 1..=cell_count { + // Calculate the number of columns needed to fit all cells for the current row count. + // This is equivalent to `ceil(cell_count / rows)`. + let cols = cell_count.div_ceil(rows); -#[derive(Copy, Clone)] -struct RgbCube { - alpha: f32, - intensity: f32, -} + // The aspect ratio of the current grid layout. + let grid_aspect = cols as f32 / rows as f32; -impl SampleCube for RgbCube { - fn sample_cube(self, p: Vec3) -> Vec4 { - (p.abs() * self.intensity).extend(self.alpha) + // Calculate the difference from the target aspect ratio. + let diff = (grid_aspect - target_aspect).abs(); + + // If this layout is better than the best one we've found so far, update it. + if diff < min_aspect_diff { + min_aspect_diff = diff; + best_layout = (rows, cols); + } } + + best_layout } +#[inline(always)] +#[must_use] pub fn fs(constants: &ShaderConstants, mut frag_coord: Vec2) -> Vec4 { - const COLS: usize = 6; - const ROWS: usize = 5; - - let resolution = vec3( - constants.width as f32 / COLS as f32, - constants.height as f32 / ROWS as f32, - 0.0, - ); + let resolution = vec3(constants.width as f32, constants.height as f32, 0.0); let time = constants.time; let mut mouse = vec4( - constants.drag_end_x / COLS as f32, - constants.drag_end_y / ROWS as f32, - constants.drag_start_x / COLS as f32, - constants.drag_start_y / ROWS as f32, + constants.drag_end_x, + constants.drag_end_y, + constants.drag_start_x, + constants.drag_start_y, ); if mouse != Vec4::ZERO { mouse.y = resolution.y - mouse.y; mouse.w = resolution.y - mouse.w; } - if !(constants.mouse_left_pressed == 1) { + if constants.mouse_left_pressed != 1 { mouse.z *= -1.0; } - if !(constants.mouse_left_clicked == 1) { + if constants.mouse_left_clicked != 1 { mouse.w *= -1.0; } - let col = (frag_coord.x / resolution.x) as usize; - let row = (frag_coord.y / resolution.y) as usize; - let i = row * COLS + col; - frag_coord.x %= resolution.x; frag_coord.y = resolution.y - frag_coord.y % resolution.y; - let mut color = Vec4::ZERO; - match i { - 0 => two_tweets::Inputs { resolution, time }.main_image(&mut color, frag_coord), - 1 => heart::Inputs { resolution, time }.main_image(&mut color, frag_coord), - 2 => clouds::Inputs { resolution, time }.main_image(&mut color, frag_coord), - 3 => mandelbrot_smooth::Inputs { resolution, time }.main_image(&mut color, frag_coord), - 4 => protean_clouds::State::new(protean_clouds::Inputs { - resolution, - time, - mouse, - }) - .main_image(&mut color, frag_coord), - 5 => tileable_water_caustic::Inputs { resolution, time }.main_image(&mut color, frag_coord), - 6 => apollonian::State::new(apollonian::Inputs { - resolution, - time, - mouse, - }) - .main_image(&mut color, frag_coord), - 7 => phantom_star::Inputs { resolution, time }.main_image(&mut color, frag_coord), - 8 => seascape::Inputs { - resolution, - time, - mouse, - } - .main_image(&mut color, frag_coord), - 9 => playing_marble::Inputs { - resolution, - time, - mouse, - channel0: RgbCube { - alpha: 1.0, - intensity: 1.0, - }, - } - .main_image(&mut color, frag_coord), - 10 => a_lot_of_spheres::Inputs { resolution, time }.main_image(&mut color, frag_coord), - 11 => a_question_of_time::Inputs { - resolution, - time, - mouse, - } - .main_image(&mut color, frag_coord), - 12 => galaxy_of_universes::Inputs { resolution, time }.main_image(&mut color, frag_coord), - 13 => atmosphere_system_test::State::new(atmosphere_system_test::Inputs { - resolution, - time, - mouse, - }) - .main_image(&mut color, frag_coord), - 14 => soft_shadow_variation::Inputs { resolution, time }.main_image(&mut color, frag_coord), - 15 => miracle_snowflakes::State::new(miracle_snowflakes::Inputs { - resolution, - time, - mouse, - }) - .main_image(&mut color, frag_coord), - 16 => morphing::State::new(morphing::Inputs { - resolution, - time, - mouse, - }) - .main_image(&mut color, frag_coord), - 17 => bubble_buckey_balls::State::new(bubble_buckey_balls::Inputs { - resolution, - time, - mouse, - channel0: RgbCube { - alpha: 1.0, - intensity: 0.5, - }, - channel1: ConstantColor { color: Vec4::ONE }, - }) - .main_image(&mut color, frag_coord), - 18 => raymarching_primitives::Inputs { - resolution, - frame: (time * 60.0) as i32, - time, - mouse, - } - .main_image(&mut color, frag_coord), - 19 => moving_square::Inputs { resolution, time }.main_image(&mut color, frag_coord), - 20 => skyline::State::new(skyline::Inputs { - resolution, - time, - mouse, - channel0: RgbCube { - alpha: 1.0, - intensity: 1.0, - }, - }) - .main_image(&mut color, frag_coord), - 21 => filtering_procedurals::Inputs { - resolution, - time, - mouse, - } - .main_image(&mut color, frag_coord), - 22 => geodesic_tiling::State::new(geodesic_tiling::Inputs { - resolution, - time, - mouse, - }) - .main_image(&mut color, frag_coord), - 23 => flappy_bird::State::new(flappy_bird::Inputs { resolution, time }) - .main_image(&mut color, frag_coord), - 24 => { - tokyo::State::new(tokyo::Inputs { resolution, time }).main_image(&mut color, frag_coord) - } - 25 => on_off_spikes::State::new(on_off_spikes::Inputs { - resolution, - time, - mouse, - }) - .main_image(&mut color, frag_coord), - 26 => luminescence::State::new(luminescence::Inputs { + let shader_count = shaders::SHADER_DEFINITIONS.len(); + + let shader_index; + let shader_input: ShaderInput; + let shader_output = &mut ShaderResult { color: Vec4::ZERO }; + + if constants.grid == 0 { + shader_input = ShaderInput { resolution, time, + frag_coord, mouse, - }) - .main_image(&mut color, frag_coord), - 27 => voxel_pac_man::State::new(voxel_pac_man::Inputs { - resolution, + }; + shader_index = constants.shader_to_show as usize; + } else { + // Render all shaders in a grid layout + // ignore shader_to_show + let (rows, cols) = optimal_grid(shader_count, vec2(resolution.x, resolution.y)); + + let cell_width = resolution.x / cols as f32; + let cell_height = resolution.y / rows as f32; + + #[expect(clippy::cast_sign_loss)] + let col = (frag_coord.x / cell_width).floor() as usize; + #[expect(clippy::cast_sign_loss)] + let row = (frag_coord.y / cell_height).floor() as usize; + shader_index = row + col * rows; + + let cell_resolution = vec3(cell_width, cell_height, 0.0); + let cell_frag_coord = vec2( + (col as f32).mul_add(-cell_width, frag_coord.x), + (row as f32).mul_add(-cell_height, frag_coord.y), + ); + let cell_mouse = mouse / vec4(cols as f32, rows as f32, cols as f32, rows as f32); + + shader_input = ShaderInput { + resolution: cell_resolution, time, - mouse, - }) - .main_image(&mut color, frag_coord), - _ => {} + frag_coord: cell_frag_coord, + mouse: cell_mouse, + }; + } + + if shader_index < shader_count { + shaders::render_shader(shader_index as u32, &shader_input, shader_output); + } else { + // If the shader index is out of bounds, just return a default color + shader_output.color = Vec4::new(0.0, 0.0, 0.0, 1.0); } + + let color = shader_output.color; Vec3::powf(color.truncate(), 2.2).extend(color.w) } diff --git a/shared/src/lib.rs b/shaders/src/shader_prelude.rs similarity index 54% rename from shared/src/lib.rs rename to shaders/src/shader_prelude.rs index f36ffe2..4cffe19 100644 --- a/shared/src/lib.rs +++ b/shaders/src/shader_prelude.rs @@ -1,43 +1,88 @@ -//! Ported to Rust from https://github.com/Tw1ddle/Sky-Shader/blob/master/src/shaders/glsl/sky.fragment - -#![cfg_attr(target_arch = "spirv", no_std)] -#![feature(asm_experimental_arch)] - -use bytemuck::{Pod, Zeroable}; -use core::f32::consts::PI; +pub use core::f32::consts::{FRAC_1_PI, FRAC_PI_2, PI, TAU}; use core::ops::{Add, Mul, Sub}; -use spirv_std::glam::{vec2, vec3, vec4, Vec2, Vec3, Vec4}; +/// We can't use the `f32::consts::SQRT_3` constant here because it is an unstable library feature +pub const SQRT_3: f32 = 1.732_050_807_568_877_2; + +pub use crate::shared_data::ShaderConstants; +pub use spirv_std::{ + arch::Derivative, + glam::{ + mat2, mat3, vec2, vec3, vec4, Mat2, Mat3, Vec2, Vec2Swizzles, Vec3, Vec3Swizzles, Vec4, + Vec4Swizzles, + }, + spirv, +}; // Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but // we tie #[no_std] above to the same condition, so it's fine. #[cfg(target_arch = "spirv")] -use spirv_std::num_traits::Float; - -#[repr(C)] -#[derive(Copy, Clone, Pod, Zeroable)] -#[allow(unused_attributes)] -pub struct ShaderConstants { - pub width: u32, - pub height: u32, +pub use spirv_std::num_traits::Float; + +pub trait SampleCube: Copy { + fn sample_cube(self, p: Vec3) -> Vec4; +} + +#[derive(Copy, Clone)] +pub struct ConstantColor { + pub color: Vec4, +} + +impl SampleCube for ConstantColor { + fn sample_cube(self, _: Vec3) -> Vec4 { + self.color + } +} + +#[derive(Copy, Clone)] +pub struct RgbCube { + pub alpha: f32, + pub intensity: f32, +} + +impl SampleCube for RgbCube { + fn sample_cube(self, p: Vec3) -> Vec4 { + (p.abs() * self.intensity).extend(self.alpha) + } +} + +pub struct ShaderInput { + pub resolution: Vec3, pub time: f32, - pub cursor_x: f32, - pub cursor_y: f32, - pub drag_start_x: f32, - pub drag_start_y: f32, - pub drag_end_x: f32, - pub drag_end_y: f32, - pub mouse_left_pressed: u32, - pub mouse_left_clicked: u32, + pub frag_coord: Vec2, + /// https://www.shadertoy.com/view/Mss3zH + pub mouse: Vec4, +} + +pub struct ShaderResult { + pub color: Vec4, +} + +pub struct ShaderDefinition { + pub name: &'static str, } -pub fn saturate(x: f32) -> f32 { - x.max(0.0).min(1.0) +#[inline(always)] +#[must_use] +pub fn saturate_vec3(a: Vec3) -> Vec3 { + a.clamp(Vec3::ZERO, Vec3::ONE) +} +#[inline(always)] +#[must_use] +pub fn saturate_vec2(a: Vec2) -> Vec2 { + a.clamp(Vec2::ZERO, Vec2::ONE) +} +#[inline(always)] +#[must_use] +pub fn saturate(a: f32) -> f32 { + a.clamp(0.0, 1.0) } /// Based on: https://seblagarde.wordpress.com/2014/12/01/inverse-trigonometric-functions-gpu-optimization-for-amd-gcn-architecture/ +#[inline] +#[must_use] pub fn acos_approx(v: f32) -> f32 { let x = v.abs(); - let mut res = -0.155972 * x + 1.56467; // p(x) + let mut res = (-0.155_972_f32).mul_add(x, 1.56467); // p(x) res *= (1.0f32 - x).sqrt(); if v >= 0.0 { @@ -47,13 +92,17 @@ pub fn acos_approx(v: f32) -> f32 { } } +#[inline(always)] +#[must_use] pub fn smoothstep(edge0: f32, edge1: f32, x: f32) -> f32 { // Scale, bias and saturate x to 0..1 range let x = saturate((x - edge0) / (edge1 - edge0)); // Evaluate polynomial - x * x * (3.0 - 2.0 * x) + x * x * 2.0f32.mul_add(-x, 3.0) } +#[inline(always)] +#[must_use] pub fn mix + Add + Sub, A: Copy>( x: X, y: X, @@ -63,28 +112,36 @@ pub fn mix + Add + Sub, A: } pub trait Clamp { + #[must_use] fn clamp(self, min: Self, max: Self) -> Self; } impl Clamp for f32 { + #[inline(always)] fn clamp(self, min: Self, max: Self) -> Self { self.max(min).min(max) } } pub trait FloatExt { + #[must_use] fn fract_gl(self) -> Self; + #[must_use] fn rem_euclid(self, rhs: Self) -> Self; + #[must_use] fn sign_gl(self) -> Self; + #[must_use] fn step(self, x: Self) -> Self; } impl FloatExt for f32 { - fn fract_gl(self) -> f32 { + #[inline] + fn fract_gl(self) -> Self { self - self.floor() } - fn rem_euclid(self, rhs: f32) -> f32 { + #[inline] + fn rem_euclid(self, rhs: Self) -> Self { let r = self % rhs; if r < 0.0 { r + rhs.abs() @@ -93,7 +150,8 @@ impl FloatExt for f32 { } } - fn sign_gl(self) -> f32 { + #[inline] + fn sign_gl(self) -> Self { if self < 0.0 { -1.0 } else if self == 0.0 { @@ -103,7 +161,8 @@ impl FloatExt for f32 { } } - fn step(self, x: f32) -> f32 { + #[inline] + fn step(self, x: Self) -> Self { if x < self { 0.0 } else { @@ -113,67 +172,87 @@ impl FloatExt for f32 { } pub trait VecExt { + #[must_use] fn sin(self) -> Self; + #[must_use] fn cos(self) -> Self; + #[must_use] fn powf_vec(self, p: Self) -> Self; + #[must_use] fn sqrt(self) -> Self; + #[must_use] fn ln(self) -> Self; + #[must_use] fn step(self, other: Self) -> Self; + #[must_use] fn sign_gl(self) -> Self; } impl VecExt for Vec2 { - fn sin(self) -> Vec2 { + #[inline] + fn sin(self) -> Self { vec2(self.x.sin(), self.y.sin()) } - fn cos(self) -> Vec2 { + #[inline] + fn cos(self) -> Self { vec2(self.x.cos(), self.y.cos()) } - fn powf_vec(self, p: Vec2) -> Vec2 { + #[inline] + fn powf_vec(self, p: Self) -> Self { vec2(self.x.powf(p.x), self.y.powf(p.y)) } - fn sqrt(self) -> Vec2 { + #[inline] + fn sqrt(self) -> Self { vec2(self.x.sqrt(), self.y.sqrt()) } - fn ln(self) -> Vec2 { + #[inline] + fn ln(self) -> Self { vec2(self.x.ln(), self.y.ln()) } - fn step(self, other: Vec2) -> Vec2 { + #[inline] + fn step(self, other: Self) -> Self { vec2(self.x.step(other.x), self.y.step(other.y)) } - fn sign_gl(self) -> Vec2 { + #[inline] + fn sign_gl(self) -> Self { vec2(self.x.sign_gl(), self.y.sign_gl()) } } impl VecExt for Vec3 { - fn sin(self) -> Vec3 { + #[inline] + fn sin(self) -> Self { vec3(self.x.sin(), self.y.sin(), self.z.sin()) } - fn cos(self) -> Vec3 { + #[inline] + fn cos(self) -> Self { vec3(self.x.cos(), self.y.cos(), self.z.cos()) } - fn powf_vec(self, p: Vec3) -> Vec3 { + #[inline] + fn powf_vec(self, p: Self) -> Self { vec3(self.x.powf(p.x), self.y.powf(p.y), self.z.powf(p.z)) } - fn sqrt(self) -> Vec3 { + #[inline] + fn sqrt(self) -> Self { vec3(self.x.sqrt(), self.y.sqrt(), self.z.sqrt()) } - fn ln(self) -> Vec3 { + #[inline] + fn ln(self) -> Self { vec3(self.x.ln(), self.y.ln(), self.z.ln()) } - fn step(self, other: Vec3) -> Vec3 { + #[inline] + fn step(self, other: Self) -> Self { vec3( self.x.step(other.x), self.y.step(other.y), @@ -181,21 +260,25 @@ impl VecExt for Vec3 { ) } - fn sign_gl(self) -> Vec3 { + #[inline] + fn sign_gl(self) -> Self { vec3(self.x.sign_gl(), self.y.sign_gl(), self.z.sign_gl()) } } impl VecExt for Vec4 { - fn sin(self) -> Vec4 { + #[inline] + fn sin(self) -> Self { vec4(self.x.sin(), self.y.sin(), self.z.sin(), self.w.sin()) } - fn cos(self) -> Vec4 { + #[inline] + fn cos(self) -> Self { vec4(self.x.cos(), self.y.cos(), self.z.cos(), self.w.cos()) } - fn powf_vec(self, p: Vec4) -> Vec4 { + #[inline] + fn powf_vec(self, p: Self) -> Self { vec4( self.x.powf(p.x), self.y.powf(p.y), @@ -204,15 +287,18 @@ impl VecExt for Vec4 { ) } - fn sqrt(self) -> Vec4 { + #[inline] + fn sqrt(self) -> Self { vec4(self.x.sqrt(), self.y.sqrt(), self.z.sqrt(), self.w.sqrt()) } - fn ln(self) -> Vec4 { + #[inline] + fn ln(self) -> Self { vec4(self.x.ln(), self.y.ln(), self.z.ln(), self.w.ln()) } - fn step(self, other: Vec4) -> Vec4 { + #[inline] + fn step(self, other: Self) -> Self { vec4( self.x.step(other.x), self.y.step(other.y), @@ -221,7 +307,8 @@ impl VecExt for Vec4 { ) } - fn sign_gl(self) -> Vec4 { + #[inline] + fn sign_gl(self) -> Self { vec4( self.x.sign_gl(), self.y.sign_gl(), @@ -231,6 +318,7 @@ impl VecExt for Vec4 { } } +#[inline(always)] pub fn discard() { unsafe { spirv_std::arch::demote_to_helper_invocation() } } diff --git a/shaders/src/shaders/a_lot_of_spheres.rs b/shaders/src/shaders/a_lot_of_spheres.rs index 9094fd5..6fca4e3 100644 --- a/shaders/src/shaders/a_lot_of_spheres.rs +++ b/shaders/src/shaders/a_lot_of_spheres.rs @@ -11,17 +11,26 @@ //! */ //! ``` -use shared::*; -use spirv_std::glam::{mat2, vec2, vec3, Mat2, Vec2, Vec3, Vec3Swizzles, Vec4}; - -// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but -// we tie #[no_std] above to the same condition, so it's fine. -#[cfg(target_arch = "spirv")] -use spirv_std::num_traits::Float; +use crate::shader_prelude::*; + +pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { + name: "A Lot of Spheres", +}; + +pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { + let color = &mut render_result.color; + let &ShaderInput { + resolution, + time, + frag_coord, + .. + } = render_instruction; + Inputs { resolution, time }.main_image(color, frag_coord); +} -pub struct Inputs { - pub resolution: Vec3, - pub time: f32, +struct Inputs { + resolution: Vec3, + time: f32, } const SHADOW: bool = true; @@ -246,7 +255,7 @@ impl Inputs { color } - pub fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { + fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { let q: Vec2 = frag_coord / self.resolution.xy(); let mut p: Vec2 = Vec2::splat(-1.0) + 2.0 * q; p.x *= self.resolution.x / self.resolution.y; diff --git a/shaders/src/shaders/a_question_of_time.rs b/shaders/src/shaders/a_question_of_time.rs index c54484e..12d1850 100644 --- a/shaders/src/shaders/a_question_of_time.rs +++ b/shaders/src/shaders/a_question_of_time.rs @@ -26,20 +26,33 @@ //! */ //! ``` -use shared::*; -use spirv_std::glam::{ - vec2, vec3, Mat2, Vec2, Vec2Swizzles, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles, +use crate::shader_prelude::*; + +pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { + name: "A Question of Time", }; -// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but -// we tie #[no_std] above to the same condition, so it's fine. -#[cfg(target_arch = "spirv")] -use spirv_std::num_traits::Float; +pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { + let color = &mut render_result.color; + let &ShaderInput { + resolution, + time, + frag_coord, + mouse, + .. + } = render_instruction; + Inputs { + resolution, + time, + mouse, + } + .main_image(color, frag_coord); +} -pub struct Inputs { - pub resolution: Vec3, - pub time: f32, - pub mouse: Vec4, +struct Inputs { + resolution: Vec3, + time: f32, + mouse: Vec4, } // a few utility functions @@ -153,7 +166,7 @@ impl Inputs { // drag your mouse to apply circle inversion if ms.y != -2.0 && ms.w > -2.0 { - uv = inversion(uv, 60.0.to_radians().cos()); + uv = inversion(uv, 60.0_f32.to_radians().cos()); ci = ms.xy(); } @@ -308,7 +321,7 @@ impl Inputs { c } - pub fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { + fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { let uv: Vec2 = (frag_coord - self.resolution.xy() * 0.5) / self.resolution.y; let ms: Vec4 = (self.mouse - self.resolution.xyxy() * 0.5) / self.resolution.y; *frag_color = self.scene(uv * 4., ms * 4.).extend(1.0); diff --git a/shaders/src/shaders/apollonian.rs b/shaders/src/shaders/apollonian.rs index fa0f093..5d96629 100644 --- a/shaders/src/shaders/apollonian.rs +++ b/shaders/src/shaders/apollonian.rs @@ -10,28 +10,44 @@ //! // Coloring and fake occlusions are done by orbit trapping, as usual. //! ``` -use shared::*; -use spirv_std::glam::{vec2, vec3, Vec2, Vec2Swizzles, Vec3, Vec3Swizzles, Vec4}; - -// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but -// we tie #[no_std] above to the same condition, so it's fine. -#[cfg(target_arch = "spirv")] -use spirv_std::num_traits::Float; - -pub struct Inputs { - pub resolution: Vec3, - pub time: f32, - pub mouse: Vec4, +use crate::shader_prelude::*; + +pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { + name: "Apollonian Fractal", +}; + +pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { + let color = &mut render_result.color; + let &ShaderInput { + resolution, + time, + frag_coord, + mouse, + .. + } = render_instruction; + State::new(Inputs { + resolution, + time, + mouse, + }) + .main_image(color, frag_coord); +} + +struct Inputs { + resolution: Vec3, + time: f32, + mouse: Vec4, } -pub struct State { +struct State { inputs: Inputs, orb: Vec4, } impl State { - pub fn new(inputs: Inputs) -> Self { - State { + #[must_use] + fn new(inputs: Inputs) -> Self { + Self { inputs, orb: Vec4::ZERO, } @@ -132,7 +148,7 @@ impl State { col.sqrt() } - pub fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { + fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { let time: f32 = self.inputs.time * 0.25 + 0.01 * self.inputs.mouse.x; let anim: f32 = 1.1 + 0.5 * smoothstep(-0.3, 0.3, (0.1 * self.inputs.time).cos()); let mut tot: Vec3 = Vec3::ZERO; @@ -169,7 +185,7 @@ impl State { *frag_color = tot.extend(1.0); } - pub fn main_vr( + fn _main_vr( &mut self, frag_color: &mut Vec4, _frag_coord: Vec2, diff --git a/shaders/src/shaders/atmosphere_system_test.rs b/shaders/src/shaders/atmosphere_system_test.rs index 0bd6b11..5ccd93b 100644 --- a/shaders/src/shaders/atmosphere_system_test.rs +++ b/shaders/src/shaders/atmosphere_system_test.rs @@ -10,27 +10,44 @@ //! // ---------------------------------------------------------------------------- //! ``` -use spirv_std::glam::{vec2, vec3, Mat3, Vec2, Vec3, Vec3Swizzles, Vec4}; +use crate::shader_prelude::*; -// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but -// we tie #[no_std] above to the same condition, so it's fine. -#[cfg(target_arch = "spirv")] -use spirv_std::num_traits::Float; +pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { + name: "Atmosphere System Test", +}; + +pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { + let color = &mut render_result.color; + let &ShaderInput { + resolution, + time, + frag_coord, + mouse, + .. + } = render_instruction; + State::new(Inputs { + resolution, + time, + mouse, + }) + .main_image(color, frag_coord); +} -pub struct Inputs { - pub resolution: Vec3, - pub time: f32, - pub mouse: Vec4, +struct Inputs { + resolution: Vec3, + time: f32, + mouse: Vec4, } -pub struct State { +struct State { inputs: Inputs, sun_dir: Vec3, } impl State { - pub fn new(inputs: Inputs) -> Self { - State { + #[must_use] + fn new(inputs: Inputs) -> Self { + Self { inputs, sun_dir: vec3(0.0, 1.0, 0.0), } @@ -238,9 +255,9 @@ impl State { SUN_POWER * (sum_r * phase_r * BETA_R + sum_m * phase_m * BETA_M) } - pub fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { + fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { let aspect_ratio: Vec2 = vec2(self.inputs.resolution.x / self.inputs.resolution.y, 1.0); - let fov: f32 = 45.0.to_radians().tan(); + let fov: f32 = 45.0_f32.to_radians().tan(); let point_ndc: Vec2 = frag_coord / self.inputs.resolution.xy(); let point_cam: Vec3 = ((2.0 * point_ndc - Vec2::ONE) * aspect_ratio * fov).extend(-1.0); diff --git a/shaders/src/shaders/bubble_buckey_balls.rs b/shaders/src/shaders/bubble_buckey_balls.rs index c3dd5ae..3e2296a 100644 --- a/shaders/src/shaders/bubble_buckey_balls.rs +++ b/shaders/src/shaders/bubble_buckey_balls.rs @@ -8,24 +8,43 @@ //! // Tested on Nvidia GTX 780 Windows 7 //! ``` -use crate::SampleCube; -use shared::*; -use spirv_std::glam::{vec2, vec3, Vec2, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles}; - -// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but -// we tie #[no_std] above to the same condition, so it's fine. -#[cfg(target_arch = "spirv")] -use spirv_std::num_traits::Float; - -pub struct Inputs { - pub resolution: Vec3, - pub time: f32, - pub mouse: Vec4, - pub channel0: C0, - pub channel1: C1, +use crate::shader_prelude::*; + +pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { + name: "Bubble Buckey Balls", +}; + +pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { + let color = &mut render_result.color; + let &ShaderInput { + resolution, + time, + frag_coord, + mouse, + .. + } = render_instruction; + State::new(Inputs { + resolution, + time, + mouse, + channel0: RgbCube { + alpha: 1.0, + intensity: 0.5, + }, + channel1: ConstantColor { color: Vec4::ONE }, + }) + .main_image(color, frag_coord); } -pub struct State { +struct Inputs { + resolution: Vec3, + time: f32, + mouse: Vec4, + channel0: C0, + channel1: C1, +} + +struct State { inputs: Inputs, cam_point_at: Vec3, @@ -35,8 +54,9 @@ pub struct State { } impl State { - pub fn new(inputs: Inputs) -> Self { - State { + #[must_use] + fn new(inputs: Inputs) -> Self { + Self { inputs, cam_point_at: Vec3::ZERO, cam_origin: Vec3::ZERO, @@ -383,8 +403,9 @@ struct SurfaceData { } impl SurfaceData { + #[must_use] fn init_surf(p: Vec3, n: Vec3) -> Self { - SurfaceData { + Self { point: p, normal: n, basecolor: Vec3::ZERO, @@ -563,7 +584,7 @@ impl State { // ************************************************************************** // MAIN - pub fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { + fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { // ---------------------------------------------------------------------- // Animate globals diff --git a/shaders/src/shaders/clouds.rs b/shaders/src/shaders/clouds.rs index 6179f7f..116ef69 100644 --- a/shaders/src/shaders/clouds.rs +++ b/shaders/src/shaders/clouds.rs @@ -1,11 +1,23 @@ //! Ported to Rust from -use shared::*; -use spirv_std::glam::{mat2, vec2, vec3, Mat2, Vec2, Vec3, Vec3Swizzles, Vec4}; +use crate::shader_prelude::*; + +pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { name: "Clouds" }; + +pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { + let color = &mut render_result.color; + let &ShaderInput { + resolution, + time, + frag_coord, + .. + } = render_instruction; + Inputs { resolution, time }.main_image(color, frag_coord); +} -pub struct Inputs { - pub resolution: Vec3, - pub time: f32, +struct Inputs { + resolution: Vec3, + time: f32, } const CLOUD_SCALE: f32 = 1.1; @@ -62,7 +74,7 @@ fn fbm(mut n: Vec2) -> f32 { // ----------------------------------------------- impl Inputs { - pub fn main_image(&self, frag_color: &mut Vec4, frag_coord: Vec2) { + fn main_image(&self, frag_color: &mut Vec4, frag_coord: Vec2) { let p: Vec2 = frag_coord / self.resolution.xy(); let mut uv: Vec2 = p * vec2(self.resolution.x / self.resolution.y, 1.0); let mut time: f32 = self.time * SPEED; diff --git a/shaders/src/shaders/filtering_procedurals.rs b/shaders/src/shaders/filtering_procedurals.rs index 4d4f806..2c9f51a 100644 --- a/shaders/src/shaders/filtering_procedurals.rs +++ b/shaders/src/shaders/filtering_procedurals.rs @@ -19,19 +19,33 @@ //! */ //! ``` -use shared::*; -use spirv_std::arch::Derivative; -use spirv_std::glam::{vec2, vec3, vec4, Vec2, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles}; - -// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but -// we tie #[no_std] above to the same condition, so it's fine. -#[cfg(target_arch = "spirv")] -use spirv_std::num_traits::Float; - -pub struct Inputs { - pub resolution: Vec3, - pub time: f32, - pub mouse: Vec4, +use crate::shader_prelude::*; + +pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { + name: "Filtering Procedurals", +}; + +pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { + let color = &mut render_result.color; + let &ShaderInput { + resolution, + time, + frag_coord, + mouse, + .. + } = render_instruction; + Inputs { + resolution, + time, + mouse, + } + .main_image(color, frag_coord); +} + +struct Inputs { + resolution: Vec3, + time: f32, + mouse: Vec4, } //=============================================================================================== @@ -337,7 +351,7 @@ fn sample_texture(uvw: Vec3, nor: Vec3, mid: f32) -> Vec3 { } impl Inputs { - pub fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { + fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { let p: Vec2 = (-self.resolution.xy() + 2.0 * frag_coord) / self.resolution.y; let mut th: f32 = (-self.resolution.x + 2.0 * self.mouse.x) / self.resolution.y; diff --git a/shaders/src/shaders/flappy_bird.rs b/shaders/src/shaders/flappy_bird.rs index bc6be58..27848d4 100644 --- a/shaders/src/shaders/flappy_bird.rs +++ b/shaders/src/shaders/flappy_bird.rs @@ -7,28 +7,39 @@ //! // Based on the "Super Mario Bros" shader by HLorenzi //! // https://www.shadertoy.com/view/Msj3zD //! ``` +#![allow(clippy::float_cmp)] +use crate::shader_prelude::*; + +pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { + name: "Flappy Bird", +}; + +pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { + let color = &mut render_result.color; + let &ShaderInput { + resolution, + time, + frag_coord, + .. + } = render_instruction; + State::new(Inputs { resolution, time }).main_image(color, frag_coord); +} -use spirv_std::glam::{vec2, vec4, Vec2, Vec3, Vec4}; - -// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but -// we tie #[no_std] above to the same condition, so it's fine. -#[cfg(target_arch = "spirv")] -use {shared::*, spirv_std::num_traits::Float}; - -pub struct Inputs { - pub resolution: Vec3, - pub time: f32, +struct Inputs { + resolution: Vec3, + time: f32, } -pub struct State { +struct State { inputs: Inputs, frag_color: Vec4, } impl State { - pub fn new(inputs: Inputs) -> State { - State { + #[must_use] + fn new(inputs: Inputs) -> Self { + Self { inputs, frag_color: Vec4::ZERO, diff --git a/shaders/src/shaders/galaxy_of_universes.rs b/shaders/src/shaders/galaxy_of_universes.rs index 5a2e100..85c681c 100644 --- a/shaders/src/shaders/galaxy_of_universes.rs +++ b/shaders/src/shaders/galaxy_of_universes.rs @@ -9,21 +9,30 @@ //! // To fake a perspective it takes advantage of the screen being wider than it is tall. //! ``` -use shared::*; -use spirv_std::glam::{vec3, Mat2, Vec2, Vec3, Vec3Swizzles, Vec4}; +use crate::shader_prelude::*; -// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but -// we tie #[no_std] above to the same condition, so it's fine. -#[cfg(target_arch = "spirv")] -use spirv_std::num_traits::Float; +pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { + name: "Galaxy of Universes", +}; -pub struct Inputs { - pub resolution: Vec3, - pub time: f32, +pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { + let color = &mut render_result.color; + let &ShaderInput { + resolution, + time, + frag_coord, + .. + } = render_instruction; + Inputs { resolution, time }.main_image(color, frag_coord); +} + +struct Inputs { + resolution: Vec3, + time: f32, } impl Inputs { - pub fn main_image(&self, frag_color: &mut Vec4, frag_coord: Vec2) { + fn main_image(&self, frag_color: &mut Vec4, frag_coord: Vec2) { let uv: Vec2 = (frag_coord / self.resolution.xy()) - Vec2::splat(0.5); let t: f32 = self.time * 0.1 + ((0.25 + 0.05 * (self.time * 0.1).sin()) / (uv.length() + 0.07)) * 2.2; diff --git a/shaders/src/shaders/geodesic_tiling.rs b/shaders/src/shaders/geodesic_tiling.rs index 36d96b8..4ad2a3a 100644 --- a/shaders/src/shaders/geodesic_tiling.rs +++ b/shaders/src/shaders/geodesic_tiling.rs @@ -1,20 +1,35 @@ //! Ported to Rust from -use shared::*; -use spirv_std::glam::{mat2, vec2, vec3, Mat2, Mat3, Vec2, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles}; - -// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but -// we tie #[no_std] above to the same condition, so it's fine. -#[cfg(target_arch = "spirv")] -use spirv_std::num_traits::Float; - -pub struct Inputs { - pub resolution: Vec3, - pub time: f32, - pub mouse: Vec4, +use crate::shader_prelude::*; + +pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { + name: "Geodesic Tiling", +}; + +pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { + let color = &mut render_result.color; + let &ShaderInput { + resolution, + time, + frag_coord, + mouse, + .. + } = render_instruction; + State::new(Inputs { + resolution, + time, + mouse, + }) + .main_image(color, frag_coord); +} + +struct Inputs { + resolution: Vec3, + time: f32, + mouse: Vec4, } -pub struct State { +struct State { inputs: Inputs, face_plane: Vec3, @@ -30,8 +45,9 @@ pub struct State { } impl State { - pub fn new(inputs: Inputs) -> State { - State { + #[must_use] + fn new(inputs: Inputs) -> Self { + Self { inputs, face_plane: Vec3::ZERO, u_plane: Vec3::ZERO, @@ -747,7 +763,7 @@ fn linear_to_screen(linear_rgb: Vec3) -> Vec3 { } impl State { - pub fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { + fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { self.time = self.inputs.time; if LOOP != 0 { diff --git a/shaders/src/shaders/heart.rs b/shaders/src/shaders/heart.rs index 0706dca..7231a0c 100644 --- a/shaders/src/shaders/heart.rs +++ b/shaders/src/shaders/heart.rs @@ -6,21 +6,28 @@ //! // License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. //! ``` -use shared::*; -use spirv_std::glam::{vec2, vec3, Vec2, Vec3, Vec3Swizzles, Vec4}; +use crate::shader_prelude::*; -// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but -// we tie #[no_std] above to the same condition, so it's fine. -#[cfg(target_arch = "spirv")] -use spirv_std::num_traits::Float; +pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { name: "Hearts" }; -pub struct Inputs { - pub resolution: Vec3, - pub time: f32, +pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { + let color = &mut render_result.color; + let &ShaderInput { + resolution, + time, + frag_coord, + .. + } = render_instruction; + Inputs { resolution, time }.main_image(color, frag_coord); +} + +struct Inputs { + resolution: Vec3, + time: f32, } impl Inputs { - pub fn main_image(&self, frag_color: &mut Vec4, frag_coord: Vec2) { + fn main_image(&self, frag_color: &mut Vec4, frag_coord: Vec2) { let mut p: Vec2 = (2.0 * frag_coord - self.resolution.xy()) / (self.resolution.y.min(self.resolution.x)); diff --git a/shaders/src/shaders/luminescence.rs b/shaders/src/shaders/luminescence.rs index c0dd9b3..777ed86 100644 --- a/shaders/src/shaders/luminescence.rs +++ b/shaders/src/shaders/luminescence.rs @@ -17,22 +17,37 @@ //! // Twitter: @The_ArtOfCode //! ``` -use shared::*; -use spirv_std::glam::{vec2, vec3, Mat3, Vec2, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles}; - -// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but -// we tie #[no_std] above to the same condition, so it's fine. -#[cfg(target_arch = "spirv")] -use spirv_std::num_traits::Float; +use crate::shader_prelude::*; + +pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { + name: "Luminescence", +}; + +pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { + let color = &mut render_result.color; + let &ShaderInput { + resolution, + time, + frag_coord, + mouse, + .. + } = render_instruction; + State::new(Inputs { + resolution, + time, + mouse, + }) + .main_image(color, frag_coord); +} #[derive(Clone, Copy)] -pub struct Inputs { - pub resolution: Vec3, - pub time: f32, - pub mouse: Vec4, +struct Inputs { + resolution: Vec3, + time: f32, + mouse: Vec4, } -pub struct State { +struct State { inputs: Inputs, bg: Vec3, // global background color @@ -42,8 +57,9 @@ pub struct State { } impl State { - pub fn new(inputs: Inputs) -> State { - State { + #[must_use] + fn new(inputs: Inputs) -> Self { + Self { inputs, bg: Vec3::ZERO, @@ -562,7 +578,7 @@ impl State { col } - pub fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { + fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { let t: f32 = self.inputs.time * 0.04; let mut uv: Vec2 = frag_coord / self.inputs.resolution.xy(); diff --git a/shaders/src/shaders/mandelbrot_smooth.rs b/shaders/src/shaders/mandelbrot_smooth.rs index 67abf99..c32346e 100644 --- a/shaders/src/shaders/mandelbrot_smooth.rs +++ b/shaders/src/shaders/mandelbrot_smooth.rs @@ -10,17 +10,26 @@ //! // http://iquilezles.org/www/articles/mset_smooth/mset_smooth.htm //! ``` -use shared::*; -use spirv_std::glam::{vec2, vec3, Vec2, Vec3, Vec3Swizzles, Vec4}; +use crate::shader_prelude::*; -// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but -// we tie #[no_std] above to the same condition, so it's fine. -#[cfg(target_arch = "spirv")] -use spirv_std::num_traits::Float; +pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { + name: "Mandelbrot Smooth", +}; -pub struct Inputs { - pub resolution: Vec3, - pub time: f32, +pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { + let color = &mut render_result.color; + let &ShaderInput { + resolution, + time, + frag_coord, + .. + } = render_instruction; + Inputs { resolution, time }.main_image(color, frag_coord); +} + +struct Inputs { + resolution: Vec3, + time: f32, } // increase this if you have a very fast GPU @@ -64,7 +73,7 @@ impl Inputs { mix(l, sl, al) } - pub fn main_image(&self, frag_color: &mut Vec4, frag_coord: Vec2) { + fn main_image(&self, frag_color: &mut Vec4, frag_coord: Vec2) { let mut col: Vec3 = Vec3::ZERO; for m in 0..AA { diff --git a/shaders/src/shaders/miracle_snowflakes.rs b/shaders/src/shaders/miracle_snowflakes.rs index e3f7879..5919a29 100644 --- a/shaders/src/shaders/miracle_snowflakes.rs +++ b/shaders/src/shaders/miracle_snowflakes.rs @@ -10,20 +10,33 @@ //! */ //! ``` -use shared::*; -use spirv_std::glam::{ - vec2, vec3, vec4, Mat3, Vec2, Vec2Swizzles, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles, +use crate::shader_prelude::*; + +pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { + name: "Playing Marble", }; -// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but -// we tie #[no_std] above to the same condition, so it's fine. -#[cfg(target_arch = "spirv")] -use spirv_std::num_traits::Float; +pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { + let color = &mut render_result.color; + let &ShaderInput { + resolution, + time, + frag_coord, + mouse, + .. + } = render_instruction; + State::new(Inputs { + resolution, + time, + mouse, + }) + .main_image(color, frag_coord); +} -pub struct Inputs { - pub resolution: Vec3, - pub time: f32, - pub mouse: Vec4, +struct Inputs { + resolution: Vec3, + time: f32, + mouse: Vec4, } const ITERATIONS: u32 = 15; @@ -33,7 +46,7 @@ const LAYERSBLOB: i32 = 20; const STEP: f32 = 1.0; const FAR: f32 = 10000.0; -pub struct State { +struct State { inputs: Inputs, radius: f32, zoom: f32, @@ -51,8 +64,9 @@ pub struct State { } impl State { - pub fn new(inputs: Inputs) -> Self { - State { + #[must_use] + fn new(inputs: Inputs) -> Self { + Self { inputs, radius: 0.25, // radius of Snowflakes. maximum for this demo 0.25. zoom: 4.0, // use this to change details. optimal 0.1 - 4.0. @@ -241,7 +255,7 @@ impl State { color } - pub fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { + fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { let time: f32 = self.inputs.time * 0.2; //*0.1; self.res = 1.0 / self.inputs.resolution.y; let p: Vec2 = (-self.inputs.resolution.xy() + 2.0 * frag_coord) * self.res; diff --git a/shaders/src/shaders/mod.rs b/shaders/src/shaders/mod.rs index 8a48999..10917ce 100644 --- a/shaders/src/shaders/mod.rs +++ b/shaders/src/shaders/mod.rs @@ -1,28 +1,89 @@ -pub mod a_lot_of_spheres; -pub mod a_question_of_time; -pub mod apollonian; -pub mod atmosphere_system_test; -pub mod bubble_buckey_balls; -pub mod clouds; -pub mod filtering_procedurals; -pub mod flappy_bird; -pub mod galaxy_of_universes; -pub mod geodesic_tiling; -pub mod heart; -pub mod luminescence; -pub mod mandelbrot_smooth; -pub mod miracle_snowflakes; -pub mod morphing; -pub mod moving_square; -pub mod on_off_spikes; -pub mod phantom_star; -pub mod playing_marble; -pub mod protean_clouds; -pub mod raymarching_primitives; -pub mod seascape; -pub mod skyline; -pub mod soft_shadow_variation; -pub mod tileable_water_caustic; -pub mod tokyo; -pub mod two_tweets; -pub mod voxel_pac_man; +use crate::shader_prelude::*; + +mod a_lot_of_spheres; +mod a_question_of_time; +mod apollonian; +mod atmosphere_system_test; +mod bubble_buckey_balls; +mod clouds; +mod filtering_procedurals; +mod flappy_bird; +mod galaxy_of_universes; +mod geodesic_tiling; +mod heart; +mod luminescence; +mod mandelbrot_smooth; +mod miracle_snowflakes; +mod morphing; +mod moving_square; +mod on_off_spikes; +mod phantom_star; +mod playing_marble; +mod protean_clouds; +mod raymarching_primitives; +mod seascape; +mod skyline; +mod soft_shadow_variation; +mod tileable_water_caustic; +mod tokyo; +mod two_tweets; +mod voxel_pac_man; + +#[allow(edition_2024_expr_fragment_specifier)] +macro_rules! match_index { + ($e:expr; $($result:expr),* $(,)?) => ({ + let mut i = 0..; + match $e { e => { + $(if e == i.next().unwrap() { $result } else)* + { unreachable!() } + }} + }) +} + +macro_rules! render_shader_macro { + ($($shader_name:ident),* $(,)?) => { + #[inline(always)] + pub fn render_shader(shader_index: u32, shader_input: &ShaderInput, shader_output: &mut ShaderResult) { + match_index!(shader_index; $( + $shader_name::shader_fn(shader_input, shader_output), + )*) + } + + pub const SHADER_DEFINITIONS: &[ShaderDefinition] = &[ + $( + $shader_name::SHADER_DEFINITION, + )* + ]; + }; +} + +render_shader_macro!( + miracle_snowflakes, + morphing, + voxel_pac_man, + luminescence, + seascape, + two_tweets, + heart, + clouds, + mandelbrot_smooth, + protean_clouds, + tileable_water_caustic, + apollonian, + phantom_star, + playing_marble, + a_lot_of_spheres, + a_question_of_time, + galaxy_of_universes, + atmosphere_system_test, + soft_shadow_variation, + bubble_buckey_balls, + raymarching_primitives, + moving_square, + skyline, + filtering_procedurals, + geodesic_tiling, + flappy_bird, + tokyo, + on_off_spikes, +); diff --git a/shaders/src/shaders/morphing.rs b/shaders/src/shaders/morphing.rs index 192ba43..ef93579 100644 --- a/shaders/src/shaders/morphing.rs +++ b/shaders/src/shaders/morphing.rs @@ -6,23 +6,36 @@ //! // License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. //! ``` -use shared::*; -use spirv_std::glam::{ - vec2, vec3, Mat2, Vec2, Vec2Swizzles, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles, +use crate::shader_prelude::*; + +pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { + name: "Morphing Teapot", }; -// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but -// we tie #[no_std] above to the same condition, so it's fine. -#[cfg(target_arch = "spirv")] -use spirv_std::num_traits::Float; +pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { + let color = &mut render_result.color; + let &ShaderInput { + resolution, + time, + frag_coord, + mouse, + .. + } = render_instruction; + State::new(Inputs { + resolution, + time, + mouse, + }) + .main_image(color, frag_coord); +} -pub struct Inputs { - pub resolution: Vec3, - pub time: f32, - pub mouse: Vec4, +struct Inputs { + resolution: Vec3, + time: f32, + mouse: Vec4, } -pub struct State { +struct State { inputs: Inputs, a: [Vec2; 15], @@ -36,8 +49,9 @@ pub struct State { } impl State { - pub fn new(inputs: Inputs) -> Self { - State { + #[must_use] + fn new(inputs: Inputs) -> Self { + Self { inputs, a: [ @@ -191,8 +205,8 @@ impl State { (grad - (grad.dot(ray).max(0.0)) * ray).normalize() } - pub fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { - let aa: f32 = 3.14159 / 4.0; + fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { + let aa: f32 = PI / 4.0; self.mat2_rot = Mat2::from_cols_array(&[aa.cos(), aa.sin(), -aa.sin(), aa.cos()]); // Morphing step diff --git a/shaders/src/shaders/moving_square.rs b/shaders/src/shaders/moving_square.rs index b695be6..6fd47ba 100644 --- a/shaders/src/shaders/moving_square.rs +++ b/shaders/src/shaders/moving_square.rs @@ -1,15 +1,25 @@ //! Ported to Rust from -use spirv_std::glam::{vec3, Mat2, Vec2, Vec3, Vec3Swizzles, Vec4}; - -// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but -// we tie #[no_std] above to the same condition, so it's fine. -#[cfg(target_arch = "spirv")] -use spirv_std::num_traits::Float; +use crate::shader_prelude::*; + +pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { + name: "Moving Square", +}; + +pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { + let color = &mut render_result.color; + let &ShaderInput { + resolution, + time, + frag_coord, + .. + } = render_instruction; + Inputs { resolution, time }.main_image(color, frag_coord); +} -pub struct Inputs { - pub resolution: Vec3, - pub time: f32, +struct Inputs { + resolution: Vec3, + time: f32, } fn rect(uv: Vec2, pos: Vec2, r: f32) -> Vec4 { @@ -23,7 +33,7 @@ fn rect(uv: Vec2, pos: Vec2, r: f32) -> Vec4 { } impl Inputs { - pub fn main_image(&self, frag_color: &mut Vec4, frag_coord: Vec2) { + fn main_image(&self, frag_color: &mut Vec4, frag_coord: Vec2) { let mut uv: Vec2 = frag_coord; let t: f32 = self.time.sin(); diff --git a/shaders/src/shaders/on_off_spikes.rs b/shaders/src/shaders/on_off_spikes.rs index e269543..88164e0 100644 --- a/shaders/src/shaders/on_off_spikes.rs +++ b/shaders/src/shaders/on_off_spikes.rs @@ -5,23 +5,36 @@ //! // On/Off Spikes, fragment shader by movAX13h, oct 2014 //! ``` -use shared::*; -use spirv_std::glam::{ - vec2, vec3, Mat2, Mat3, Vec2, Vec2Swizzles, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles, +use crate::shader_prelude::*; + +pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { + name: "On/Off Spikes", }; -// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but -// we tie #[no_std] above to the same condition, so it's fine. -#[cfg(target_arch = "spirv")] -use spirv_std::num_traits::Float; +pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { + let color = &mut render_result.color; + let &ShaderInput { + resolution, + time, + frag_coord, + mouse, + .. + } = render_instruction; + State::new(Inputs { + resolution, + time, + mouse, + }) + .main_image(color, frag_coord); +} -pub struct Inputs { - pub resolution: Vec3, - pub time: f32, - pub mouse: Vec4, +struct Inputs { + resolution: Vec3, + time: f32, + mouse: Vec4, } -pub struct State { +struct State { inputs: Inputs, // globals @@ -34,8 +47,9 @@ pub struct State { } impl State { - pub fn new(inputs: Inputs) -> State { - State { + #[must_use] + pub fn new(inputs: Inputs) -> Self { + Self { inputs, glow: 0.0, @@ -309,7 +323,7 @@ impl State { hit.color + diffuse * Vec3::splat(0.9) + specular * Vec3::splat(1.0) } - pub fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { + fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { //self.time = self.inputs.time; self.glow = (2.0 * (self.inputs.time * 0.7 - 5.0).sin()) .min(1.0) diff --git a/shaders/src/shaders/phantom_star.rs b/shaders/src/shaders/phantom_star.rs index 6d76980..f883cfc 100644 --- a/shaders/src/shaders/phantom_star.rs +++ b/shaders/src/shaders/phantom_star.rs @@ -1,17 +1,25 @@ //! Ported to Rust from -use spirv_std::glam::{vec3, Mat2, Vec2, Vec3, Vec3Swizzles, Vec4}; - -use core::f32::consts::PI; - -// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but -// we tie #[no_std] above to the same condition, so it's fine. -#[cfg(target_arch = "spirv")] -use {shared::FloatExt, spirv_std::num_traits::Float}; +use crate::shader_prelude::*; + +pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { + name: "Phantom Star", +}; + +pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { + let color = &mut render_result.color; + let &ShaderInput { + resolution, + time, + frag_coord, + .. + } = render_instruction; + Inputs { resolution, time }.main_image(color, frag_coord); +} -pub struct Inputs { - pub resolution: Vec3, - pub time: f32, +struct Inputs { + resolution: Vec3, + time: f32, } fn rot(a: f32) -> Mat2 { @@ -58,7 +66,7 @@ impl Inputs { self.ifs_box(p1) } - pub fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { + fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { let p: Vec2 = (frag_coord * 2.0 - self.resolution.xy()) / self.resolution.x.min(self.resolution.y); diff --git a/shaders/src/shaders/playing_marble.rs b/shaders/src/shaders/playing_marble.rs index 3da5435..1f367e4 100644 --- a/shaders/src/shaders/playing_marble.rs +++ b/shaders/src/shaders/playing_marble.rs @@ -6,20 +6,38 @@ //! // Created by S. Guillitte 2015 //! ``` -use crate::SampleCube; -use shared::*; -use spirv_std::glam::{vec2, vec3, vec4, Mat2, Vec2, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles}; - -// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but -// we tie #[no_std] above to the same condition, so it's fine. -#[cfg(target_arch = "spirv")] -use spirv_std::num_traits::Float; - -pub struct Inputs { - pub resolution: Vec3, - pub time: f32, - pub mouse: Vec4, - pub channel0: C0, +use crate::shader_prelude::*; + +pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { + name: "Playing Marble", +}; + +pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { + let color = &mut render_result.color; + let &ShaderInput { + resolution, + time, + frag_coord, + mouse, + .. + } = render_instruction; + Inputs { + resolution, + time, + mouse, + channel0: RgbCube { + alpha: 1.0, + intensity: 1.0, + }, + } + .main_image(color, frag_coord); +} + +struct Inputs { + resolution: Vec3, + time: f32, + mouse: Vec4, + channel0: C0, } const ZOOM: f32 = 1.0; @@ -82,7 +100,7 @@ impl Inputs { } col } - pub fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { + fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { let time: f32 = self.time; let q: Vec2 = frag_coord / self.resolution.xy(); let mut p: Vec2 = Vec2::splat(-1.0) + 2.0 * q; diff --git a/shaders/src/shaders/protean_clouds.rs b/shaders/src/shaders/protean_clouds.rs index 5b4dfd9..ede75b4 100644 --- a/shaders/src/shaders/protean_clouds.rs +++ b/shaders/src/shaders/protean_clouds.rs @@ -26,31 +26,45 @@ //! */ //! ``` -use shared::*; -use spirv_std::glam::{ - mat3, vec2, vec3, vec4, Mat2, Mat3, Vec2, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles, +use crate::shader_prelude::*; + +pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { + name: "Protean Clouds", }; -// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but -// we tie #[no_std] above to the same condition, so it's fine. -#[cfg(target_arch = "spirv")] -use spirv_std::num_traits::Float; +pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { + let color = &mut render_result.color; + let &ShaderInput { + resolution, + time, + frag_coord, + mouse, + .. + } = render_instruction; + State::new(Inputs { + resolution, + time, + mouse, + }) + .main_image(color, frag_coord); +} -pub struct Inputs { - pub resolution: Vec3, - pub time: f32, - pub mouse: Vec4, +struct Inputs { + resolution: Vec3, + time: f32, + mouse: Vec4, } -pub struct State { +struct State { inputs: Inputs, prm1: f32, bs_mo: Vec2, } impl State { - pub fn new(inputs: Inputs) -> Self { - State { + #[must_use] + fn new(inputs: Inputs) -> Self { + Self { inputs, prm1: 0.0, bs_mo: Vec2::ZERO, @@ -183,7 +197,7 @@ fn i_lerp(a: Vec3, b: Vec3, x: f32) -> Vec3 { } impl State { - pub fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { + fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { let q: Vec2 = frag_coord / self.inputs.resolution.xy(); let p: Vec2 = (frag_coord - 0.5 * self.inputs.resolution.xy()) / self.inputs.resolution.y; self.bs_mo = diff --git a/shaders/src/shaders/raymarching_primitives.rs b/shaders/src/shaders/raymarching_primitives.rs index c8e1ac2..c377fc4 100644 --- a/shaders/src/shaders/raymarching_primitives.rs +++ b/shaders/src/shaders/raymarching_primitives.rs @@ -17,21 +17,35 @@ //! // https://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm //! ``` -use shared::*; -use spirv_std::glam::{ - vec2, vec3, Mat3, Vec2, Vec2Swizzles, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles, +use crate::shader_prelude::*; + +pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { + name: "Raymarching Primitives", }; -// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but -// we tie #[no_std] above to the same condition, so it's fine. -#[cfg(target_arch = "spirv")] -use spirv_std::num_traits::Float; +pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { + let color = &mut render_result.color; + let &ShaderInput { + resolution, + time, + frag_coord, + mouse, + .. + } = render_instruction; + Inputs { + resolution, + frame: (time * 60.0) as i32, + time, + mouse, + } + .main_image(color, frag_coord); +} -pub struct Inputs { - pub resolution: Vec3, - pub frame: i32, - pub time: f32, - pub mouse: Vec4, +struct Inputs { + resolution: Vec3, + frame: i32, + time: f32, + mouse: Vec4, } const HW_PERFORMANCE: usize = 1; diff --git a/shaders/src/shaders/seascape.rs b/shaders/src/shaders/seascape.rs index 400edba..bae7251 100644 --- a/shaders/src/shaders/seascape.rs +++ b/shaders/src/shaders/seascape.rs @@ -9,18 +9,31 @@ //! */ //! ``` -use shared::*; -use spirv_std::glam::{mat2, vec2, vec3, Mat2, Mat3, Vec2, Vec3, Vec3Swizzles, Vec4}; - -// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but -// we tie #[no_std] above to the same condition, so it's fine. -#[cfg(target_arch = "spirv")] -use spirv_std::num_traits::Float; - -pub struct Inputs { - pub resolution: Vec3, - pub time: f32, - pub mouse: Vec4, +use crate::shader_prelude::*; + +pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { name: "Seascape" }; + +pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { + let color = &mut render_result.color; + let &ShaderInput { + resolution, + time, + frag_coord, + mouse, + .. + } = render_instruction; + Inputs { + resolution, + time, + mouse, + } + .main_image(color, frag_coord); +} + +struct Inputs { + resolution: Vec3, + time: f32, + mouse: Vec4, } const NUM_STEPS: usize = 8; @@ -230,7 +243,7 @@ impl Inputs { } // main - pub fn main_image(&self, frag_color: &mut Vec4, frag_coord: Vec2) { + fn main_image(&self, frag_color: &mut Vec4, frag_coord: Vec2) { let time: f32 = self.time * 0.3 + self.mouse.x * 0.01; let mut color: Vec3; if AA { diff --git a/shaders/src/shaders/skyline.rs b/shaders/src/shaders/skyline.rs index dbb55e5..ca9290e 100644 --- a/shaders/src/shaders/skyline.rs +++ b/shaders/src/shaders/skyline.rs @@ -10,25 +10,39 @@ //! -Otavio Good //! */ //! ``` +use crate::shader_prelude::*; + +pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { name: "Skyline" }; + +pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { + let color = &mut render_result.color; + let &ShaderInput { + resolution, + time, + frag_coord, + mouse, + .. + } = render_instruction; + State::new(Inputs { + resolution, + time, + mouse, + channel0: RgbCube { + alpha: 1.0, + intensity: 1.0, + }, + }) + .main_image(color, frag_coord); +} -use crate::SampleCube; -use shared::*; -use spirv_std::arch::Derivative; -use spirv_std::glam::{vec2, vec3, Vec2, Vec2Swizzles, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles}; - -// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but -// we tie #[no_std] above to the same condition, so it's fine. -#[cfg(target_arch = "spirv")] -use spirv_std::num_traits::Float; - -pub struct Inputs { - pub resolution: Vec3, - pub time: f32, - pub mouse: Vec4, - pub channel0: C0, +struct Inputs { + resolution: Vec3, + time: f32, + mouse: Vec4, + channel0: C0, } -pub struct State { +struct State { inputs: Inputs, // -------------------------------------------------------- @@ -49,8 +63,9 @@ pub struct State { } impl State { - pub fn new(inputs: Inputs) -> Self { - State { + #[must_use] + fn new(inputs: Inputs) -> Self { + Self { inputs, local_time: 0.0, @@ -1009,7 +1024,7 @@ impl State { } } - pub fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { + fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { if NON_REALTIME_HQ_RENDER { // Optionally render a non-realtime scene with high quality self.block_render(frag_coord); diff --git a/shaders/src/shaders/soft_shadow_variation.rs b/shaders/src/shaders/soft_shadow_variation.rs index 1617a4e..8d7168f 100644 --- a/shaders/src/shaders/soft_shadow_variation.rs +++ b/shaders/src/shaders/soft_shadow_variation.rs @@ -16,17 +16,26 @@ //! // Go to lines 54 to compare both. //! ``` -use shared::*; -use spirv_std::glam::{vec2, vec3, Mat3, Vec2, Vec2Swizzles, Vec3, Vec3Swizzles, Vec4}; - -// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but -// we tie #[no_std] above to the same condition, so it's fine. -#[cfg(target_arch = "spirv")] -use spirv_std::num_traits::Float; +use crate::shader_prelude::*; + +pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { + name: "Soft Shadow Variation", +}; + +pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { + let color = &mut render_result.color; + let &ShaderInput { + resolution, + time, + frag_coord, + .. + } = render_instruction; + Inputs { resolution, time }.main_image(color, frag_coord); +} -pub struct Inputs { - pub resolution: Vec3, - pub time: f32, +struct Inputs { + resolution: Vec3, + time: f32, } // make this 1 is your machine is too slow @@ -184,7 +193,7 @@ fn set_camera(ro: Vec3, ta: Vec3, cr: f32) -> Mat3 { } impl Inputs { - pub fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { + fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { // camera let an: f32 = 12.0 - (0.1 * self.time).sin(); let ro: Vec3 = vec3(3.0 * (0.1 * an).cos(), 1.0, -3.0 * (0.1 * an).sin()); diff --git a/shaders/src/shaders/tileable_water_caustic.rs b/shaders/src/shaders/tileable_water_caustic.rs index e2a7afc..fc08308 100644 --- a/shaders/src/shaders/tileable_water_caustic.rs +++ b/shaders/src/shaders/tileable_water_caustic.rs @@ -10,17 +10,26 @@ //! // Water turbulence effect by joltz0r 2013-07-04, improved 2013-07-07 //! ``` -use shared::*; -use spirv_std::glam::{vec2, vec3, Vec2, Vec3, Vec3Swizzles, Vec4}; +use crate::shader_prelude::*; -// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but -// we tie #[no_std] above to the same condition, so it's fine. -#[cfg(target_arch = "spirv")] -use spirv_std::num_traits::Float; +pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { + name: "Tileable Water Caustic", +}; -pub struct Inputs { - pub resolution: Vec3, - pub time: f32, +pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { + let color = &mut render_result.color; + let &ShaderInput { + resolution, + time, + frag_coord, + .. + } = render_instruction; + Inputs { resolution, time }.main_image(color, frag_coord); +} + +struct Inputs { + resolution: Vec3, + time: f32, } // Redefine below to see the tiling... @@ -30,7 +39,7 @@ use core::f32::consts::TAU; const MAX_ITER: usize = 5; impl Inputs { - pub fn main_image(&self, frag_color: &mut Vec4, frag_coord: Vec2) { + fn main_image(&self, frag_color: &mut Vec4, frag_coord: Vec2) { let time: f32 = self.time * 0.5 + 23.0; // uv should be the 0-1 uv of texture... let mut uv: Vec2 = frag_coord / self.resolution.xy(); diff --git a/shaders/src/shaders/tokyo.rs b/shaders/src/shaders/tokyo.rs index 6b15d2b..e71c495 100644 --- a/shaders/src/shaders/tokyo.rs +++ b/shaders/src/shaders/tokyo.rs @@ -13,23 +13,30 @@ //! // I have never been in Tokyo btw. //! ``` -use shared::*; -use spirv_std::glam::{ - mat2, vec2, vec3, vec4, Mat2, Vec2, Vec2Swizzles, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles, +use crate::shader_prelude::*; + +pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { + name: "Tokyo by Night", }; -// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but -// we tie #[no_std] above to the same condition, so it's fine. -#[cfg(target_arch = "spirv")] -use spirv_std::num_traits::Float; +pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { + let color = &mut render_result.color; + let &ShaderInput { + resolution, + time, + frag_coord, + .. + } = render_instruction; + State::new(Inputs { resolution, time }).main_image(color, frag_coord); +} #[derive(Clone, Copy)] -pub struct Inputs { - pub resolution: Vec3, - pub time: f32, +struct Inputs { + resolution: Vec3, + time: f32, } -pub struct State { +struct State { inputs: Inputs, d_l: f32, // minimal distance to light @@ -42,8 +49,9 @@ pub struct State { } impl State { - pub fn new(inputs: Inputs) -> State { - State { + #[must_use] + fn new(inputs: Inputs) -> Self { + Self { inputs, d_l: 0.0, @@ -446,7 +454,7 @@ impl State { //---------------------------------------------------------------------- // main - pub fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { + fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { let mut q: Vec2 = frag_coord / self.inputs.resolution.xy(); let mut p: Vec2 = -Vec2::ONE + 2.0 * q; p.x *= self.inputs.resolution.x / self.inputs.resolution.y; diff --git a/shaders/src/shaders/two_tweets.rs b/shaders/src/shaders/two_tweets.rs index e482020..8c2b760 100644 --- a/shaders/src/shaders/two_tweets.rs +++ b/shaders/src/shaders/two_tweets.rs @@ -6,16 +6,24 @@ //! // License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. //! ``` -use spirv_std::glam::{vec3, Vec2, Vec3, Vec4}; +use crate::shader_prelude::*; -// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but -// we tie #[no_std] above to the same condition, so it's fine. -#[cfg(target_arch = "spirv")] -use spirv_std::num_traits::Float; +pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { name: "Two Tweets" }; -pub struct Inputs { - pub resolution: Vec3, - pub time: f32, +pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { + let color = &mut render_result.color; + let &ShaderInput { + resolution, + time, + frag_coord, + .. + } = render_instruction; + Inputs { resolution, time }.main_image(color, frag_coord); +} + +struct Inputs { + resolution: Vec3, + time: f32, } impl Inputs { @@ -27,7 +35,7 @@ impl Inputs { - 1. } - pub fn main_image(&self, c: &mut Vec4, p: Vec2) { + fn main_image(&self, c: &mut Vec4, p: Vec2) { let d: Vec3 = Vec3::splat(0.5) - p.extend(1.0) / self.resolution.x; let mut o: Vec3 = d; for _ in 0..128 { diff --git a/shaders/src/shaders/voxel_pac_man.rs b/shaders/src/shaders/voxel_pac_man.rs index 7f2efd6..d55cf8a 100644 --- a/shaders/src/shaders/voxel_pac_man.rs +++ b/shaders/src/shaders/voxel_pac_man.rs @@ -14,21 +14,36 @@ //! */ //! ``` -use shared::*; -use spirv_std::glam::{vec2, vec3, Mat3, Vec2, Vec2Swizzles, Vec3, Vec3Swizzles, Vec4}; - -// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but -// we tie #[no_std] above to the same condition, so it's fine. -#[cfg(target_arch = "spirv")] -use spirv_std::num_traits::Float; - -pub struct Inputs { - pub resolution: Vec3, - pub time: f32, - pub mouse: Vec4, +use crate::shader_prelude::*; + +pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { + name: "Voxel PacMan", +}; + +pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { + let color = &mut render_result.color; + let &ShaderInput { + resolution, + time, + frag_coord, + mouse, + .. + } = render_instruction; + State::new(Inputs { + resolution, + time, + mouse, + }) + .main_image(color, frag_coord); } -pub struct State { +struct Inputs { + resolution: Vec3, + time: f32, + mouse: Vec4, +} + +struct State { inputs: Inputs, // Global variable to handle the glow effect @@ -36,8 +51,9 @@ pub struct State { } impl State { - pub fn new(inputs: Inputs) -> State { - State { + #[must_use] + fn new(inputs: Inputs) -> Self { + Self { inputs, glow_counter: 0.0, @@ -253,7 +269,7 @@ fn hsv2rgb(mut hsv: Vec3) -> Vec3 { impl State { // Main function - pub fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { + fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { // Get the fragment let frag: Vec2 = (2.0 * frag_coord - self.inputs.resolution.xy()) / self.inputs.resolution.y; diff --git a/shaders/src/shared_data.rs b/shaders/src/shared_data.rs new file mode 100644 index 0000000..c608ddd --- /dev/null +++ b/shaders/src/shared_data.rs @@ -0,0 +1,21 @@ +use bytemuck::{Pod, Zeroable}; + +#[repr(C)] +#[derive(Copy, Clone, Pod, Zeroable)] +#[allow(unused_attributes)] +pub struct ShaderConstants { + /// Boolean value indicating whether all shaders are rendered in a grid layout. + pub grid: u32, + pub width: u32, + pub height: u32, + pub time: f32, + pub cursor_x: f32, + pub cursor_y: f32, + pub drag_start_x: f32, + pub drag_start_y: f32, + pub drag_end_x: f32, + pub drag_end_y: f32, + pub mouse_left_pressed: u32, + pub mouse_left_clicked: u32, + pub shader_to_show: u32, +} diff --git a/shared/Cargo.toml b/shared/Cargo.toml deleted file mode 100644 index 7659ff9..0000000 --- a/shared/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "shared" -version = "0.0.0" -authors = [] -edition = "2021" - -[dependencies] -spirv-std.workspace = true -bytemuck = { version = "1.20.0", features = ["derive"] } - -[lints] -workspace = true diff --git a/src/main.rs b/src/main.rs index cb11317..7fa6afb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,16 @@ use futures::executor::block_on; use ouroboros::self_referencing; -use std::error::Error; -use std::time::Instant; -use wgpu::{self, InstanceDescriptor}; -use wgpu::{include_spirv, include_spirv_raw}; -use winit::application::ApplicationHandler; -use winit::dpi::LogicalSize; -use winit::event::{ElementState, MouseButton, WindowEvent}; -use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop}; -use winit::keyboard::NamedKey; -use winit::window::{Window, WindowAttributes, WindowId}; +use shadertoys_shaders::{shaders::SHADER_DEFINITIONS, shared_data::ShaderConstants}; +use std::{error::Error, time::Instant}; +use wgpu::{self, include_spirv, include_spirv_raw, InstanceDescriptor}; +use winit::{ + application::ApplicationHandler, + dpi::LogicalSize, + event::{ElementState, KeyEvent, MouseButton, WindowEvent}, + event_loop::{ActiveEventLoop, ControlFlow, EventLoop}, + keyboard::{KeyCode, NamedKey, PhysicalKey}, + window::{Window, WindowAttributes, WindowId}, +}; #[self_referencing] struct WindowSurface { @@ -28,6 +29,9 @@ struct ShaderToyApp { shader_module: Option, close_requested: bool, start: Instant, + // UI state + grid_mode: bool, + shader_to_show: u32, // Mouse state. cursor_x: f32, cursor_y: f32, @@ -58,6 +62,8 @@ impl Default for ShaderToyApp { drag_end_y: 0.0, mouse_left_pressed: false, mouse_left_clicked: false, + shader_to_show: 0, + grid_mode: false, } } } @@ -132,7 +138,7 @@ impl ShaderToyApp { bind_group_layouts: &[], push_constant_ranges: &[wgpu::PushConstantRange { stages: wgpu::ShaderStages::VERTEX_FRAGMENT, - range: 0..std::mem::size_of::() as u32, + range: 0..std::mem::size_of::() as u32, }], }); let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { @@ -201,7 +207,7 @@ impl ShaderToyApp { Err(e) => { eprintln!("Failed to acquire texture: {:?}", e); return; - } + }, }; let view = frame .texture @@ -231,7 +237,7 @@ impl ShaderToyApp { 0.0, 1.0, ); - let push_constants = shared::ShaderConstants { + let push_constants = ShaderConstants { width: current_size.width, height: current_size.height, time: self.start.elapsed().as_secs_f32(), @@ -243,6 +249,8 @@ impl ShaderToyApp { drag_end_y: self.drag_end_y, mouse_left_pressed: self.mouse_left_pressed as u32, mouse_left_clicked: self.mouse_left_clicked as u32, + shader_to_show: self.shader_to_show, + grid: self.grid_mode as u32, }; self.mouse_left_clicked = false; rpass.set_pipeline(self.render_pipeline.as_ref().unwrap()); @@ -285,7 +293,7 @@ impl ApplicationHandler for ShaderToyApp { } } } - } + }, WindowEvent::PointerMoved { position, .. } => { self.cursor_x = position.x as f32; self.cursor_y = position.y as f32; @@ -293,7 +301,7 @@ impl ApplicationHandler for ShaderToyApp { self.drag_end_x = self.cursor_x; self.drag_end_y = self.cursor_y; } - } + }, WindowEvent::PointerButton { state, button, .. } => { if button.mouse_button() == MouseButton::Left { self.mouse_left_pressed = state == ElementState::Pressed; @@ -305,20 +313,59 @@ impl ApplicationHandler for ShaderToyApp { self.mouse_left_clicked = true; } } - } + }, WindowEvent::MouseWheel { delta, .. } => { - if let winit::event::MouseScrollDelta::LineDelta(x, y) = delta { - self.drag_end_x = x * 0.1; - self.drag_end_y = y * 0.1; + if let winit::event::MouseScrollDelta::LineDelta(delta_x, delta_y) = delta { + self.drag_end_x = delta_x * 0.1; + self.drag_end_y = delta_y * 0.1; } - } - WindowEvent::KeyboardInput { event, .. } => { - if event.logical_key == NamedKey::Escape && event.state == ElementState::Pressed { + }, + WindowEvent::KeyboardInput { event, .. } => match event { + KeyEvent { + state: ElementState::Pressed, + .. + } if event.logical_key == NamedKey::Escape => { self.close_requested = true; - } - } + }, + KeyEvent { + state: ElementState::Pressed, + physical_key: PhysicalKey::Code(KeyCode::KeyE), + .. + } => { + self.grid_mode = false; + self.shader_to_show = + (self.shader_to_show + 1) % SHADER_DEFINITIONS.len() as u32; + println!( + "Shader to show: {}", + SHADER_DEFINITIONS[self.shader_to_show as usize].name + ); + }, + KeyEvent { + state: ElementState::Pressed, + physical_key: PhysicalKey::Code(KeyCode::KeyQ), + .. + } => { + self.grid_mode = false; + self.shader_to_show = (self.shader_to_show + SHADER_DEFINITIONS.len() as u32 + - 1) + % SHADER_DEFINITIONS.len() as u32; + println!( + "Shader to show: {}", + SHADER_DEFINITIONS[self.shader_to_show as usize].name + ); + }, + KeyEvent { + state: ElementState::Pressed, + physical_key: PhysicalKey::Code(KeyCode::KeyG), + .. + } => { + self.grid_mode = !self.grid_mode; + println!("Grid mode: {}", self.grid_mode); + }, + _ => {}, + }, WindowEvent::RedrawRequested => self.render(), - _ => {} + _ => {}, } if self.close_requested { event_loop.exit(); From 8fc3f63fdccd158d50e2ef8dd483810f4b6e6009 Mon Sep 17 00:00:00 2001 From: raldone01 Date: Sat, 7 Jun 2025 14:53:24 +0200 Subject: [PATCH 3/7] Clippy lints and code quality. --- shaders/src/shaders/a_lot_of_spheres.rs | 2 +- shaders/src/shaders/a_question_of_time.rs | 4 +- shaders/src/shaders/apollonian.rs | 2 +- shaders/src/shaders/atmosphere_system_test.rs | 20 +-- shaders/src/shaders/bubble_buckey_balls.rs | 22 ++- shaders/src/shaders/filtering_procedurals.rs | 9 +- shaders/src/shaders/flappy_bird.rs | 4 +- shaders/src/shaders/geodesic_tiling.rs | 20 ++- shaders/src/shaders/heart.rs | 6 +- shaders/src/shaders/luminescence.rs | 25 ++- shaders/src/shaders/mandelbrot_smooth.rs | 2 +- shaders/src/shaders/miracle_snowflakes.rs | 2 +- shaders/src/shaders/morphing.rs | 4 +- shaders/src/shaders/on_off_spikes.rs | 15 +- shaders/src/shaders/phantom_star.rs | 8 +- shaders/src/shaders/playing_marble.rs | 4 +- shaders/src/shaders/protean_clouds.rs | 22 +-- shaders/src/shaders/raymarching_primitives.rs | 7 +- shaders/src/shaders/seascape.rs | 2 - shaders/src/shaders/skyline.rs | 18 +-- shaders/src/shaders/soft_shadow_variation.rs | 18 +-- shaders/src/shaders/tokyo.rs | 142 +++++++++--------- shaders/src/shaders/voxel_pac_man.rs | 10 +- 23 files changed, 161 insertions(+), 207 deletions(-) diff --git a/shaders/src/shaders/a_lot_of_spheres.rs b/shaders/src/shaders/a_lot_of_spheres.rs index 6fca4e3..8d71c16 100644 --- a/shaders/src/shaders/a_lot_of_spheres.rs +++ b/shaders/src/shaders/a_lot_of_spheres.rs @@ -77,7 +77,7 @@ fn intersect_plane(ro: Vec3, rd: Vec3, height: f32, dist: &mut f32) -> bool { } let mut d: f32 = -(ro.y - height) / rd.y; - d = d.min(100000.0); + d = d.min(100_000.0); if d > 0.0 { *dist = d; return true; diff --git a/shaders/src/shaders/a_question_of_time.rs b/shaders/src/shaders/a_question_of_time.rs index 12d1850..ede7729 100644 --- a/shaders/src/shaders/a_question_of_time.rs +++ b/shaders/src/shaders/a_question_of_time.rs @@ -75,7 +75,7 @@ fn stroke(d: f32, w: f32, s: f32, i: f32) -> f32 { } // a simple palette fn pal(d: f32) -> Vec3 { - 0.5 * ((6.283 * d * vec3(2.0, 2.0, 1.0) + vec3(0.0, 1.4, 0.0)).cos() + Vec3::ONE) + 0.5 * ((TAU * d * vec3(2.0, 2.0, 1.0) + vec3(0.0, 1.4, 0.0)).cos() + Vec3::ONE) } // 2d rotation matrix fn uvr_rotate(a: f32) -> Mat2 { @@ -100,7 +100,7 @@ fn apollonian(uv: Vec2) -> Vec3 { // a DEC is a configuration of 4 circles tangent to each other // the easiest way to build the initial one it to construct a symetric Steiner Chain. // http://mathworld.wolfram.com/SteinerChain.html - let a: f32 = 6.283 / 3.; + let a: f32 = TAU / 3.; let ra: f32 = 1.0 + (a * 0.5).sin(); let rb: f32 = 1.0 - (a * 0.5).sin(); dec[0] = vec3(0.0, 0.0, -1.0 / ra); diff --git a/shaders/src/shaders/apollonian.rs b/shaders/src/shaders/apollonian.rs index 5d96629..c14fd51 100644 --- a/shaders/src/shaders/apollonian.rs +++ b/shaders/src/shaders/apollonian.rs @@ -180,7 +180,7 @@ impl State { } } - tot = tot / (AA * AA) as f32; + tot /= (AA * AA) as f32; *frag_color = tot.extend(1.0); } diff --git a/shaders/src/shaders/atmosphere_system_test.rs b/shaders/src/shaders/atmosphere_system_test.rs index 5ccd93b..8aba2ea 100644 --- a/shaders/src/shaders/atmosphere_system_test.rs +++ b/shaders/src/shaders/atmosphere_system_test.rs @@ -77,12 +77,12 @@ struct _Plane { fn rotate_around_x(angle_degrees: f32) -> Mat3 { let angle: f32 = angle_degrees.to_radians(); - let _sin: f32 = angle.sin(); - let _cos: f32 = angle.cos(); - Mat3::from_cols_array(&[1.0, 0.0, 0.0, 0.0, _cos, -_sin, 0.0, _sin, _cos]) + let sin: f32 = angle.sin(); + let cos: f32 = angle.cos(); + Mat3::from_cols_array(&[1.0, 0.0, 0.0, 0.0, cos, -sin, 0.0, sin, cos]) } -fn get_primary_ray(cam_local_point: Vec3, cam_origin: &mut Vec3, cam_look_at: &mut Vec3) -> Ray { +fn get_primary_ray(cam_local_point: Vec3, cam_origin: &Vec3, cam_look_at: &Vec3) -> Ray { let fwd: Vec3 = (*cam_look_at - *cam_origin).normalize(); let mut up: Vec3 = vec3(0.0, 1.0, 0.0); let right: Vec3 = up.cross(fwd); @@ -94,7 +94,7 @@ fn get_primary_ray(cam_local_point: Vec3, cam_origin: &mut Vec3, cam_look_at: &m } } -fn isect_sphere(ray: Ray, sphere: Sphere, t0: &mut f32, t1: &mut f32) -> bool { +fn isect_sphere(ray: Ray, sphere: &Sphere, t0: &mut f32, t1: &mut f32) -> bool { let rc: Vec3 = sphere.origin - ray.origin; let radius2: f32 = sphere.radius * sphere.radius; let tca: f32 = rc.dot(ray.direction); @@ -160,7 +160,7 @@ const NUM_SAMPLES_LIGHT: i32 = 8; fn get_sun_light(ray: Ray, optical_depth_r: &mut f32, optical_depth_m: &mut f32) -> bool { let mut t0: f32 = 0.0; let mut t1: f32 = 0.0; - isect_sphere(ray, ATMOSPHERE, &mut t0, &mut t1); + isect_sphere(ray, &ATMOSPHERE, &mut t0, &mut t1); let mut march_pos: f32 = 0.0; let march_step: f32 = t1 / NUM_SAMPLES_LIGHT as f32; @@ -185,7 +185,7 @@ impl State { // "pierce" the atmosphere with the viewing ray let mut t0: f32 = 0.0; let mut t1: f32 = 0.0; - if !isect_sphere(ray, ATMOSPHERE, &mut t0, &mut t1) { + if !isect_sphere(ray, &ATMOSPHERE, &mut t0, &mut t1) { return Vec3::ZERO; } @@ -286,10 +286,10 @@ impl State { col = self.get_incident_light(ray); } else { - let mut eye: Vec3 = vec3(0.0, EARTH_RADIUS + 1.0, 0.0); - let mut look_at: Vec3 = vec3(0.0, EARTH_RADIUS + 1.5, -1.0); + let eye: Vec3 = vec3(0.0, EARTH_RADIUS + 1.0, 0.0); + let look_at: Vec3 = vec3(0.0, EARTH_RADIUS + 1.5, -1.0); - let ray: Ray = get_primary_ray(point_cam, &mut eye, &mut look_at); + let ray: Ray = get_primary_ray(point_cam, &eye, &look_at); if ray.direction.dot(vec3(0.0, 1.0, 0.0)) > 0.0 { col = self.get_incident_light(ray); diff --git a/shaders/src/shaders/bubble_buckey_balls.rs b/shaders/src/shaders/bubble_buckey_balls.rs index 3e2296a..3c8a17e 100644 --- a/shaders/src/shaders/bubble_buckey_balls.rs +++ b/shaders/src/shaders/bubble_buckey_balls.rs @@ -69,10 +69,6 @@ impl State { // ************************************************************************** // CONSTANTS -const PI: f32 = 3.14159; -const TWO_PI: f32 = 6.28318; -const _PI_OVER_TWO: f32 = 1.570796; -const ONE_OVER_PI: f32 = 0.318310; const GR: f32 = 1.61803398; const SMALL_FLOAT: f32 = 0.0001; @@ -94,11 +90,11 @@ const BOND_MATL: f32 = 3.0; // Range of outputs := ([-1.,-1.,-1.] -> [1.,1.,1.]) fn rotate_around_y_axis(point: Vec3, cosangle: f32, sinangle: f32) -> Vec3 { - return vec3( + vec3( point.x * cosangle + point.z * sinangle, point.y, point.x * -sinangle + point.z * cosangle, - ); + ) } // Rotate the input point around the x-axis by the angle given as a @@ -129,9 +125,9 @@ fn _cartesian_to_polar(p: Vec3) -> Vec2 { fn mergeobjs(a: Vec2, b: Vec2) -> Vec2 { if a.x < b.x { - return a; + a } else { - return b; + b } // XXX: Some architectures have bad optimization paths @@ -152,7 +148,7 @@ fn segmentdf(p: Vec3, a: Vec3, b: Vec3, r: f32) -> f32 { let ba: Vec3 = b - a; let mut t: f32 = ba.dot(p - a) / SMALL_FLOAT.max(ba.dot(ba)); t = t.clamp(0., 1.); - return (ba * t + a - p).length() - r; + (ba * t + a - p).length() - r } // ************************************************************************** @@ -277,7 +273,7 @@ impl State { if t > maxd { material = -1.0; } - return vec2(t, material); + vec2(t, material) } } @@ -341,7 +337,7 @@ impl State { let cosrotx: f32 = rotx.cos(); let sinrotx: f32 = rotx.sin(); - let roty: f32 = TWO_PI * click.x + 0.05 * self.time; + let roty: f32 = TAU * click.x + 0.05 * self.time; let cosroty: f32 = roty.cos(); let sinroty: f32 = roty.sin(); @@ -465,10 +461,10 @@ impl State { if ndl > 0. { let frk: f32 = 0.5 + 2.0 * costd * costd * surf.roughness; let diff: Vec3 = surf.basecolor - * ONE_OVER_PI + * FRAC_1_PI * (1. + (frk - 1.) * pow5(1. - costl)) * (1. + (frk - 1.) * pow5(1. - costv)); - //let diff: Vec3 = surf.basecolor * ONE_OVER_PI; // lambert + //let diff: Vec3 = surf.basecolor * FRAC_1_PI; // lambert // D(h) factor // using the GGX approximation where the gamma factor is 2. diff --git a/shaders/src/shaders/filtering_procedurals.rs b/shaders/src/shaders/filtering_procedurals.rs index 2c9f51a..905fde5 100644 --- a/shaders/src/shaders/filtering_procedurals.rs +++ b/shaders/src/shaders/filtering_procedurals.rs @@ -411,13 +411,12 @@ impl Inputs { ddy_uvw = uvw + uvw.dfdy(); } // shading - let mate: Vec3; - if p.x > th { - mate = sample_texture(uvw, nor, mid); + let mate = if p.x > th { + sample_texture(uvw, nor, mid) } else { - mate = sample_texture_with_filter(uvw, ddx_uvw, ddy_uvw, nor, mid); - } + sample_texture_with_filter(uvw, ddx_uvw, ddy_uvw, nor, mid) + }; // lighting let lin: Vec3 = do_lighting(pos, nor, occ, rd); diff --git a/shaders/src/shaders/flappy_bird.rs b/shaders/src/shaders/flappy_bird.rs index 27848d4..bec03ab 100644 --- a/shaders/src/shaders/flappy_bird.rs +++ b/shaders/src/shaders/flappy_bird.rs @@ -102,7 +102,7 @@ const PIPE_BOTTOM: f32 = 39.0; // px const PIPE_HOLE_HEIGHT: f32 = 12.0; // px // const PIPE_OUTLINE_COLOR: Vec4 = RGB(84, 56, 71); -const PIPE_OUTLINE_COLOR: Vec4 = vec4(84 as f32 / 255.0, 56 as f32 / 255.0, 71 as f32 / 255.0, 1.0); +const PIPE_OUTLINE_COLOR: Vec4 = vec4(84.0 / 255.0, 56.0 / 255.0, 71.0 / 255.0, 1.0); // gameplay consts const HORZ_PIPE_DISTANCE: f32 = 100.0; // px; @@ -1237,7 +1237,7 @@ impl State { } } - pub fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { + fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { let level_pixel: Vec2 = self.get_level_pixel(frag_coord); self.frag_color = rgb(113, 197, 207); // draw the blue sky background diff --git a/shaders/src/shaders/geodesic_tiling.rs b/shaders/src/shaders/geodesic_tiling.rs index 4ad2a3a..d571f2d 100644 --- a/shaders/src/shaders/geodesic_tiling.rs +++ b/shaders/src/shaders/geodesic_tiling.rs @@ -86,7 +86,7 @@ fn p_r(p: &mut Vec2, a: f32) { fn p_reflect(p: &mut Vec3, plane_normal: Vec3, offset: f32) -> f32 { let t: f32 = p.dot(plane_normal) + offset; if t < 0.0 { - *p = *p - (2. * t) * plane_normal; + *p -= (2. * t) * plane_normal; } t.sign_gl() } @@ -94,6 +94,10 @@ fn p_reflect(p: &mut Vec3, plane_normal: Vec3, offset: f32) -> f32 { fn smax(a: f32, b: f32, r: f32) -> f32 { let m: f32 = a.max(b); if (-a < r) && (-b < r) { + #[expect( + clippy::imprecise_flops, + reason = "Rust GPU does not yet support hypot from libm" + )] m.max(-(r - ((r + a) * (r + a) + (r + b) * (r + b)).sqrt())) } else { m @@ -141,14 +145,10 @@ impl State { // Adapted from mattz https://www.shadertoy.com/view/4d2GzV // -------------------------------------------------------- -const SQRT3: f32 = 1.7320508075688772; const I3: f32 = 0.5773502691896258; const CART2HEX: Mat2 = mat2(vec2(1.0, 0.0), vec2(I3, 2.0 * I3)); -const HEX2CART: Mat2 = mat2(vec2(1.0, 0.0), vec2(-0.5, 0.5 * SQRT3)); - -const _PHI: f32 = 1.618033988749895; -const _TAU: f32 = 6.283185307179586; +const HEX2CART: Mat2 = mat2(vec2(1.0, 0.0), vec2(-0.5, 0.5 * SQRT_3)); struct TriPoints { a: Vec2, @@ -272,7 +272,7 @@ impl State { // -------------------------------------------------------- fn pal(t: f32, a: Vec3, b: Vec3, c: Vec3, d: Vec3) -> Vec3 { - a + b * (6.28318 * (c * t + d)).cos() + a + b * (TAU * (c * t + d)).cos() } fn spectrum(n: f32) -> Vec3 { @@ -307,11 +307,9 @@ impl State { xy.y = mouse.y; } } - let rx: f32; - let ry: f32; - rx = (xy.y + 0.5) * PI; - ry = (-xy.x) * 2.0 * PI; + let rx = (xy.y + 0.5) * PI; + let ry = (-xy.x) * 2.0 * PI; spherical_matrix(rx, ry) } diff --git a/shaders/src/shaders/heart.rs b/shaders/src/shaders/heart.rs index 7231a0c..b0d4ab8 100644 --- a/shaders/src/shaders/heart.rs +++ b/shaders/src/shaders/heart.rs @@ -29,7 +29,7 @@ struct Inputs { impl Inputs { fn main_image(&self, frag_color: &mut Vec4, frag_coord: Vec2) { let mut p: Vec2 = - (2.0 * frag_coord - self.resolution.xy()) / (self.resolution.y.min(self.resolution.x)); + (2.0 * frag_coord - self.resolution.xy()) / (self.resolution.xy().min_element()); // background color let bcol: Vec3 = vec3(1.0, 0.8, 0.7 - 0.07 * p.y) * (1.0 - 0.25 * p.length()); @@ -37,7 +37,7 @@ impl Inputs { // animate let tt: f32 = self.time.rem_euclid(1.5) / 1.5; let mut ss: f32 = tt.powf(0.2) * 0.5 + 0.5; - ss = 1.0 + ss * 0.5 * (tt * 6.2831 * 3.0 + p.y * 0.5).sin() * (-tt * 4.0).exp(); + ss = 1.0 + ss * 0.5 * (tt * TAU * 3.0 + p.y * 0.5).sin() * (-tt * 4.0).exp(); p *= vec2(0.5, 1.5) + ss * vec2(0.5, -0.5); // shape @@ -51,7 +51,7 @@ impl Inputs { d = 0.5; } else { p.y -= 0.25; - let a: f32 = p.x.atan2(p.y) / 3.141593; + let a: f32 = p.x.atan2(p.y) / PI; r = p.length(); let h: f32 = a.abs(); d = (13.0 * h - 22.0 * h * h + 10.0 * h * h * h) / (6.0 - 5.0 * h); diff --git a/shaders/src/shaders/luminescence.rs b/shaders/src/shaders/luminescence.rs index 777ed86..90dee0b 100644 --- a/shaders/src/shaders/luminescence.rs +++ b/shaders/src/shaders/luminescence.rs @@ -93,10 +93,6 @@ const _LF: Vec3 = vec3(1.0, 0.0, 0.0); const UP: Vec3 = vec3(0.0, 1.0, 0.0); const _FW: Vec3 = vec3(0.0, 0.0, 1.0); -const _HALF_PI: f32 = 1.570796326794896619; -const PI: f32 = 3.141592653589793238; -const TWO_PI: f32 = 6.283185307179586; - const ACCENT_COLOR1: Vec3 = vec3(1.0, 0.1, 0.5); const SECOND_COLOR1: Vec3 = vec3(0.1, 0.5, 1.0); const ACCENT_COLOR2: Vec3 = vec3(1.0, 0.5, 0.1); @@ -110,7 +106,7 @@ fn _n2(x: f32, y: f32) -> f32 { } fn n3(mut p: Vec3) -> f32 { - p = (p * 0.3183099 + Vec3::splat(0.1)).fract_gl(); + p = (p * FRAC_1_PI + Vec3::splat(0.1)).fract_gl(); p *= 17.0; (p.x * p.y * p.z * (p.x + p.y + p.z)).fract_gl() } @@ -215,7 +211,7 @@ fn sd_sphere(p: Vec3, pos: Vec3, s: f32) -> f32 { // From http://mercury.sexy/hg_sdf fn p_mod_polar(p: &mut Vec2, repetitions: f32, fix: f32) -> Vec2 { - let angle: f32 = TWO_PI / repetitions; + let angle: f32 = TAU / repetitions; let mut a: f32 = p.y.atan2(p.x) + angle / 2.; let r: f32 = p.length(); let _c: f32 = (a / angle).floor(); @@ -332,14 +328,13 @@ impl State { let n: f32 = n3(id); let mut o: De = De::default(); - o.m = 0.0; - let mut x: f32 = (p.y + n * TWO_PI) * 1. + t; + let mut x: f32 = (p.y + n * TAU) * 1. + t; let r: f32 = 1.; let pump: f32 = (x + x.cos()).cos() + (2.0 * x).sin() * 0.2 + (4.0 * x).sin() * 0.02; - x = t + n * TWO_PI; + x = t + n * TAU; p.y -= ((x + x.cos()).cos() + (2.0 * x).sin() * 0.2) * 0.6; p = (p.xz() * (1.0 + pump * 0.2)).extend(p.y).xzy(); @@ -350,7 +345,7 @@ impl State { o.m = 1.0; if p.y < 0.5 { - let sway: f32 = (t + p.y + n * TWO_PI).sin() * smoothstep(0.5, -3.0, p.y) * n * 0.3; + let sway: f32 = (t + p.y + n * TAU).sin() * smoothstep(0.5, -3.0, p.y) * n * 0.3; p.x += sway * n; // add some sway to the tentacles p.z += sway * (1. - n); @@ -466,21 +461,21 @@ impl State { p.y *= scale; - let mut s2: f32 = 5. * p.x / TWO_PI; + let mut s2: f32 = 5. * p.x / TAU; let _id: f32 = s2.floor(); s2 = s2.fract_gl(); let ep: Vec2 = vec2(s2 - 0.5, p.y - 0.6); let ed: f32 = ep.length(); let e: f32 = b(0.35, 0.45, 0.05, ed); - let mut s: f32 = sin(s2 * TWO_PI * 15.0); + let mut s: f32 = sin(s2 * TAU * 15.0); s = s * s; s = s * s; - s *= smoothstep(1.4, -0.3, uv.y - (s2 * TWO_PI).cos() * 0.2 + 0.3) + s *= smoothstep(1.4, -0.3, uv.y - (s2 * TAU).cos() * 0.2 + 0.3) * smoothstep(-0.6, -0.3, uv.y); let t: f32 = self.inputs.time * 5.0; - let mask: f32 = sin(p.x * TWO_PI * 2.0 + t); + let mask: f32 = sin(p.x * TAU * 2.0 + t); s *= mask * mask * 2.0; s + e * pump * 2.0 @@ -595,7 +590,7 @@ impl State { self.accent = mix(ACCENT_COLOR1, ACCENT_COLOR2, sin(t * 15.456)); self.bg = mix(SECOND_COLOR1, SECOND_COLOR2, sin(t * 7.345231)); - let turn: f32 = (0.1 - m.x) * TWO_PI; + let turn: f32 = (0.1 - m.x) * TAU; let s: f32 = turn.sin(); let c: f32 = turn.cos(); let rot_x: Mat3 = Mat3::from_cols_array(&[c, 0.0, s, 0.0, 1.0, 0.0, s, 0.0, -c]); diff --git a/shaders/src/shaders/mandelbrot_smooth.rs b/shaders/src/shaders/mandelbrot_smooth.rs index c32346e..80906d5 100644 --- a/shaders/src/shaders/mandelbrot_smooth.rs +++ b/shaders/src/shaders/mandelbrot_smooth.rs @@ -69,7 +69,7 @@ impl Inputs { // equivalent optimized smooth interation count let sl: f32 = l - z.dot(z).log2().log2() + 4.0; - let al: f32 = smoothstep(-0.1, 0.0, (self.time * 0.5 * 6.2831).sin()); + let al: f32 = smoothstep(-0.1, 0.0, (self.time * 0.5 * TAU).sin()); mix(l, sl, al) } diff --git a/shaders/src/shaders/miracle_snowflakes.rs b/shaders/src/shaders/miracle_snowflakes.rs index 5919a29..4a03065 100644 --- a/shaders/src/shaders/miracle_snowflakes.rs +++ b/shaders/src/shaders/miracle_snowflakes.rs @@ -126,7 +126,7 @@ fn noise3(x: Vec3) -> f32 { hash4(Vec4::splat(n) + NC1), f.xxxx(), ); - return mix(mix(s1.x, s1.y, f.y), mix(s1.z, s1.w, f.y), f.z); + mix(mix(s1.x, s1.y, f.y), mix(s1.z, s1.w, f.y), f.z) } fn noise3_2(x: Vec3) -> Vec2 { vec2(noise3(x), noise3(x + Vec3::splat(100.0))) diff --git a/shaders/src/shaders/morphing.rs b/shaders/src/shaders/morphing.rs index ef93579..2ce40cd 100644 --- a/shaders/src/shaders/morphing.rs +++ b/shaders/src/shaders/morphing.rs @@ -92,7 +92,7 @@ const _E: Vec3 = vec3(0.0, 0.01, 0.0); // Distance to Bezier // inspired by [iq:https://www.shadertoy.com/view/ldj3Wh] -// calculate distance to 2D bezier curve on xy but without forgeting the z component of p +// calculate distance to 2D bezier curve on xy but without forgetting the z component of p // total distance is corrected using pytagore just before return fn bezier(mut m: Vec2, mut n: Vec2, mut o: Vec2, p: Vec3) -> Vec2 { let q: Vec2 = p.xy(); @@ -153,7 +153,7 @@ impl State { // Distance to other shapes --------------------------------------------- let mut d_shape: f32; - let id_morph: i32 = ((0.5 + (self.inputs.time) / (2.0 * 3.141592658)).floor() % 3.0) as i32; + let id_morph: i32 = ((0.5 + self.inputs.time / TAU).floor() % 3.0) as i32; if id_morph == 1 { p = (self.mat2_rot.transpose() * p.xz()).extend(p.y).xzy(); diff --git a/shaders/src/shaders/on_off_spikes.rs b/shaders/src/shaders/on_off_spikes.rs index 88164e0..4963f03 100644 --- a/shaders/src/shaders/on_off_spikes.rs +++ b/shaders/src/shaders/on_off_spikes.rs @@ -78,13 +78,8 @@ const TENTACLE_COL: Vec3 = vec3(0.06, 0.06, 0.06); const GAMMA: f32 = 2.2; -//--- -const PI2: f32 = 6.283185307179586476925286766559; -const PIH: f32 = 1.5707963267949; - // Using the nebula function of the "Star map shader" by morgan3d // as environment map and light sphere texture (https://www.shadertoy.com/view/4sBXzG) -const _PI: f32 = 3.1415927; const NUM_OCTAVES: i32 = 4; fn hash(n: f32) -> f32 { (n.sin() * 1e4).fract_gl() @@ -223,7 +218,7 @@ impl State { let mut a: f32 = q.z.atan2(q.x); a += 0.4 * (r - self.inputs.time).sin(); - q = vec3(a * NUM_TENTACLES as f32 / PI2, q.y, q.xz().length()); // circular domain + q = vec3(a * NUM_TENTACLES as f32 / TAU, q.y, q.xz().length()); // circular domain q = vec3(q.x.rem_euclid(1.0) - 0.5 * 1.0, q.y, q.z); // repetition d3 = sd_capped_cylinder( @@ -325,9 +320,7 @@ impl State { fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { //self.time = self.inputs.time; - self.glow = (2.0 * (self.inputs.time * 0.7 - 5.0).sin()) - .min(1.0) - .max(0.0); + self.glow = (2.0 * (self.inputs.time * 0.7 - 5.0).sin()).clamp(0.0, 1.0); self.bite = smoothstep(0.0, 1.0, 1.6 * (self.inputs.time * 0.7).sin()); self.sphere_col = SPHERE_COL * self.glow; @@ -345,9 +338,9 @@ impl State { self.inputs.mouse.xy() / self.inputs.resolution.xy() - Vec2::splat(0.5); let mdis: f32 = 8.0 + 6.0 * mrel.y; cp = vec3( - mdis * (-mrel.x * PIH).cos(), + mdis * (-mrel.x * FRAC_PI_2).cos(), 4.0 * mrel.y, - mdis * (-mrel.x * PIH).sin(), + mdis * (-mrel.x * FRAC_PI_2).sin(), ); } diff --git a/shaders/src/shaders/phantom_star.rs b/shaders/src/shaders/phantom_star.rs index f883cfc..e6fd3c6 100644 --- a/shaders/src/shaders/phantom_star.rs +++ b/shaders/src/shaders/phantom_star.rs @@ -28,13 +28,9 @@ fn rot(a: f32) -> Mat2 { Mat2::from_cols_array(&[c, s, -s, c]) } -//const pi: f32 = (-1.0).acos(); -const PI_: f32 = PI; -const PI2: f32 = PI_ * 2.0; - fn pmod(p: Vec2, r: f32) -> Vec2 { - let mut a: f32 = p.x.atan2(p.y) + PI_ / r; - let n: f32 = PI2 / r; + let mut a: f32 = p.x.atan2(p.y) + PI / r; + let n: f32 = TAU / r; a = (a / n).floor() * n; rot(-a).transpose() * p } diff --git a/shaders/src/shaders/playing_marble.rs b/shaders/src/shaders/playing_marble.rs index 1f367e4..bbf55fe 100644 --- a/shaders/src/shaders/playing_marble.rs +++ b/shaders/src/shaders/playing_marble.rs @@ -107,9 +107,9 @@ impl Inputs { p.x *= self.resolution.x / self.resolution.y; let mut m: Vec2 = Vec2::ZERO; if self.mouse.z > 0.0 { - m = self.mouse.xy() / self.resolution.xy() * 3.14; + m = self.mouse.xy() / self.resolution.xy() * PI; } - m = m - Vec2::splat(0.5); + m -= Vec2::splat(0.5); // camera diff --git a/shaders/src/shaders/protean_clouds.rs b/shaders/src/shaders/protean_clouds.rs index ede75b4..fbd9df7 100644 --- a/shaders/src/shaders/protean_clouds.rs +++ b/shaders/src/shaders/protean_clouds.rs @@ -8,20 +8,20 @@ //! // Contact the author for other licensing options //! //! /* -//! Technical details: +//! Technical details: //! -//! The main volume noise is generated from a deformed periodic grid, which can produce -//! a large range of noise-like patterns at very cheap evalutation cost. Allowing for multiple -//! fetches of volume gradient computation for improved lighting. +//! The main volume noise is generated from a deformed periodic grid, which can produce +//! a large range of noise-like patterns at very cheap evalutation cost. Allowing for multiple +//! fetches of volume gradient computation for improved lighting. //! -//! To further accelerate marching, since the volume is smooth, more than half the the density -//! information isn't used to rendering or shading but only as an underlying volume distance to -//! determine dynamic step size, by carefully selecting an equation (polynomial for speed) to -//! step as a function of overall density (not necessarialy rendered) the visual results can be -//! the same as a naive implementation with ~40% increase in rendering performance. +//! To further accelerate marching, since the volume is smooth, more than half the the density +//! information isn't used to rendering or shading but only as an underlying volume distance to +//! determine dynamic step size, by carefully selecting an equation (polynomial for speed) to +//! step as a function of overall density (not necessarialy rendered) the visual results can be +//! the same as a naive implementation with ~40% increase in rendering performance. //! -//! Since the dynamic marching step size is even less uniform due to steps not being rendered at all -//! the fog is evaluated as the difference of the fog integral at each rendered step. +//! Since the dynamic marching step size is even less uniform due to steps not being rendered at all +//! the fog is evaluated as the difference of the fog integral at each rendered step. //! //! */ //! ``` diff --git a/shaders/src/shaders/raymarching_primitives.rs b/shaders/src/shaders/raymarching_primitives.rs index c377fc4..4ad0c76 100644 --- a/shaders/src/shaders/raymarching_primitives.rs +++ b/shaders/src/shaders/raymarching_primitives.rs @@ -91,7 +91,7 @@ fn sd_bounding_box(mut p: Vec3, b: Vec3, e: f32) -> f32 { fn sd_ellipsoid(p: Vec3, r: Vec3) -> f32 { let k0: f32 = (p / r).length(); let k1: f32 = (p / (r * r)).length(); - return k0 * (k0 - 1.0) / k1; + k0 * (k0 - 1.0) / k1 } fn sd_torus(p: Vec3, t: Vec2) -> f32 { @@ -193,7 +193,7 @@ fn sd_tri_prism(mut p: Vec3, mut h: Vec2) -> f32 { h.x *= 0.5 * k; p = (p.xy() / h.x).extend(p.z); p.x = p.x.abs() - 1.0; - p.y = p.y + 1.0 / k; + p.y += 1.0 / k; if p.x + k * p.y > 0.0 { p = (vec2(p.x - k * p.y, -k * p.x - p.y) / 2.0).extend(p.z); } @@ -377,6 +377,7 @@ fn op_u(d1: Vec2, d2: Vec2) -> Vec2 { //------------------------------------------------------------------ impl Inputs { + #[allow(unused)] fn zero(&self) -> i32 { let frame = self.frame; if frame >= 0 { @@ -800,7 +801,7 @@ fn set_camera(ro: Vec3, ta: Vec3, cr: f32) -> Mat3 { } impl Inputs { - pub fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { + fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { let mo: Vec2 = self.mouse.xy() / self.resolution.xy(); let time: f32 = 32.0 + self.time * 1.5; diff --git a/shaders/src/shaders/seascape.rs b/shaders/src/shaders/seascape.rs index bae7251..4164d5e 100644 --- a/shaders/src/shaders/seascape.rs +++ b/shaders/src/shaders/seascape.rs @@ -37,8 +37,6 @@ struct Inputs { } const NUM_STEPS: usize = 8; -const PI: f32 = 3.141592; -const _EPSILON: f32 = 1e-3; impl Inputs { fn epsilon_nrm(&self) -> f32 { 0.1 / self.resolution.x diff --git a/shaders/src/shaders/skyline.rs b/shaders/src/shaders/skyline.rs index ca9290e..f4d60b7 100644 --- a/shaders/src/shaders/skyline.rs +++ b/shaders/src/shaders/skyline.rs @@ -155,18 +155,6 @@ fn noise(uv: Vec3) -> f32 { ) } -const PI: f32 = 3.14159265; - -fn saturate_vec3(a: Vec3) -> Vec3 { - a.clamp(Vec3::ZERO, Vec3::ONE) -} -fn _saturate_vec2(a: Vec2) -> Vec2 { - a.clamp(Vec2::ZERO, Vec2::ONE) -} -fn saturate(a: f32) -> f32 { - a.clamp(0.0, 1.0) -} - impl State { // This function basically is a procedural environment map that makes the sun fn get_sun_color_small(&self, ray_dir: Vec3, sun_dir: Vec3) -> Vec3 { @@ -440,7 +428,7 @@ impl State { rep.z += p2.x.floor(); // shift so less repitition between parallel blocks rep.x = repeat(p2.x - 0.5, 1.0); // repeat every block - rep.z = rep.z * rep.x.sign_gl(); // mirror but keep cars facing the right way + rep.z *= rep.x.sign_gl(); // mirror but keep cars facing the right way rep.x = (rep.x * rep.x.sign_gl()) - 0.09; rep.z -= car_time * cross_street; // make cars move let unique_id: f32 = (rep.z / repeat_dist).floor(); // each car gets a unique ID that we can use for colors @@ -541,7 +529,7 @@ impl State { // debugging camera let mx: f32 = -self.inputs.mouse.x / self.inputs.resolution.x * PI * 2.0; // + localTime * 0.05; - let my: f32 = self.inputs.mouse.y / self.inputs.resolution.y * 3.14 * 0.5 + PI / 2.0; // + sin(localTime * 0.3)*0.8+0.1;//*PI/2.01; + let my: f32 = self.inputs.mouse.y / self.inputs.resolution.y * PI * 0.5 + PI / 2.0; // + sin(localTime * 0.3)*0.8+0.1;//*PI/2.01; cam_pos = vec3(my.cos() * mx.cos(), my.sin(), my.cos() * mx.sin()) * 7.35; //7.35 } else { @@ -1048,7 +1036,7 @@ impl State { ); // don't antialias if only 1 sample. if ANTIALIASING_SAMPLES == 1 { - jittered = frag_coord + jittered = frag_coord; }; // Accumulate one pass of raytracing into our pixel value final_color += self.ray_trace(jittered); diff --git a/shaders/src/shaders/soft_shadow_variation.rs b/shaders/src/shaders/soft_shadow_variation.rs index 8d7168f..e4c78d2 100644 --- a/shaders/src/shaders/soft_shadow_variation.rs +++ b/shaders/src/shaders/soft_shadow_variation.rs @@ -2,7 +2,7 @@ //! //! Original comment: //! ```glsl -//! // +//! // //! // Testing Sebastian Aaltonen's soft shadow improvement //! // //! // The technique is based on estimating a better closest point in ray @@ -56,13 +56,13 @@ fn sd_box(p: Vec3, b: Vec3) -> f32 { fn map(pos: Vec3) -> f32 { let qos: Vec3 = vec3((pos.x + 0.5).fract_gl() - 0.5, pos.y, pos.z); - return sd_plane(pos - vec3(0.0, 0.00, 0.0)) - .min(sd_box(qos - vec3(0.0, 0.25, 0.0), vec3(0.2, 0.5, 0.2))); + sd_plane(pos - vec3(0.0, 0.00, 0.0)) + .min(sd_box(qos - vec3(0.0, 0.25, 0.0), vec3(0.2, 0.5, 0.2))) } //------------------------------------------------------------------ -fn calc_softshadow(ro: Vec3, rd: Vec3, mint: f32, tmax: f32, technique: i32) -> f32 { +fn calc_softshadow(ro: Vec3, rd: Vec3, mint: f32, tmax: f32, technique: bool) -> f32 { let mut res: f32 = 1.0; let mut t: f32 = mint; let mut ph: f32 = 1e10; // big, such that y = 0 on the first iteration @@ -70,7 +70,7 @@ fn calc_softshadow(ro: Vec3, rd: Vec3, mint: f32, tmax: f32, technique: i32) -> let h: f32 = map(ro + rd * t); // traditional technique - if technique == 0 { + if !technique { res = res.min(10.0 * h / t); } // improved technique @@ -149,7 +149,7 @@ fn calc_ao(pos: Vec3, nor: Vec3) -> f32 { (1.0 - 1.5 * occ).clamp(0.0, 1.0) } -fn render(ro: Vec3, rd: Vec3, technique: i32) -> Vec3 { +fn render(ro: Vec3, rd: Vec3, technique: bool) -> Vec3 { let mut col: Vec3 = Vec3::ZERO; let t: f32 = cast_ray(ro, rd); @@ -201,11 +201,7 @@ impl Inputs { // camera-to-world transformation let ca: Mat3 = set_camera(ro, ta, 0.0); - let technique: i32 = if (self.time / 2.0).fract_gl() > 0.5 { - 1 - } else { - 0 - }; + let technique = (self.time / 2.0).fract_gl() > 0.5; let mut tot: Vec3 = Vec3::ZERO; diff --git a/shaders/src/shaders/tokyo.rs b/shaders/src/shaders/tokyo.rs index e71c495..18e2e9a 100644 --- a/shaders/src/shaders/tokyo.rs +++ b/shaders/src/shaders/tokyo.rs @@ -347,7 +347,7 @@ impl State { } } - ro = ro + rd * t; + ro *= rd * t; self.nor1 = self.calc_normal(ro); ro += 0.01 * self.nor1; rd = rd.reflect(self.nor1); @@ -462,87 +462,85 @@ impl State { if q.y < 0.12 || q.y >= 0.88 { *frag_color = vec4(0.0, 0.0, 0.0, 1.0); return; - } else { - // camera - let z: f32 = self.time(); - let x: f32 = -10.9 + 1. * (self.time() * 0.2).sin(); - let ro: Vec3 = vec3(x, 1.3 + 0.3 * (self.time() * 0.26).cos(), z - 1.); - let ta: Vec3 = vec3( - -8.0, - 1.3 + 0.4 * (self.time() * 0.26).cos(), - z + 4. + (self.time() * 0.04).cos(), - ); + } - let ww: Vec3 = (ta - ro).normalize(); - let uu: Vec3 = ww.cross(vec3(0.0, 1.0, 0.0)).normalize(); - let vv: Vec3 = uu.cross(ww).normalize(); - let rd: Vec3 = (-p.x * uu + p.y * vv + 2.2 * ww).normalize(); - - let mut col: Vec3 = BACKGROUND_COLOR; - - // raymarch - let ints: f32 = self.intersect(ro + random_start(p) * rd, rd); - if ints > -0.5 { - // calculate reflectance - let mut r: f32 = 0.09; - if self.int1.y > 0.129 { - r = 0.025 - * hash( - 133.1234 * (self.int1.y / 3.0).floor() + (self.int1.z / 3.0).floor(), - ); - } - if self.int1.x.abs() < 8.0 { - if self.int1.y < 0.01 { - // road - r = 0.007 * fbm(self.int1.xz()); - } else { - // car - r = 0.02; - } - } - if self.int1.x.abs() < 0.1 { - r *= 4.0; - } - if (self.int1.x.abs() - 7.4).abs() < 0.1 { - r *= 4.0; + // camera + let z: f32 = self.time(); + let x: f32 = -10.9 + 1. * (self.time() * 0.2).sin(); + let ro: Vec3 = vec3(x, 1.3 + 0.3 * (self.time() * 0.26).cos(), z - 1.); + let ta: Vec3 = vec3( + -8.0, + 1.3 + 0.4 * (self.time() * 0.26).cos(), + z + 4. + (self.time() * 0.04).cos(), + ); + + let ww: Vec3 = (ta - ro).normalize(); + let uu: Vec3 = ww.cross(vec3(0.0, 1.0, 0.0)).normalize(); + let vv: Vec3 = uu.cross(ww).normalize(); + let rd: Vec3 = (-p.x * uu + p.y * vv + 2.2 * ww).normalize(); + + let mut col: Vec3 = BACKGROUND_COLOR; + + // raymarch + let ints: f32 = self.intersect(ro + random_start(p) * rd, rd); + if ints > -0.5 { + // calculate reflectance + let mut r: f32 = 0.09; + if self.int1.y > 0.129 { + r = 0.025 + * hash(133.1234 * (self.int1.y / 3.0).floor() + (self.int1.z / 3.0).floor()); + } + if self.int1.x.abs() < 8.0 { + if self.int1.y < 0.01 { + // road + r = 0.007 * fbm(self.int1.xz()); + } else { + // car + r = 0.02; } + } + if self.int1.x.abs() < 0.1 { + r *= 4.0; + } + if (self.int1.x.abs() - 7.4).abs() < 0.1 { + r *= 4.0; + } - r *= 2.0; + r *= 2.0; - col = self.shade(ro, self.int1, self.nor1); + col = self.shade(ro, self.int1, self.nor1); - if ints > 0.5 { - let tmp = self.calc_normal_simple(self.int2); - col += r * self.shade(self.int1, self.int2, tmp); - } - if self.lint2.w > 0. { - col += (r * LIGHTINTENSITY * (-self.lint2.w * 7.0).exp()) - * self.get_light_color(self.lint2.xyz()); - } + if ints > 0.5 { + let tmp = self.calc_normal_simple(self.int2); + col += r * self.shade(self.int1, self.int2, tmp); } + if self.lint2.w > 0. { + col += (r * LIGHTINTENSITY * (-self.lint2.w * 7.0).exp()) + * self.get_light_color(self.lint2.xyz()); + } + } - // Rain (by Dave Hoskins) - let st: Vec2 = 256. - * (p * vec2(0.5, 0.01) + vec2(self.time() * 0.13 - q.y * 0.6, self.time() * 0.13)); - let mut f: f32 = noise(st) * noise(st * 0.773) * 1.55; - f = 0.25 + (f.abs().powf(13.0) * 13.0).clamp(0.0, q.y * 0.14); + // Rain (by Dave Hoskins) + let st: Vec2 = + 256. * (p * vec2(0.5, 0.01) + vec2(self.time() * 0.13 - q.y * 0.6, self.time() * 0.13)); + let mut f: f32 = noise(st) * noise(st * 0.773) * 1.55; + f = 0.25 + (f.abs().powf(13.0) * 13.0).clamp(0.0, q.y * 0.14); - if self.lint1.w > 0.0 { - col += (f * LIGHTINTENSITY * (-self.lint1.w * 7.0).exp()) - * self.get_light_color(self.lint1.xyz()); - } + if self.lint1.w > 0.0 { + col += (f * LIGHTINTENSITY * (-self.lint1.w * 7.0).exp()) + * self.get_light_color(self.lint1.xyz()); + } - col += 0.25 * f * (Vec3::splat(0.2) + BACKGROUND_COLOR); + col += 0.25 * f * (Vec3::splat(0.2) + BACKGROUND_COLOR); - // post processing - col = col.clamp(Vec3::ZERO, Vec3::ONE).powf(0.4545); - col *= 1.2 * vec3(1.0, 0.99, 0.95); - col = (1.06 * col - Vec3::splat(0.03)).clamp(Vec3::ZERO, Vec3::ONE); - q.y = (q.y - 0.12) * (1. / 0.76); - col *= Vec3::splat(0.5) - + Vec3::splat(0.5) * (16.0 * q.x * q.y * (1.0 - q.x) * (1.0 - q.y)).powf(0.1); + // post processing + col = col.clamp(Vec3::ZERO, Vec3::ONE).powf(0.4545); + col *= 1.2 * vec3(1.0, 0.99, 0.95); + col = (1.06 * col - Vec3::splat(0.03)).clamp(Vec3::ZERO, Vec3::ONE); + q.y = (q.y - 0.12) * (1. / 0.76); + col *= Vec3::splat(0.5) + + Vec3::splat(0.5) * (16.0 * q.x * q.y * (1.0 - q.x) * (1.0 - q.y)).powf(0.1); - *frag_color = col.extend(1.0); - } + *frag_color = col.extend(1.0); } } diff --git a/shaders/src/shaders/voxel_pac_man.rs b/shaders/src/shaders/voxel_pac_man.rs index d55cf8a..3b1e76f 100644 --- a/shaders/src/shaders/voxel_pac_man.rs +++ b/shaders/src/shaders/voxel_pac_man.rs @@ -85,10 +85,6 @@ const BACKGROUND: f32 = 0.7; const GLOW: f32 = 0.4; const GAMMA: f32 = 0.8; -// Math constants -const PI: f32 = 3.14159265359; -const SQRT3: f32 = 1.73205080757; - // PRNG (from https://www.shadertoy.com/view/4djSRW) fn rand(mut seed: Vec3) -> f32 { seed = (seed * vec3(5.3983, 5.4427, 6.9371)).fract_gl(); @@ -206,9 +202,9 @@ impl State { } else { d = self.dist_scene(*p, &mut p2); if voxelized > 0.5 { - if d.x < SQRT3 * 0.5 { - ray_length_check_voxel = ray_length + d.x.abs() + SQRT3 * 0.5; - d.x = (ray_length_in_voxel - ray_length + DELTA).max(d.x - SQRT3 * 0.5); + if d.x < SQRT_3 * 0.5 { + ray_length_check_voxel = ray_length + d.x.abs() + SQRT_3 * 0.5; + d.x = (ray_length_in_voxel - ray_length + DELTA).max(d.x - SQRT_3 * 0.5); } } else if d.x < DELTA { break; From 511ccfd377da11e7fa6220ec4b03fa2824556eea Mon Sep 17 00:00:00 2001 From: raldone01 Date: Sat, 7 Jun 2025 16:01:47 +0200 Subject: [PATCH 4/7] Minor consistency change. --- shaders/src/lib.rs | 2 +- shaders/src/shared_data.rs | 10 +++++++--- src/main.rs | 4 +++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/shaders/src/lib.rs b/shaders/src/lib.rs index 7946058..cd306b4 100644 --- a/shaders/src/lib.rs +++ b/shaders/src/lib.rs @@ -75,7 +75,7 @@ pub fn fs(constants: &ShaderConstants, mut frag_coord: Vec2) -> Vec4 { let shader_input: ShaderInput; let shader_output = &mut ShaderResult { color: Vec4::ZERO }; - if constants.grid == 0 { + if constants.grid_mode == 0 { shader_input = ShaderInput { resolution, time, diff --git a/shaders/src/shared_data.rs b/shaders/src/shared_data.rs index c608ddd..8a9fa75 100644 --- a/shaders/src/shared_data.rs +++ b/shaders/src/shared_data.rs @@ -4,11 +4,16 @@ use bytemuck::{Pod, Zeroable}; #[derive(Copy, Clone, Pod, Zeroable)] #[allow(unused_attributes)] pub struct ShaderConstants { - /// Boolean value indicating whether all shaders are rendered in a grid layout. - pub grid: u32, pub width: u32, pub height: u32, pub time: f32, + + // UI state + /// Boolean value indicating whether all shaders are rendered in a grid layout. + pub grid_mode: u32, + pub shader_to_show: u32, + + // Mouse state. pub cursor_x: f32, pub cursor_y: f32, pub drag_start_x: f32, @@ -17,5 +22,4 @@ pub struct ShaderConstants { pub drag_end_y: f32, pub mouse_left_pressed: u32, pub mouse_left_clicked: u32, - pub shader_to_show: u32, } diff --git a/src/main.rs b/src/main.rs index 7fa6afb..291c980 100644 --- a/src/main.rs +++ b/src/main.rs @@ -29,9 +29,11 @@ struct ShaderToyApp { shader_module: Option, close_requested: bool, start: Instant, + // UI state grid_mode: bool, shader_to_show: u32, + // Mouse state. cursor_x: f32, cursor_y: f32, @@ -250,7 +252,7 @@ impl ShaderToyApp { mouse_left_pressed: self.mouse_left_pressed as u32, mouse_left_clicked: self.mouse_left_clicked as u32, shader_to_show: self.shader_to_show, - grid: self.grid_mode as u32, + grid_mode: self.grid_mode as u32, }; self.mouse_left_clicked = false; rpass.set_pipeline(self.render_pipeline.as_ref().unwrap()); From 994e8dbb50f8c0d2cbd5ed3123e670ee1f8fd1e7 Mon Sep 17 00:00:00 2001 From: raldone01 Date: Sun, 8 Jun 2025 03:55:12 +0200 Subject: [PATCH 5/7] Use shader trait. --- shaders/src/shader_prelude.rs | 5 ++ shaders/src/shaders/a_lot_of_spheres.rs | 58 ++++++++++++----------- shaders/src/shaders/miracle_snowflakes.rs | 42 ++++++---------- shaders/src/shaders/mod.rs | 15 +++--- 4 files changed, 58 insertions(+), 62 deletions(-) diff --git a/shaders/src/shader_prelude.rs b/shaders/src/shader_prelude.rs index 4cffe19..e5b086c 100644 --- a/shaders/src/shader_prelude.rs +++ b/shaders/src/shader_prelude.rs @@ -61,6 +61,11 @@ pub struct ShaderDefinition { pub name: &'static str, } +pub trait Shader { + const SHADER_DEFINITION: &'static ShaderDefinition; + fn shader_fn(shader_input: &ShaderInput, shader_output: &mut ShaderResult); +} + #[inline(always)] #[must_use] pub fn saturate_vec3(a: Vec3) -> Vec3 { diff --git a/shaders/src/shaders/a_lot_of_spheres.rs b/shaders/src/shaders/a_lot_of_spheres.rs index 8d71c16..6d25de3 100644 --- a/shaders/src/shaders/a_lot_of_spheres.rs +++ b/shaders/src/shaders/a_lot_of_spheres.rs @@ -13,22 +13,26 @@ use crate::shader_prelude::*; -pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { +const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { name: "A Lot of Spheres", }; -pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { - let color = &mut render_result.color; - let &ShaderInput { - resolution, - time, - frag_coord, - .. - } = render_instruction; - Inputs { resolution, time }.main_image(color, frag_coord); +impl Shader for ShaderALotOfSpheres { + const SHADER_DEFINITION: &'static ShaderDefinition = &SHADER_DEFINITION; + + fn shader_fn(shader_input: &ShaderInput, shader_output: &mut ShaderResult) { + let frag_color = &mut shader_output.color; + let &ShaderInput { + resolution, + time, + frag_coord, + .. + } = shader_input; + Self { resolution, time }.main_image(frag_color, frag_coord); + } } -struct Inputs { +pub struct ShaderALotOfSpheres { resolution: Vec3, time: f32, } @@ -110,7 +114,7 @@ fn get_sphere_offset(grid: Vec2, center: &mut Vec2) { *center = (hash2_vec(grid + vec2(43.12, 1.23)) - Vec2::splat(0.5)) * (GRIDSIZESMALL); } -impl Inputs { +impl ShaderALotOfSpheres { fn get_moving_sphere_position(&self, grid: Vec2, sphere_offset: Vec2, center: &mut Vec3) { // falling? let s: f32 = 0.1 + hash(grid.x * 1.23114 + 5.342 + 74.324231 * grid.y); @@ -130,7 +134,7 @@ fn get_sphere_color(grid: Vec2) -> Vec3 { hash3_vec(grid + vec2(43.12 * grid.y, 12.23 * grid.x)).normalize() } -impl Inputs { +impl ShaderALotOfSpheres { fn trace( &self, ro: Vec3, @@ -256,18 +260,18 @@ impl Inputs { } fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { - let q: Vec2 = frag_coord / self.resolution.xy(); - let mut p: Vec2 = Vec2::splat(-1.0) + 2.0 * q; + let q = frag_coord / self.resolution.xy(); + let mut p = Vec2::splat(-1.0) + 2.0 * q; p.x *= self.resolution.x / self.resolution.y; // camera - let ce: Vec3 = vec3( + let ce = vec3( (0.232 * self.time).cos() * 10.0, 6. + 3.0 * (0.3 * self.time).cos(), GRIDSIZE * (self.time / SPEED), ); - let ro: Vec3 = ce; - let ta: Vec3 = ro + let ro = ce; + let ta = ro + vec3( -(0.232 * self.time).sin() * 10., -2.0 + (0.23 * self.time).cos(), @@ -276,18 +280,18 @@ impl Inputs { let roll: f32 = -0.15 * (0.5 * self.time).sin(); // camera tx - let cw: Vec3 = (ta - ro).normalize(); - let cp: Vec3 = vec3(roll.sin(), roll.cos(), 0.0); - let cu: Vec3 = (cw.cross(cp)).normalize(); - let cv: Vec3 = (cu.cross(cw)).normalize(); - let mut rd: Vec3 = (p.x * cu + p.y * cv + 1.5 * cw).normalize(); + let cw = (ta - ro).normalize(); + let cp = vec3(roll.sin(), roll.cos(), 0.0); + let cu = (cw.cross(cp)).normalize(); + let cv = (cu.cross(cw)).normalize(); + let mut rd = (p.x * cu + p.y * cv + 1.5 * cw).normalize(); // raytrace let mut material: i32 = 0; - let mut normal: Vec3 = Vec3::ZERO; - let mut intersection: Vec3 = Vec3::ZERO; + let mut normal = Vec3::ZERO; + let mut intersection = Vec3::ZERO; let mut dist: f32 = 0.0; - let mut col: Vec3 = self.trace( + let mut col = self.trace( ro, rd, &mut intersection, @@ -296,7 +300,7 @@ impl Inputs { &mut material, ); if material > 0 && REFLECTION { - let ro: Vec3 = intersection + EPSILON * normal; + let ro = intersection + EPSILON * normal; rd = rd.reflect(normal); col += 0.05 * self.trace( diff --git a/shaders/src/shaders/miracle_snowflakes.rs b/shaders/src/shaders/miracle_snowflakes.rs index 4a03065..3145153 100644 --- a/shaders/src/shaders/miracle_snowflakes.rs +++ b/shaders/src/shaders/miracle_snowflakes.rs @@ -12,31 +12,18 @@ use crate::shader_prelude::*; -pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { +const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { name: "Playing Marble", }; -pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { - let color = &mut render_result.color; - let &ShaderInput { - resolution, - time, - frag_coord, - mouse, - .. - } = render_instruction; - State::new(Inputs { - resolution, - time, - mouse, - }) - .main_image(color, frag_coord); -} +impl Shader for ShaderMiracleSnowflakes<'_> { + const SHADER_DEFINITION: &'static ShaderDefinition = &SHADER_DEFINITION; -struct Inputs { - resolution: Vec3, - time: f32, - mouse: Vec4, + fn shader_fn(shader_input: &ShaderInput, shader_output: &mut ShaderResult) { + let frag_color = &mut shader_output.color; + let &ShaderInput { frag_coord, .. } = shader_input; + ShaderMiracleSnowflakes::new(&shader_input).main_image(frag_color, frag_coord); + } } const ITERATIONS: u32 = 15; @@ -46,8 +33,8 @@ const LAYERSBLOB: i32 = 20; const STEP: f32 = 1.0; const FAR: f32 = 10000.0; -struct State { - inputs: Inputs, +pub struct ShaderMiracleSnowflakes<'a> { + inputs: &'a ShaderInput, radius: f32, zoom: f32, @@ -63,9 +50,9 @@ struct State { mxc: f32, } -impl State { +impl<'a> ShaderMiracleSnowflakes<'a> { #[must_use] - fn new(inputs: Inputs) -> Self { + fn new(inputs: &'a ShaderInput) -> Self { Self { inputs, radius: 0.25, // radius of Snowflakes. maximum for this demo 0.25. @@ -132,7 +119,7 @@ fn noise3_2(x: Vec3) -> Vec2 { vec2(noise3(x), noise3(x + Vec3::splat(100.0))) } -impl State { +impl<'a> ShaderMiracleSnowflakes<'a> { fn map(&self, rad: Vec2) -> f32 { let a: f32; if self.res < 0.0015 { @@ -148,8 +135,7 @@ impl State { } a - 0.5 } -} -impl State { + fn dist_obj(&self, pos: Vec3, mut ray: Vec3, mut r: f32, seed: Vec2) -> Vec3 { let rq: f32 = r * r; let mut dist: Vec3 = ray * FAR; diff --git a/shaders/src/shaders/mod.rs b/shaders/src/shaders/mod.rs index 10917ce..632b520 100644 --- a/shaders/src/shaders/mod.rs +++ b/shaders/src/shaders/mod.rs @@ -41,25 +41,26 @@ macro_rules! match_index { } macro_rules! render_shader_macro { - ($($shader_name:ident),* $(,)?) => { + ($($shader_name:path),* $(,)?) => { #[inline(always)] pub fn render_shader(shader_index: u32, shader_input: &ShaderInput, shader_output: &mut ShaderResult) { match_index!(shader_index; $( - $shader_name::shader_fn(shader_input, shader_output), + <$shader_name>::shader_fn(shader_input, shader_output), )*) } - pub const SHADER_DEFINITIONS: &[ShaderDefinition] = &[ + pub const SHADER_DEFINITIONS: &[&ShaderDefinition] = &[ $( - $shader_name::SHADER_DEFINITION, + <$shader_name>::SHADER_DEFINITION, )* ]; }; } render_shader_macro!( - miracle_snowflakes, - morphing, + a_lot_of_spheres::ShaderALotOfSpheres, + miracle_snowflakes::ShaderMiracleSnowflakes<'_>, + /*morphing, voxel_pac_man, luminescence, seascape, @@ -85,5 +86,5 @@ render_shader_macro!( geodesic_tiling, flappy_bird, tokyo, - on_off_spikes, + on_off_spikes,*/ ); From ebbce16f78d067837faf9eaadca5d25d083af154 Mon Sep 17 00:00:00 2001 From: raldone01 Date: Tue, 10 Jun 2025 09:50:28 +0200 Subject: [PATCH 6/7] Semantic improvements. --- Cargo.lock | 40 ++++++++++++++------ Cargo.toml | 5 ++- shaders/Cargo.toml | 2 +- shaders/src/lib.rs | 75 ++++++++++++++++++++------------------ shaders/src/shared_data.rs | 16 +++++--- src/main.rs | 20 +++++++--- 6 files changed, 99 insertions(+), 59 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 84f0bbf..072e608 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -255,7 +255,15 @@ version = "1.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c" dependencies = [ - "bytemuck_derive", + "bytemuck_derive 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bytemuck" +version = "1.23.1" +source = "git+https://github.com/Lokathor/bytemuck.git?rev=0e11472150c3b63cbae3b445230fe074405bd2d2#0e11472150c3b63cbae3b445230fe074405bd2d2" +dependencies = [ + "bytemuck_derive 1.9.3 (git+https://github.com/Lokathor/bytemuck.git?rev=0e11472150c3b63cbae3b445230fe074405bd2d2)", ] [[package]] @@ -269,6 +277,16 @@ dependencies = [ "syn", ] +[[package]] +name = "bytemuck_derive" +version = "1.9.3" +source = "git+https://github.com/Lokathor/bytemuck.git?rev=0e11472150c3b63cbae3b445230fe074405bd2d2#0e11472150c3b63cbae3b445230fe074405bd2d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "bytes" version = "1.10.1" @@ -1692,7 +1710,7 @@ source = "git+https://github.com/Rust-GPU/rust-gpu?rev=0b37696e9f5edde8fa0c1363a dependencies = [ "ahash", "ar", - "bytemuck", + "bytemuck 1.23.0", "either", "indexmap", "itertools", @@ -1869,7 +1887,7 @@ dependencies = [ name = "shadertoys-shaders" version = "0.0.0" dependencies = [ - "bytemuck", + "bytemuck 1.23.1", "spirv-std", ] @@ -1877,7 +1895,7 @@ dependencies = [ name = "shadertoys-wgpu" version = "0.0.0" dependencies = [ - "bytemuck", + "bytemuck 1.23.1", "env_logger", "futures", "ouroboros", @@ -1971,7 +1989,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2d5968bd2a36466468aac637b355776f080edfb0c6f769b2b99b9708260c42a" dependencies = [ "arrayvec", - "bytemuck", + "bytemuck 1.23.0", "derive_more", "elsa", "indexmap", @@ -2198,7 +2216,7 @@ checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab" dependencies = [ "arrayref", "arrayvec", - "bytemuck", + "bytemuck 1.23.0", "cfg-if", "log", "tiny-skia-path", @@ -2211,7 +2229,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93" dependencies = [ "arrayref", - "bytemuck", + "bytemuck 1.23.0", "strict-num", ] @@ -2642,7 +2660,7 @@ dependencies = [ "bit-set", "bit-vec", "bitflags 2.9.0", - "bytemuck", + "bytemuck 1.23.0", "cfg_aliases", "document-features", "hashbrown 0.15.2", @@ -2703,7 +2721,7 @@ dependencies = [ "bit-set", "bitflags 2.9.0", "block", - "bytemuck", + "bytemuck 1.23.0", "cfg-if", "cfg_aliases", "core-graphics-types", @@ -2745,7 +2763,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2aa49460c2a8ee8edba3fca54325540d904dd85b2e086ada762767e17d06e8bc" dependencies = [ "bitflags 2.9.0", - "bytemuck", + "bytemuck 1.23.0", "js-sys", "log", "thiserror 2.0.12", @@ -3062,7 +3080,7 @@ dependencies = [ "atomic-waker", "bitflags 2.9.0", "block2", - "bytemuck", + "bytemuck 1.23.0", "calloop", "cfg_aliases", "concurrent-queue", diff --git a/Cargo.toml b/Cargo.toml index 26afd70..ed64939 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ futures = { version = "0.3", default-features = false, features = [ ] } wgpu = { version = "25.0.0", features = ["spirv", "vulkan-portability"] } winit = { git = "https://github.com/rust-windowing/winit.git", rev = "cdbdd974fbf79b82b3fb1a4bc84ed717312a3bd2" } -bytemuck = "1.23.0" +bytemuck.workspace = true env_logger = "0.11.6" ouroboros = "0.18.5" @@ -31,6 +31,9 @@ members = ["shaders"] [workspace.dependencies] spirv-builder = { git = "https://github.com/Rust-GPU/rust-gpu", rev = "0b37696e9f5edde8fa0c1363a88e6c8cb8e6ff68", default-features = false } spirv-std = { git = "https://github.com/Rust-GPU/rust-gpu", rev = "0b37696e9f5edde8fa0c1363a88e6c8cb8e6ff68" } +bytemuck = { git = "https://github.com/Lokathor/bytemuck.git", rev = "0e11472150c3b63cbae3b445230fe074405bd2d2", features = [ + "derive", +] } # Compile build-dependencies in release mode with # the same settings as regular dependencies. diff --git a/shaders/Cargo.toml b/shaders/Cargo.toml index 0db5533..8bdac58 100644 --- a/shaders/Cargo.toml +++ b/shaders/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["dylib"] [dependencies] spirv-std.workspace = true -bytemuck = { version = "1.23.0", features = ["derive"] } +bytemuck.workspace = true [lints] workspace = true diff --git a/shaders/src/lib.rs b/shaders/src/lib.rs index cd306b4..e0fb454 100644 --- a/shaders/src/lib.rs +++ b/shaders/src/lib.rs @@ -2,6 +2,8 @@ pub mod shader_prelude; use shader_prelude::*; + +use crate::shared_data::DisplayMode; pub mod shaders; pub mod shared_data; @@ -75,41 +77,44 @@ pub fn fs(constants: &ShaderConstants, mut frag_coord: Vec2) -> Vec4 { let shader_input: ShaderInput; let shader_output = &mut ShaderResult { color: Vec4::ZERO }; - if constants.grid_mode == 0 { - shader_input = ShaderInput { - resolution, - time, - frag_coord, - mouse, - }; - shader_index = constants.shader_to_show as usize; - } else { - // Render all shaders in a grid layout - // ignore shader_to_show - let (rows, cols) = optimal_grid(shader_count, vec2(resolution.x, resolution.y)); - - let cell_width = resolution.x / cols as f32; - let cell_height = resolution.y / rows as f32; - - #[expect(clippy::cast_sign_loss)] - let col = (frag_coord.x / cell_width).floor() as usize; - #[expect(clippy::cast_sign_loss)] - let row = (frag_coord.y / cell_height).floor() as usize; - shader_index = row + col * rows; - - let cell_resolution = vec3(cell_width, cell_height, 0.0); - let cell_frag_coord = vec2( - (col as f32).mul_add(-cell_width, frag_coord.x), - (row as f32).mul_add(-cell_height, frag_coord.y), - ); - let cell_mouse = mouse / vec4(cols as f32, rows as f32, cols as f32, rows as f32); - - shader_input = ShaderInput { - resolution: cell_resolution, - time, - frag_coord: cell_frag_coord, - mouse: cell_mouse, - }; + match constants.shader_display_mode { + DisplayMode::Grid { _padding: _ } => { + // Render all shaders in a grid layout + // ignore shader_to_show + let (rows, cols) = optimal_grid(shader_count, vec2(resolution.x, resolution.y)); + + let cell_width = resolution.x / cols as f32; + let cell_height = resolution.y / rows as f32; + + #[expect(clippy::cast_sign_loss)] + let col = (frag_coord.x / cell_width).floor() as usize; + #[expect(clippy::cast_sign_loss)] + let row = (frag_coord.y / cell_height).floor() as usize; + shader_index = row + col * rows; + + let cell_resolution = vec3(cell_width, cell_height, 0.0); + let cell_frag_coord = vec2( + (col as f32).mul_add(-cell_width, frag_coord.x), + (row as f32).mul_add(-cell_height, frag_coord.y), + ); + let cell_mouse = mouse / vec4(cols as f32, rows as f32, cols as f32, rows as f32); + + shader_input = ShaderInput { + resolution: cell_resolution, + time, + frag_coord: cell_frag_coord, + mouse: cell_mouse, + }; + }, + DisplayMode::SingleShader(index) => { + shader_input = ShaderInput { + resolution, + time, + frag_coord, + mouse, + }; + shader_index = index as usize; + }, } if shader_index < shader_count { diff --git a/shaders/src/shared_data.rs b/shaders/src/shared_data.rs index 8a9fa75..ceead30 100644 --- a/shaders/src/shared_data.rs +++ b/shaders/src/shared_data.rs @@ -1,17 +1,21 @@ -use bytemuck::{Pod, Zeroable}; +use bytemuck::{NoUninit, Zeroable}; + +#[repr(C, u32)] +#[derive(Copy, Clone, NoUninit, Zeroable)] +pub enum DisplayMode { + Grid { _padding: u32 }, + SingleShader(u32), +} #[repr(C)] -#[derive(Copy, Clone, Pod, Zeroable)] -#[allow(unused_attributes)] +#[derive(Copy, Clone, NoUninit, Zeroable)] pub struct ShaderConstants { pub width: u32, pub height: u32, pub time: f32, // UI state - /// Boolean value indicating whether all shaders are rendered in a grid layout. - pub grid_mode: u32, - pub shader_to_show: u32, + pub shader_display_mode: DisplayMode, // Mouse state. pub cursor_x: f32, diff --git a/src/main.rs b/src/main.rs index 291c980..ec2c96b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,9 @@ use futures::executor::block_on; use ouroboros::self_referencing; -use shadertoys_shaders::{shaders::SHADER_DEFINITIONS, shared_data::ShaderConstants}; +use shadertoys_shaders::{ + shaders::SHADER_DEFINITIONS, + shared_data::{self, ShaderConstants}, +}; use std::{error::Error, time::Instant}; use wgpu::{self, include_spirv, include_spirv_raw, InstanceDescriptor}; use winit::{ @@ -56,6 +59,8 @@ impl Default for ShaderToyApp { shader_module: None, close_requested: false, start: Instant::now(), + grid_mode: false, + shader_to_show: 0, cursor_x: 0.0, cursor_y: 0.0, drag_start_x: 0.0, @@ -64,8 +69,6 @@ impl Default for ShaderToyApp { drag_end_y: 0.0, mouse_left_pressed: false, mouse_left_clicked: false, - shader_to_show: 0, - grid_mode: false, } } } @@ -193,6 +196,14 @@ impl ShaderToyApp { Ok(()) } + fn display_mode(&self) -> shared_data::DisplayMode { + if self.grid_mode { + shared_data::DisplayMode::Grid { _padding: 0 } + } else { + shared_data::DisplayMode::SingleShader(self.shader_to_show) + } + } + fn render(&mut self) { let window_surface = match &self.window_surface { Some(ws) => ws, @@ -243,6 +254,7 @@ impl ShaderToyApp { width: current_size.width, height: current_size.height, time: self.start.elapsed().as_secs_f32(), + shader_display_mode: self.display_mode(), cursor_x: self.cursor_x, cursor_y: self.cursor_y, drag_start_x: self.drag_start_x, @@ -251,8 +263,6 @@ impl ShaderToyApp { drag_end_y: self.drag_end_y, mouse_left_pressed: self.mouse_left_pressed as u32, mouse_left_clicked: self.mouse_left_clicked as u32, - shader_to_show: self.shader_to_show, - grid_mode: self.grid_mode as u32, }; self.mouse_left_clicked = false; rpass.set_pipeline(self.render_pipeline.as_ref().unwrap()); From 569d75c93f963898e288dc2c2decc7980caa39bc Mon Sep 17 00:00:00 2001 From: raldone01 Date: Tue, 10 Jun 2025 10:21:00 +0200 Subject: [PATCH 7/7] Add another shader. --- shaders/src/shaders/miracle_snowflakes.rs | 140 +++++++++--------- shaders/src/shaders/mod.rs | 6 +- .../{morphing.rs => morphing_teapot.rs} | 39 ++--- 3 files changed, 86 insertions(+), 99 deletions(-) rename shaders/src/shaders/{morphing.rs => morphing_teapot.rs} (94%) diff --git a/shaders/src/shaders/miracle_snowflakes.rs b/shaders/src/shaders/miracle_snowflakes.rs index 3145153..eab9d09 100644 --- a/shaders/src/shaders/miracle_snowflakes.rs +++ b/shaders/src/shaders/miracle_snowflakes.rs @@ -78,24 +78,24 @@ fn hash4(n: Vec4) -> Vec4 { (n.sin() * 1399763.5453123).fract_gl() } fn noise2(x: Vec2) -> f32 { - let p: Vec2 = x.floor(); - let mut f: Vec2 = x.fract_gl(); + let p = x.floor(); + let mut f = x.fract_gl(); f = f * f * (Vec2::splat(3.0) - 2.0 * f); - let n: f32 = p.x + p.y * 157.0; + let n = p.x + p.y * 157.0; let nc0 = NC0; let nc1 = NC1; - let h: Vec4 = hash4(Vec4::splat(n) + vec4(nc0.x, nc0.y, nc1.x, nc1.y)); - let s1: Vec2 = mix(h.xy(), h.zw(), f.xx()); + let h = hash4(Vec4::splat(n) + vec4(nc0.x, nc0.y, nc1.x, nc1.y)); + let s1 = mix(h.xy(), h.zw(), f.xx()); mix(s1.x, s1.y, f.y) } fn noise222(x: Vec2, y: Vec2, z: Vec2) -> f32 { - let lx: Vec4 = vec4(x.x * y.x, x.y * y.x, x.x * y.y, x.y * y.y); - let p: Vec4 = lx.floor(); - let mut f: Vec4 = lx.fract_gl(); + let lx = vec4(x.x * y.x, x.y * y.x, x.x * y.y, x.y * y.y); + let p = lx.floor(); + let mut f = lx.fract_gl(); f = f * f * (Vec4::splat(3.0) - 2.0 * f); - let n: Vec2 = p.xz() + p.yw() * 157.0; - let h: Vec4 = mix( + let n = p.xz() + p.yw() * 157.0; + let h = mix( hash4(n.xxyy() + NC0.xyxy()), hash4(n.xxyy() + NC1.xyxy()), f.xxzz(), @@ -104,11 +104,11 @@ fn noise222(x: Vec2, y: Vec2, z: Vec2) -> f32 { } fn noise3(x: Vec3) -> f32 { - let p: Vec3 = x.floor(); - let mut f: Vec3 = x.fract_gl(); + let p = x.floor(); + let mut f = x.fract_gl(); f = f * f * (Vec3::splat(3.0) - 2.0 * f); - let n: f32 = p.x + p.yz().dot(vec2(157.0, 113.0)); - let s1: Vec4 = mix( + let n = p.x + p.yz().dot(vec2(157.0, 113.0)); + let s1 = mix( hash4(Vec4::splat(n) + NC0), hash4(Vec4::splat(n) + NC1), f.xxxx(), @@ -121,7 +121,7 @@ fn noise3_2(x: Vec3) -> Vec2 { impl<'a> ShaderMiracleSnowflakes<'a> { fn map(&self, rad: Vec2) -> f32 { - let a: f32; + let a; if self.res < 0.0015 { //a = noise2(rad.xy*20.6)*0.9+noise2(rad.xy*100.6)*0.1; a = noise222(rad, vec2(20.6, 100.6), vec2(0.9, 0.1)); @@ -137,35 +137,35 @@ impl<'a> ShaderMiracleSnowflakes<'a> { } fn dist_obj(&self, pos: Vec3, mut ray: Vec3, mut r: f32, seed: Vec2) -> Vec3 { - let rq: f32 = r * r; - let mut dist: Vec3 = ray * FAR; + let rq = r * r; + let mut dist = ray * FAR; - let norm: Vec3 = vec3(0.0, 0.0, 1.0); - let invn: f32 = 1.0 / norm.dot(ray); - let mut depthi: f32 = DEPTH; + let norm = vec3(0.0, 0.0, 1.0); + let invn = 1.0 / norm.dot(ray); + let mut depthi = DEPTH; if invn < 0.0 { depthi = -depthi; } - let mut ds: f32 = 2.0 * depthi * invn; - let mut r1: Vec3 = ray * (norm.dot(pos) - depthi) * invn - pos; - let op1: Vec3 = r1 + norm * depthi; - let len1: f32 = op1.dot(op1); - let mut r2: Vec3 = r1 + ray * ds; - let op2: Vec3 = r2 - norm * depthi; - let len2: f32 = op2.dot(op2); - let n: Vec3 = ray.cross(norm).normalize(); - let mind: f32 = pos.dot(n); - let n2: Vec3 = ray.cross(n); - let d: f32 = n2.dot(pos) / n2.dot(norm); - let invd: f32 = 0.2 / DEPTH; + let mut ds = 2.0 * depthi * invn; + let mut r1 = ray * (norm.dot(pos) - depthi) * invn - pos; + let op1 = r1 + norm * depthi; + let len1 = op1.dot(op1); + let mut r2 = r1 + ray * ds; + let op2 = r2 - norm * depthi; + let len2 = op2.dot(op2); + let n = ray.cross(norm).normalize(); + let mind = pos.dot(n); + let n2 = ray.cross(n); + let d = n2.dot(pos) / n2.dot(norm); + let invd = 0.2 / DEPTH; if (len1 < rq || len2 < rq) || (mind.abs() < r && d <= DEPTH && d >= -DEPTH) { - let _r3: Vec3 = r2; - let len: f32 = len1; + let _r3 = r2; + let len = len1; if len >= rq { - let n3: Vec3 = norm.cross(n); - let a: f32 = 1.0 / (rq - mind * mind).sqrt() * ray.dot(n3).abs(); - let dt: Vec3 = ray / a; + let n3 = norm.cross(n); + let a = 1.0 / (rq - mind * mind).sqrt() * ray.dot(n3).abs(); + let dt = ray / a; r1 = -d * norm - mind * n - dt; if len2 >= rq { r2 = -d * norm - mind * n + dt; @@ -177,21 +177,21 @@ impl<'a> ShaderMiracleSnowflakes<'a> { if ds > 0.01 { ds = 0.01; } - let ir: f32 = 0.35 / r; + let ir = 0.35 / r; r *= self.zoom; ray = ray * ds * 5.0; for m in 0..ITERATIONS { if m as f32 >= self.iteratorc { break; } - let mut l: f32 = r1.xy().length(); //r1.xy().dot(r1.xy()).sqrt(); - let mut c3: Vec2 = (r1.xy() / l).abs(); + let mut l = r1.xy().length(); //r1.xy().dot(r1.xy()).sqrt(); + let mut c3 = (r1.xy() / l).abs(); if c3.x > 0.5 { c3 = (c3 * 0.5 + vec2(-c3.y, c3.x) * 0.86602540).abs(); } - let g: f32 = l + c3.x * c3.x; //*1.047197551; + let g = l + c3.x * c3.x; //*1.047197551; l *= self.zoom; - let mut h: f32 = l - r - 0.1; + let mut h = l - r - 0.1; l = l.powf(self.powr) + 0.1; h = h.max(mix(self.map(c3 * l + seed), 1.0, (r1.z * invd).abs())) + g * ir - 0.245; //0.7*0.35=0.245 //*0.911890636 if (h < self.res * 20.0) || r1.z.abs() > DEPTH + 0.01 { @@ -215,20 +215,20 @@ impl<'a> ShaderMiracleSnowflakes<'a> { ray1: Vec3, ray2: Vec3, ) -> Vec4 { - let d: Vec3 = self.dist_obj(pos, ray, self.radius, self.seed); - let n1: Vec3 = self.dist_obj(pos, ray1, self.radius, self.seed); - let n2: Vec3 = self.dist_obj(pos, ray2, self.radius, self.seed); + let d = self.dist_obj(pos, ray, self.radius, self.seed); + let n1 = self.dist_obj(pos, ray1, self.radius, self.seed); + let n2 = self.dist_obj(pos, ray2, self.radius, self.seed); - let lq: Vec3 = vec3(d.dot(d), n1.dot(n1), n2.dot(n2)); + let lq = vec3(d.dot(d), n1.dot(n1), n2.dot(n2)); if lq.x < FAR || lq.y < FAR || lq.z < FAR { - let n: Vec3 = (n1 - d).cross(n2 - d).normalize(); + let n = (n1 - d).cross(n2 - d).normalize(); if lq.x < FAR && lq.y < FAR && lq.z < FAR { self.nray = n; //(self.nray+n).normalize(); //self.nray1 = (ray1+n).normalize(); //self.nray2 = (ray2+n).normalize(); } - let da: f32 = n.dot(self.light).abs().powf(3.0); - let mut cf: Vec3 = mix(vec3(0.0, 0.4, 1.0), color.xyz() * 10.0, n.dot(ray).abs()); + let da = n.dot(self.light).abs().powf(3.0); + let mut cf = mix(vec3(0.0, 0.4, 1.0), color.xyz() * 10.0, n.dot(ray).abs()); cf = mix(cf, Vec3::splat(2.0), da); color = (mix( color.xyz(), @@ -242,16 +242,16 @@ impl<'a> ShaderMiracleSnowflakes<'a> { } fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { - let time: f32 = self.inputs.time * 0.2; //*0.1; + let time = self.inputs.time * 0.2; //*0.1; self.res = 1.0 / self.inputs.resolution.y; - let p: Vec2 = (-self.inputs.resolution.xy() + 2.0 * frag_coord) * self.res; + let p = (-self.inputs.resolution.xy() + 2.0 * frag_coord) * self.res; - let mut rotate: Vec3; - let mut mr: Mat3; - let mut ray: Vec3; - let mut ray1: Vec3; - let mut ray2: Vec3; - let mut pos: Vec3 = vec3(0.0, 0.0, 1.0); + let mut rotate; + let mut mr; + let mut ray; + let mut ray1; + let mut ray2; + let mut pos = vec3(0.0, 0.0, 1.0); *frag_color = vec4(0.0, 0.0, 0.0, 0.0); self.nray = Vec3::ZERO; @@ -261,27 +261,27 @@ impl<'a> ShaderMiracleSnowflakes<'a> { let mut refcolor: Vec4 = Vec4::ZERO; self.iteratorc = ITERATIONS as f32 - LAYERS; - let mut addrot: Vec2 = Vec2::ZERO; + let mut addrot = Vec2::ZERO; if self.inputs.mouse.z > 0.0 { addrot = (self.inputs.mouse.xy() - self.inputs.resolution.xy() * 0.5) * self.res; } - let mut mxcl: f32 = 1.0; - let mut addpos: Vec3 = Vec3::ZERO; + let mut mxcl = 1.0; + let mut addpos = Vec3::ZERO; pos.z = 1.0; self.mxc = 1.0; self.radius = 0.25; let mzd: f32 = (self.zoom - 0.1) / LAYERS; for i in 0..LAYERSBLOB { - let p2: Vec2 = p - Vec2::splat(0.25) + Vec2::splat(0.1 * i as f32); + let p2 = p - Vec2::splat(0.25) + Vec2::splat(0.1 * i as f32); ray = p2.extend(2.0) - self.nray * 2.0; //ray = self.nray;//*0.6; ray1 = (ray + vec3(0.0, self.res * 2.0, 0.0)).normalize(); ray2 = (ray + vec3(self.res * 2.0, 0.0, 0.0)).normalize(); ray = ray.normalize(); - let mut sb: Vec2 = ray.xy() * pos.length() / pos.normalize().dot(ray) + vec2(0.0, time); + let mut sb = ray.xy() * pos.length() / pos.normalize().dot(ray) + vec2(0.0, time); self.seed = (sb + vec2(0.0, pos.z)).floor() + Vec2::splat(pos.z); - let mut seedn: Vec3 = self.seed.extend(pos.z); + let mut seedn = self.seed.extend(pos.z); sb = sb.floor(); if noise3(seedn) > 0.2 && i < LAYERS as i32 { self.powr = noise3(seedn * 10.0) * 1.9 + 0.1; @@ -290,8 +290,8 @@ impl<'a> ShaderMiracleSnowflakes<'a> { rotate.z = (0.5 - noise3(seedn + vec3(10.0, 3.0, 1.0))) * time * 5.0; seedn.z += time * 0.5; addpos = (sb + vec2(0.25, 0.25 - time) + noise3_2(seedn) * 0.5).extend(addpos.z); - let sins: Vec3 = rotate.sin(); - let coss: Vec3 = rotate.cos(); + let sins = rotate.sin(); + let coss = rotate.cos(); mr = Mat3::from_cols( vec3(coss.x, 0.0, sins.x), vec3(0.0, 1.0, 0.0), @@ -309,14 +309,14 @@ impl<'a> ShaderMiracleSnowflakes<'a> { ) * mr; self.light = mr.transpose() * vec3(1.0, 0.0, 1.0).normalize(); - // let cc: Vec4 = self.filter_flake( + // let cc = self.filter_flake( // *frag_color, // mr.transpose() * (pos + addpos), // (mr.transpose() * ray + self.nray * 0.1).normalize(), // (mr.transpose() * ray1 + self.nray * 0.1).normalize(), // (mr.transpose() * ray2 + self.nray * 0.1).normalize(), // ); - let mut cc: Vec4 = self.filter_flake( + let mut cc = self.filter_flake( *frag_color, mr.transpose() * (pos + addpos), mr.transpose() * ray, @@ -343,10 +343,10 @@ impl<'a> ShaderMiracleSnowflakes<'a> { } seedn = sb.extend(pos.z) + vec3(0.5, 1000.0, 300.0); if noise3(seedn * 10.0) > 0.4 { - let raf: f32 = 0.3 + noise3(seedn * 100.0); + let raf = 0.3 + noise3(seedn * 100.0); addpos = (sb + vec2(0.2, 0.2 - time) + noise3_2(seedn * 100.0) * 0.6).extend(addpos.z); - let mut l: f32 = (ray * ray.dot(pos + addpos) - pos - addpos).length(); + let mut l = (ray * ray.dot(pos + addpos) - pos - addpos).length(); l = (1.0 - l * 10.0 * raf).max(0.0); *frag_color += vec4(1.0, 1.2, 3.0, 1.0) * l.powf(5.0) * ((0.6 + raf).powf(2.0) - 0.6) * mxcl; @@ -358,7 +358,7 @@ impl<'a> ShaderMiracleSnowflakes<'a> { self.zoom -= mzd; } - let cr: Vec3 = mix(Vec3::ZERO, vec3(0.0, 0.0, 0.4), (-0.55 + p.y) * 2.0); + let cr = mix(Vec3::ZERO, vec3(0.0, 0.0, 0.4), (-0.55 + p.y) * 2.0); *frag_color = (frag_color.xyz() + mix( (cr - frag_color.xyz()) * 0.1, diff --git a/shaders/src/shaders/mod.rs b/shaders/src/shaders/mod.rs index 632b520..d863908 100644 --- a/shaders/src/shaders/mod.rs +++ b/shaders/src/shaders/mod.rs @@ -14,7 +14,7 @@ mod heart; mod luminescence; mod mandelbrot_smooth; mod miracle_snowflakes; -mod morphing; +mod morphing_teapot; mod moving_square; mod on_off_spikes; mod phantom_star; @@ -60,8 +60,8 @@ macro_rules! render_shader_macro { render_shader_macro!( a_lot_of_spheres::ShaderALotOfSpheres, miracle_snowflakes::ShaderMiracleSnowflakes<'_>, - /*morphing, - voxel_pac_man, + morphing_teapot::ShaderMorphingTeapot<'_>, + /*voxel_pac_man, luminescence, seascape, two_tweets, diff --git a/shaders/src/shaders/morphing.rs b/shaders/src/shaders/morphing_teapot.rs similarity index 94% rename from shaders/src/shaders/morphing.rs rename to shaders/src/shaders/morphing_teapot.rs index 2ce40cd..d36edac 100644 --- a/shaders/src/shaders/morphing.rs +++ b/shaders/src/shaders/morphing_teapot.rs @@ -12,31 +12,18 @@ pub const SHADER_DEFINITION: ShaderDefinition = ShaderDefinition { name: "Morphing Teapot", }; -pub fn shader_fn(render_instruction: &ShaderInput, render_result: &mut ShaderResult) { - let color = &mut render_result.color; - let &ShaderInput { - resolution, - time, - frag_coord, - mouse, - .. - } = render_instruction; - State::new(Inputs { - resolution, - time, - mouse, - }) - .main_image(color, frag_coord); -} +impl Shader for ShaderMorphingTeapot<'_> { + const SHADER_DEFINITION: &'static ShaderDefinition = &SHADER_DEFINITION; -struct Inputs { - resolution: Vec3, - time: f32, - mouse: Vec4, + fn shader_fn(shader_input: &ShaderInput, shader_output: &mut ShaderResult) { + let frag_color = &mut shader_output.color; + let &ShaderInput { frag_coord, .. } = shader_input; + ShaderMorphingTeapot::new(&shader_input).main_image(frag_color, frag_coord); + } } -struct State { - inputs: Inputs, +pub struct ShaderMorphingTeapot<'a> { + inputs: &'a ShaderInput, a: [Vec2; 15], t1: [Vec2; 5], @@ -48,9 +35,9 @@ struct State { mat2_rot: Mat2, } -impl State { +impl<'a> ShaderMorphingTeapot<'a> { #[must_use] - fn new(inputs: Inputs) -> Self { + fn new(inputs: &'a ShaderInput) -> Self { Self { inputs, @@ -117,7 +104,7 @@ fn smin(a: f32, b: f32, k: f32) -> f32 { mix(b, a, h) - k * h * (1. - h) } -impl State { +impl<'a> ShaderMorphingTeapot<'a> { // Distance to scene fn m(&self, mut p: Vec3) -> f32 { // Distance to Teapot --------------------------------------------------- @@ -187,7 +174,7 @@ fn hsv2rgb_smooth(x: f32, y: f32, z: f32) -> Vec3 { z * mix(Vec3::ONE, rgb, y) } -impl State { +impl<'a> ShaderMorphingTeapot<'a> { fn normal(&self, p: Vec3, ray: Vec3, t: f32) -> Vec3 { let pitch: f32 = 0.4 * t / self.inputs.resolution.x; let d: Vec2 = vec2(-1.0, 1.0) * pitch;