//! GLSL Operation declarations use quote::{Ident, Tokens}; fn operation(name: &str, args: u32, adnl_generics: &[Ident], constraints: &Tokens, implementation: &Tokens) -> Tokens { let node = Ident::from(name); let fn_name = Ident::from(name.to_lowercase()); let indices: Vec = (0..args).collect(); let mut generics: Vec<_> = { indices.iter() .map(|i| Ident::from(format!("T{}", i))) .collect() }; let args: Vec = { indices.iter() .map(|i| Ident::from(format!("arg_{}", i))) .collect() }; let arg_list: Vec<_> = { args.iter() .zip(generics.iter()) .map(|(arg, ty)| quote! { #arg: #ty }) .collect() }; let args2 = args.clone(); for gen in adnl_generics { generics.push(gen.clone()); } let method_impl = match_values( &args, implementation, quote! { let index = graph.add_node(Node::#node); #( graph.add_edge(#args2, index, #indices); )* index }, ); quote! { #[allow(unused_variables)] pub fn #fn_name< #( #generics , )* R >( #( #arg_list ),* ) -> Value #constraints { #method_impl } } } pub fn match_values(names: &[Ident], concrete: &Tokens, index: Tokens) -> Tokens { let parts = names.len(); let arms: Vec<_> = { (0..2u32.pow(parts as u32)) .map(|id| { if id == 0 { quote! { ( #( Value::Concrete( #names ), )* ) => { return { #concrete } }, } } else { let mut first_abstract = true; let (patterns, indices): (Vec<_>, Vec<_>) = { names.into_iter().enumerate() .map(move |(i, name)| { if (id >> i) & 1 == 1 { ( if first_abstract { first_abstract = false; quote! { Value::Abstract { module, function, index: #name, .. } } } else { quote! { Value::Abstract { index: #name, .. } } }, quote! { #name } ) } else { ( quote! { #name @ Value::Concrete(_) }, quote! {{ let module = module.borrow_mut(); let graph = function.get_graph_mut(module); #name.get_index(graph) }} ) } }) .unzip() }; let ident1: Vec<_> = (0..indices.len()).map(|i| Ident::from(format!("tmp_{}", i))).collect(); let ident2 = ident1.clone(); quote! { ( #( #patterns, )* ) => { #( let #ident1 = #indices; )* ( module, function, #( #ident2 ),* ) }, } } }) .collect() }; quote! { let ( module, function, #( #names ),* ) = match ( #( #names.into_value(), )* ) { #( #arms )* }; let index = { let module = module.borrow_mut(); let mut graph = function.get_graph_mut(module); #index }; Value::Abstract { module, function, index, ty: PhantomData, } } } pub fn impl_operations() -> Vec { let operations: &[(&str, u32, &[Ident], Tokens, Tokens)] = &[ ( "Normalize", 1, &[ Ident::from("S") ], quote! { where T0: IntoValue, R: Vector, S: Floating }, quote! { let count = R::component_count(); let length = match length(arg_0) { Value::Concrete(v) => v, _ => unreachable!(), }; let arr: Vec<_> = (0..count).map(|i| arg_0[i] / length).collect(); let vec: R = arr.into(); vec.into() } ), ( "Dot", 2, &[ Ident::from("V") ], quote! { where T0: IntoValue, T1: IntoValue, V: Vector, R: Numerical }, quote! { let count = V::component_count(); let val: R = (0..count).map(|i| arg_0[i] * arg_1[i]).sum(); val.into() } ), ( "Clamp", 3, &[], quote! { where T0: IntoValue, T1: IntoValue, T2: IntoValue, R: Scalar }, quote! { let x: Value = arg_0.into(); let min_val: Value = arg_1.into(); let max_val: Value = arg_2.into(); min(max(x, min_val), max_val) } ), ( "Cross", 2, &[ Ident::from("S") ], quote! { where T0: IntoValue, T1: IntoValue, R: Vector, S: Numerical }, quote! { let vec: R = vec![ arg_0[1] * arg_1[2] - arg_1[1] * arg_0[2], arg_0[2] * arg_1[0] - arg_1[2] * arg_0[0], arg_0[0] * arg_1[1] - arg_1[0] * arg_0[1], ].into(); vec.into() } ), ( "Floor", 1, &[], quote! { where T0: IntoValue, R: Floating }, quote! { arg_0.floor().into() } ), ( "Ceil", 1, &[], quote! { where T0: IntoValue, R: Floating }, quote! { arg_0.ceil().into() } ), ( "Round", 1, &[], quote! { where T0: IntoValue, R: Floating }, quote! { arg_0.round().into() } ), ( "Sin", 1, &[], quote! { where T0: IntoValue, R: Floating }, quote! { arg_0.sin().into() } ), ( "Cos", 1, &[], quote! { where T0: IntoValue, R: Floating }, quote! { arg_0.cos().into() } ), ( "Tan", 1, &[], quote! { where T0: IntoValue, R: Floating }, quote! { arg_0.tan().into() } ), ( "Pow", 2, &[], quote! { where T0: IntoValue, T1: IntoValue, R: Numerical }, quote! { Numerical::pow(arg_0, arg_1).into() } ), ( "Min", 2, &[], quote! { where T0: IntoValue, T1: IntoValue, R: Scalar }, quote! { (if arg_1 < arg_0 { arg_1 } else { arg_0 }).into() } ), ( "Max", 2, &[], quote! { where T0: IntoValue, T1: IntoValue, R: Scalar }, quote! { (if arg_1 > arg_0 { arg_1 } else { arg_0 }).into() } ), ( "Length", 1, &[ Ident::from("V") ], quote! { where T0: IntoValue, V: Vector, R: Floating }, quote! { let count = V::component_count(); let length: R = { (0..count) .map(|i| arg_0[i] * arg_0[i]) .sum() }; length.sqrt().into() } ), ( "Distance", 2, &[ Ident::from("V") ], quote! { where T0: IntoValue, T1: IntoValue, V: Vector + Sub, R: Floating }, quote! { length(arg_0 - arg_1) } ), ( "Reflect", 2, &[ Ident::from("S") ], quote! { where T0: IntoValue, T1: IntoValue, R: Vector + Sub, S: Numerical + Mul }, quote! { let res: S = match dot(arg_1, arg_0) { Value::Concrete(v) => v, _ => unreachable!(), }; let res: S = res + res; let res: R = arg_0 - res * arg_1; res.into() } ), ( "Refract", 3, &[ Ident::from("S") ], quote! { where T0: IntoValue, T1: IntoValue, T2: IntoValue, R: Vector + Sub, S: Floating + Mul }, quote! { let one: S = Scalar::one(); let dot: S = match dot(arg_1, arg_0) { Value::Concrete(v) => v, _ => unreachable!(), }; let k: S = one - arg_2 * arg_2 * (one - dot * dot); let res: R = if k < Scalar::zero() { Vector::zero() } else { let lhs = arg_2 * arg_0; let rhs = (arg_2 * dot + k.sqrt()) * arg_1; lhs - rhs }; res.into() } ), ( "Mix", 3, &[ Ident::from("V0"), Ident::from("V1"), Ident::from("V2"), Ident::from("V3"), Ident::from("V4") ], quote! { where T0: IntoValue, T1: IntoValue, T2: IntoValue, V0: IntoValue + Copy + Add, V1: IntoValue + Clone + Sub, V2: IntoValue + Clone + Mul, R: Into> }, quote! { (arg_0 + arg_2 * (arg_1 - arg_0)).into() } ) ]; operations.into_iter() .map(|&(name, args, generics, ref constraints, ref implementation)| { operation(name, args, generics, constraints, implementation) }) .collect() }