From 08ada94bd270dc6851460637fb19b59617a238c3 Mon Sep 17 00:00:00 2001 From: Bradlee Speice Date: Sun, 12 Jul 2026 10:05:19 -0400 Subject: [PATCH] Implement post-transform coefficients --- Cargo.toml | 2 +- enkou-shaders/examples/gasket.rs | 30 +++++++++--------- enkou-shaders/src/transform.rs | 53 ++++++++++++++++++++++++++++++-- enkou-shaders/src/variation.rs | 6 ++++ 4 files changed, 73 insertions(+), 18 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 594cd29..b5fdf79 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ bytemuck = { version = "1.25.0", features = ["derive"] } glam = { version = "0.33.1", default-features = false, features = ["bytemuck", "scalar-math"] } image = { version = "0.25.10", default-features = false, features = ["default-formats"]} libm = "0.2.16" -rand = { version = "0.10.1", default-features = false } +rand = { version = "0.10.1", default-features = false } rand_xoshiro = "0.8.1" rspirv = "0.13.0" tempfile = "3.27.0" diff --git a/enkou-shaders/examples/gasket.rs b/enkou-shaders/examples/gasket.rs index 55d0001..12ce467 100644 --- a/enkou-shaders/examples/gasket.rs +++ b/enkou-shaders/examples/gasket.rs @@ -17,21 +17,21 @@ const IMAGE_DIMENSION: UVec2 = uvec2(600, 600); pub fn main() -> Result<()> { let transforms = [ - // F_0: (x / 2, y / 2) - Transform::new( - Affine2::from_coefficients(0.5, 0.0, 0.0, 0.0, 0.5, 0.0), - uvec2(0, 1), - ), - // F_1: ((x + 1) / 2, y / 2) - Transform::new( - Affine2::from_coefficients(0.5, 0.0, 0.5, 0.0, 0.5, 0.0), - uvec2(0, 1), - ), - // F_2: (x / 2, (y + 1) / 2) - Transform::new( - Affine2::from_coefficients(0.5, 0.0, 0.0, 0.0, 0.5, 0.5), - uvec2(0, 1), - ), + { + // F_0: (x / 2, y / 2) + let coefficients = Affine2::from_coefficients(0.5, 0.0, 0.0, 0.0, 0.5, 0.0); + Transform::new(coefficients, Affine2::IDENTITY, uvec2(0, 1)) + }, + { + // F_1: ((x + 1) / 2, y / 2) + let coefficients = Affine2::from_coefficients(0.5, 0.0, 0.5, 0.0, 0.5, 0.0); + Transform::new(coefficients, Affine2::IDENTITY, uvec2(0, 1)) + }, + { + // F_2: (x / 2, (y + 1) / 2) + let coefficients = Affine2::from_coefficients(0.5, 0.0, 0.0, 0.0, 0.5, 0.5); + Transform::new(coefficients, Affine2::IDENTITY, uvec2(0, 1)) + }, ]; let weights = [1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0]; diff --git a/enkou-shaders/src/transform.rs b/enkou-shaders/src/transform.rs index 3b8badc..0c91370 100644 --- a/enkou-shaders/src/transform.rs +++ b/enkou-shaders/src/transform.rs @@ -13,14 +13,16 @@ use rand::Rng; #[repr(C)] pub struct Transform { coefficients: Affine2, + coefficients_post: Affine2, variation_range: UVec2, } impl Transform { /// Create a new transform from an affine transformation matrix - pub fn new(coefficients: Affine2, variation_range: UVec2) -> Self { + pub fn new(coefficients: Affine2, coefficients_post: Affine2, variation_range: UVec2) -> Self { Transform { coefficients, + coefficients_post, variation_range, } } @@ -43,6 +45,53 @@ impl Transform { point_output += variation.transform_point(point, rng, &self.coefficients) } - point_output + self.coefficients_post.transform_point2(point) + } +} + +#[cfg(test)] +mod test { + use crate::rng::xoshiro256starstar_from_seed; + use crate::transform::Transform; + use crate::variation::{Variation, VariationKind}; + use glam::{Affine2, uvec2, vec2}; + + #[test] + fn transform_scaling() { + let scale_coefficients = vec2(2.0, 0.5); + let transform = Transform::new( + Affine2::from_scale(scale_coefficients), + Affine2::IDENTITY, + uvec2(0, 1), + ); + + let mut rng = xoshiro256starstar_from_seed([0; 32]); + let variations = [Variation::IDENTITY]; + let point = vec2(1.0, 1.0); + + assert_eq!( + transform.transform_point(&mut rng, &variations, point), + scale_coefficients + ); + } + + #[test] + fn transform_scaling_post() { + let scale_coefficients = vec2(2.0, 0.5); + let transform_pdj = Transform::new(Affine2::IDENTITY, Affine2::IDENTITY, uvec2(0, 1)); + let transform_pdj_post = Transform::new( + Affine2::IDENTITY, + Affine2::from_scale(scale_coefficients), + uvec2(0, 1), + ); + + let mut rng = xoshiro256starstar_from_seed([0; 32]); + let variations = [Variation::new(VariationKind::Pdj, 1.0, [0.0f32; 4].into())]; + let point = vec2(1.0, 1.0); + + let point_pdj = transform_pdj.transform_point(&mut rng, &variations, point); + let point_pdj_post = transform_pdj_post.transform_point(&mut rng, &variations, point); + + assert_eq!(point_pdj * scale_coefficients, point_pdj_post); } } diff --git a/enkou-shaders/src/variation.rs b/enkou-shaders/src/variation.rs index 06a0df0..81c3463 100644 --- a/enkou-shaders/src/variation.rs +++ b/enkou-shaders/src/variation.rs @@ -20,6 +20,12 @@ use rand::{Rng, RngExt}; #[repr(C)] pub struct VariationParams([f32; 4]); +impl From<[f32; 4]> for VariationParams { + fn from(v: [f32; 4]) -> Self { + VariationParams(v) + } +} + /// Enum for all supported variation types /// /// ID numbers are chosen to match the variation identifier also used by `flam3` -- 2.52.0