From 1709336062b2e941a054dd27bec8872459a70171 Mon Sep 17 00:00:00 2001 From: Bradlee Speice Date: Sat, 20 Jun 2026 10:05:04 -0400 Subject: [PATCH] Add an initial implementation of the chaos game --- Cargo.lock | 17 +++++++++++++++ Cargo.toml | 3 ++- enkou-shaders/Cargo.toml | 5 +++-- enkou-shaders/src/lib.rs | 46 +++++++++++++++++++++++++++++++++++++++- 4 files changed, 67 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cb8c6b3..4684777 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -155,6 +155,7 @@ version = "0.1.0" dependencies = [ "bytemuck", "glam", + "rand", "spirv-std", ] @@ -210,6 +211,7 @@ version = "0.33.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "898f5a568a84989b6c0f8caa50a93074b97dbdc58fc6d9543157bb4562758933" dependencies = [ + "bytemuck", "libm", ] @@ -435,6 +437,21 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + [[package]] name = "raw-string" version = "0.3.5" diff --git a/Cargo.toml b/Cargo.toml index fa17411..cdedf41 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ spirv-std = { git = "https://github.com/Rust-GPU/rust-gpu.git", rev = "67f1ff2" anyhow = "1.0.102" bytemuck = { version = "1.25.0", features = ["derive"] } -glam = { version = "0.33.1", default-features = false, features = ["libm"] } +glam = { version = "0.33.1", default-features = false, features = ["bytemuck", "scalar-math"] } +rand = { version = "0.10.1", default-features = false } rspirv = "0.13.0" diff --git a/enkou-shaders/Cargo.toml b/enkou-shaders/Cargo.toml index 59ffd5a..ecbf4a0 100644 --- a/enkou-shaders/Cargo.toml +++ b/enkou-shaders/Cargo.toml @@ -10,6 +10,7 @@ repository.workspace = true workspace = true [dependencies] -spirv-std.workspace = true -glam.workspace = true bytemuck.workspace = true +glam.workspace = true +rand.workspace = true +spirv-std.workspace = true diff --git a/enkou-shaders/src/lib.rs b/enkou-shaders/src/lib.rs index cfadb05..ce89c67 100644 --- a/enkou-shaders/src/lib.rs +++ b/enkou-shaders/src/lib.rs @@ -1,8 +1,12 @@ +//! # Enkou #![no_std] +#![warn(missing_docs)] use bytemuck::{Pod, Zeroable}; use core::f32::consts::PI; -use glam::{Affine2, Vec3, Vec4, vec2, vec3}; +use glam::{Affine2, Vec3, Vec4, vec2, vec3, Vec2}; +use rand::{Rng, RngExt}; +use rand::distr::StandardUniform; #[cfg(target_arch = "spirv")] use spirv_std::num_traits::Float; use spirv_std::spirv; @@ -69,6 +73,46 @@ impl Coefficients2 for Affine2 { } } +#[derive(Copy, Clone, Pod, Zeroable)] +#[repr(C)] +pub struct Transform { + pub coefficients: Affine2, +} + +impl Transform { + pub fn new(coefficients: Affine2) -> Self { + Transform { coefficients } + } + + pub fn transform_point(&self, point: Vec2) -> Vec2 { + self.coefficients.transform_point2(point) + } +} + +/// Iterate one step in the chaos game; choose the next transform, apply it, +/// and return the resulting point. Also returns the transform index so that +/// path-dependent weights (the "Xaos" table in Apophysis) can be chosen +/// for the next iteration step. +/// +/// # Arguments +/// +/// * `weights` - Weights are assumed to be normalized; adding all elements together should return the value 1 +pub fn step_chaos_game(rng: &mut R, point: Vec2, weights: &[f32], transforms: &[Transform]) -> (Vec2, u32) { + let mut choice_weight = rng.sample::(StandardUniform); + let mut transform_index: u32 = 0; + + for weight in weights { + choice_weight -= weight; + if choice_weight <= 0.0 { + break; + } + + transform_index += 1; + } + + (transforms[transform_index as usize].transform_point(point), transform_index) +} + #[derive(Copy, Clone, Pod, Zeroable)] #[repr(C)] pub struct ShaderConstants {