diff options
author | pommicket <pommicket@gmail.com> | 2022-12-15 11:33:32 -0500 |
---|---|---|
committer | pommicket <pommicket@gmail.com> | 2022-12-15 11:33:32 -0500 |
commit | 4f48f02f91f2134b4452729dd96524ea1814efb2 (patch) | |
tree | 2af6a435a33119bb2169cdec48da7a71c6bf0437 | |
parent | e45cbe4744c76a160e012a4d9bcf8d46340821d8 (diff) |
various fixes
-rw-r--r-- | gen_random/src/lib.rs | 36 | ||||
-rw-r--r-- | gen_random_proc_macro/src/lib.rs | 38 | ||||
-rw-r--r-- | src/main.rs | 13 | ||||
-rw-r--r-- | src/sdf.rs | 114 |
4 files changed, 133 insertions, 68 deletions
diff --git a/gen_random/src/lib.rs b/gen_random/src/lib.rs index c21a1b1..07da6b5 100644 --- a/gen_random/src/lib.rs +++ b/gen_random/src/lib.rs @@ -6,7 +6,7 @@ use std::cell::{Cell, RefCell}; /// Generate random structs and enums! /// -/// You shouldn't implement this trait yourself — instead, use the `derive` macro: +/// You don't need to implement this trait yourself — instead, use the `derive` macro: /// ``` /// use gen_random_proc_macro::GenRandom; /// use gen_random::GenRandom; @@ -14,15 +14,15 @@ use std::cell::{Cell, RefCell}; /// #[derive(GenRandom, Debug)] /// enum MyType { /// // this variant will be chosen 7 / 10.5 = 2/3 of the time -/// #[prob = 7] +/// #[prob(7)] /// Variant1(f64), /// // this variant will be chosen 3.5 / 10.5 = 1/3 of the time -/// #[prob = 3.5] +/// #[prob(3.5)] /// Variant2 { /// // bias & scale attributes can be used for fields of type f32/f64. /// // this makes `a` range from 2 to 6 (as opposed to the default 0 to 1). -/// #[bias = 2.0] -/// #[scale = 4.0] +/// #[bias(2.0)] +/// #[scale(4.0)] /// a: f64, /// // we can even include a randomly-generated MyType inside this MyType! /// // be careful when doing this or else you might try to generate an infinite struct! @@ -176,46 +176,46 @@ mod tests { #[derive(GenRandom, Debug)] enum Test1 { - #[prob = 0.2] + #[prob(0.2)] A(f32), - #[prob = 0.8] + #[prob(0.8)] B(Option<f32>), } #[derive(GenRandom, Debug)] #[allow(dead_code)] enum Test2 { - #[prob = 0.1] + #[prob(0.1)] Variant1, - #[prob = 0.7] + #[prob(0.7)] Variant2 { x: f32, y: f64, z: Test1 }, - #[prob = 0.2] + #[prob(0.2)] Variant3(f32, Box<Test2>), } #[derive(GenRandom, Debug)] enum LinkedList { - #[prob = 10] + #[prob(10)] Empty, - #[prob = 90] + #[prob(90)] Cons(f32, Box<LinkedList>), } #[derive(GenRandom, Debug)] enum BinaryTree { - #[prob = 1] + #[prob(1)] Empty, - #[prob = 99] + #[prob(99)] Node(f64, Box<BinaryTree>, Box<BinaryTree>) } #[derive(GenRandom, Debug)] struct ScaleBias { - #[bias = 1.0] - #[scale = 10.0] + #[bias(1.0)] + #[scale(10.0)] a: f32, - #[bias = 2.0] - #[scale = 0.0] + #[bias(2.0)] + #[scale(0.0)] b: f32, } diff --git a/gen_random_proc_macro/src/lib.rs b/gen_random_proc_macro/src/lib.rs index 5e28e16..9b7a771 100644 --- a/gen_random_proc_macro/src/lib.rs +++ b/gen_random_proc_macro/src/lib.rs @@ -19,7 +19,7 @@ pub fn gen_random_derive(input: TokenStream) -> TokenStream { impl_gen_random(&ast) } -fn get_attribute_literal(attrs: &[syn::Attribute], name: &str) -> Option<proc_macro2::Literal> { +fn get_attribute(attrs: &[syn::Attribute], name: &str) -> Option<proc_macro2::TokenStream> { let attr = attrs.iter().find(|a| { let path = &a.path; if let Some(ident) = path.get_ident() { @@ -30,25 +30,27 @@ fn get_attribute_literal(attrs: &[syn::Attribute], name: &str) -> Option<proc_ma })?; let tokens: TokenStream2 = attr.tokens.clone().into(); - let mut tokens: Vec<TokenTree2> = tokens.into_iter().collect(); - if tokens.len() != 2 { - panic!("Expected {name} = <value>"); + let tokens: Vec<TokenTree2> = tokens.into_iter().collect(); + if tokens.len() != 1 { + panic!("Expected {name}(<value>)"); } - use TokenTree2::{Punct, Literal}; - match &tokens[0] { - Punct(equals) if equals.as_char() == '=' => {} - _ => panic!("Expected = after {name} attribute"), + use TokenTree2::Group; + use proc_macro2::Delimiter; + let value = match &tokens[0] { + Group(g) if g.delimiter() == Delimiter::Parenthesis => { + g.stream() + }, + _ => { + panic!("Expected {name}(<value>)"); + }, }; - let Literal(literal) = tokens.remove(1) else { - panic!("Bad value for {name} attribute."); - }; - Some(literal) + Some(value) } fn parse_attribute_value<T: FromStr>(attrs: &[syn::Attribute], name: &str) -> Option<T> { - let literal = get_attribute_literal(attrs, name)?; - let Ok(value) = literal.to_string().parse() else { + let stream = get_attribute(attrs, name)?; + let Ok(value) = stream.to_string().parse() else { panic!("Bad {} for {name} attribute", type_name::<T>()) }; Some(value) @@ -63,11 +65,11 @@ fn generate_fields(fields: &syn::Fields) -> impl quote::ToTokens { let ty = &field.ty; field_values.extend(quote! { <#ty as GenRandom>::gen_random_max_depth(rng, _depth - 1) }); - if let Some(scale) = get_attribute_literal(&field.attrs, "scale") { - field_values.extend(quote! { * #scale }); + if let Some(scale) = get_attribute(&field.attrs, "scale") { + field_values.extend(quote! { * ( #scale ) }); } - if let Some(bias) = get_attribute_literal(&field.attrs, "bias") { - field_values.extend(quote! { + #bias }); + if let Some(bias) = get_attribute(&field.attrs, "bias") { + field_values.extend(quote! { + ( #bias ) }); } field_values.extend(quote! { , }); diff --git a/src/main.rs b/src/main.rs index a9e9909..79b9d1f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,7 @@ /* @TODO: +- auto-select level set by sampling a bunch of points +- Params instead of depth - fullscreen key - mathematical analysis - options for: @@ -65,16 +67,7 @@ impl View { } fn try_main() -> Result<(), String> { -// use sdf::{Constant, R3ToR, R3ToR3, RToR}; -// let _test = Constant::gen_thread_random(); -// println!("{_test:?}"); -// -// let funciton = R3ToR::compose( -// R3ToR3::InfiniteMirrors(Constant::from(2.0)), -// R3ToR::sphere_f32(0.2), -// RToR::Identity, -// ); - let my_sdf = sdf::Sdf::gen_thread_random_max_depth(6); + let my_sdf = sdf::Sdf::gen_thread_random_max_depth(7); println!("{my_sdf:?}"); let mut window = win::Window::new("AutoSDF", 1280, 720, true) @@ -1,4 +1,3 @@ -#![allow(dead_code)] // @TODO @TEMPORARY extern crate gen_random_proc_macro; extern crate rand; @@ -12,20 +11,47 @@ macro_rules! write_str { } /// these are constant across 3D space, not across time/user input/etc. -#[derive(GenRandom, Debug)] +#[derive(Debug, GenRandom)] pub enum Constant { - #[prob = 0.5] + #[prob(0.5)] F32(f32), - #[prob = 0] - Time(f32, f32), + #[prob(0.5)] + Time( + #[scale(0.2)] + #[bias(-0.1)] + f32, f32), } + + impl From<f32> for Constant { fn from(x: f32) -> Self { Self::F32(x) } } +impl std::ops::Add<f32> for Constant { + type Output = Self; + fn add(self, a: f32) -> Self::Output { + use Constant::*; + match self { + F32(x) => F32(x + a), + Time(s, b) => Time(s, b + a), + } + } +} + +impl std::ops::Mul<f32> for Constant { + type Output = Self; + fn mul(self, m: f32) -> Self::Output { + use Constant::*; + match self { + F32(x) => F32(x * m), + Time(s, b) => Time(s * m, b * m), + } + } +} + impl Display for Constant { fn fmt(&self, f: &mut Formatter) -> fmt::Result { use Constant::*; @@ -39,6 +65,20 @@ impl Display for Constant { #[derive(GenRandom, Debug)] pub struct Constant3(Constant, Constant, Constant); +impl std::ops::Add<f32> for Constant3 { + type Output = Self; + fn add(self, a: f32) -> Self::Output { + Self(self.0 + a, self.1 + a, self.2 + a) + } +} + +impl std::ops::Mul<f32> for Constant3 { + type Output = Self; + fn mul(self, m: f32) -> Self::Output { + Self(self.0 * m, self.1 * m, self.2 * m) + } +} + impl From<(Constant, Constant, Constant)> for Constant3 { fn from(x: (Constant, Constant, Constant)) -> Self { Self(x.0, x.1, x.2) @@ -54,41 +94,46 @@ impl Display for Constant3 { #[derive(GenRandom, Debug)] pub enum R3ToR3 { - #[prob = 0] + #[prob(0)] Identity, - #[prob = 6] + #[prob(6)] Compose(Box<R3ToR3>, Box<R3ToR3>), - #[prob = 1] + #[prob(1)] Translate(Constant3), - #[prob = 2] + #[prob(2)] Sin(Constant), - #[prob = 2] + #[prob(2)] InfiniteMirrors(Constant), + #[prob(2)] + #[scale(2 * std::f32::consts::PI)] + Rotate(Constant3), + #[prob(2)] + Arctan(Constant) // arctan(c x) / c } #[derive(GenRandom, Debug)] pub enum RToR { - #[prob = 0] + #[prob(0)] Identity, - #[prob = 2] + #[prob(2)] Compose(Box<RToR>, Box<RToR>), - #[prob = 2] - Add(Constant), + #[prob(2)] + Subtract(Constant), } #[derive(GenRandom, Debug)] pub enum R3ToR { - #[prob = 1] + #[prob(1)] Sphere(Constant), - #[prob = 1] + #[prob(1)] Cube(Constant), - #[prob = 8] + #[prob(8)] Compose(Box<R3ToR3>, Box<R3ToR>, Box<RToR>), - #[prob = 4] + #[prob(4)] Mix(Box<R3ToR>, Box<R3ToR>, Constant), - #[prob = 2] + #[prob(2)] SmoothMin(Box<R3ToR>, Box<R3ToR>), - #[prob = 2] + #[prob(2)] Min(Box<R3ToR>, Box<R3ToR>), } @@ -184,9 +229,9 @@ impl Function for RToR { match self { Identity => input, - Add(x) => { + Subtract(x) => { let output = var.next(); - write_str!(code, "float {output} = {input} + {x};\n"); + write_str!(code, "float {output} = {input} - {x};\n"); output } Compose(a, b) => { @@ -233,6 +278,31 @@ impl Function for R3ToR3 { let a_output = a.to_glsl(input, code, var); b.to_glsl(a_output, code, var) } + Arctan(c) => { + let output = var.next(); + // we need to scale arctan(cx) so it doesn't break the SDF + write_str!(code, "vec3 {output} = (1.0 / {c}) * atan({c} * {input});\n"); + output + }, + Rotate(by) => { + // by = euler angles + // see https://en.wikipedia.org/wiki/Rotation_matrix#General_rotations + // for matrix + // this is the RzRyRx one + let c = var.next(); + let s = var.next(); + let m = var.next(); + let output = var.next(); + write_str!(code, "vec3 {c} = cos({by});\n"); + write_str!(code, "vec3 {s} = sin({by});\n"); + write_str!(code, "mat3 {m} = mat3( +{c}.y*{c}.z, {s}.x*{s}.y*{c}.z - {c}.x*{s}.z, {c}.x*{s}.y*{c}.z + {s}.x*{s}.z, +{c}.y*{s}.z, {s}.x*{s}.y*{s}.z + {c}.x*{c}.z, {c}.x*{s}.y*{s}.z - {s}.x*{c}.z, +-{s}.y, {s}.x*{c}.y, {c}.x*{c}.y +);\n"); + write_str!(code, "vec3 {output} = {m} * {input};\n"); + output + } } } } |