clay_core/material/
combine.rs1#[macro_export]
3macro_rules! _replace {
4 ($_t:tt, $sub:expr) => { $sub };
5}
6
7#[macro_export]
11macro_rules! material_combine {
12 ($Combine:ident { $( $field:ident : $Material:ty ),+ $(,)? }) => {
13 pub struct $Combine {
14 $( pub $field: (f64, $Material), )+
15 }
16
17 impl $Combine {
18 pub fn new(
19 $( mut $field: (f64, $Material), )+
20 ) -> Self {
21 let mut sum = 0.0;
22 $(
23 sum += $field.0;
24 $field.0 = sum;
25 )+
26 Self {
27 $( $field: ($field.0*sum, $field.1), )+
28 }
29 }
30
31
32 #[allow(unused_assignments)]
33 fn method_source(method: &str) -> String {
34 use $crate::{prelude::*, material::*};
35
36 let cpref = format!(
37 "{}_{}",
38 MaterialClass::name(),
39 method,
40 ).to_uppercase();
41
42 let mut cases = Vec::new();
43 let (mut si, mut sf) = (0, 0);
44 $(
45 let inst_name = <$Material as Instance<MaterialClass>>::inst_name();
46 cases.push([
47 format!("\tif (alpha < fbuf[{}]) {{", sf),
48 format!(
49 "\t\treturn {}_{}({}_ARGS_B({}, {}));",
50 inst_name, method, cpref, si, sf + 1,
51 ),
52 "\t}".to_string(),
53 ].join("\n"));
54 si += <$Material>::size_int();
55 sf += 1 + <$Material>::size_float();
56 )+
57 let cases_text = cases.join(" else\n");
58 [
59 &format!(
60 "{}_RET {}_{}({}_ARGS_DEF) {{",
61 cpref, Self::inst_name(), method, cpref,
62 ),
63 "\tfloat alpha = random_uniform(seed);",
64 &cases_text,
65 &format!("\treturn {}_RET_BAD;", cpref),
66 "}",
67 ].join("\n")
68 }
69 }
70
71 impl $crate::material::Material for $Combine {
72 fn brightness(&self) -> f64 {
73 $(
74 self.$field.0*self.$field.1.brightness() +
75 )+
76 0.0
77 }
78 }
79
80 impl $crate::Instance<$crate::material::MaterialClass> for $Combine {
81 fn source(cache: &mut std::collections::HashSet<u64>) -> String {
82 use $crate::{prelude::*, material::*};
83 if !cache.insert(Self::type_hash()) {
84 return String::new()
85 }
86 let mut ms = Vec::new();
87 for method in MaterialClass::methods().into_iter() {
88 ms.push(Self::method_source(&method));
89 }
90 [
91 $( <$Material as Instance<MaterialClass>>::source(cache), )+
92 ms.join("\n"),
93 ].join("\n")
94 }
95
96 fn inst_name() -> String {
97 use $crate::TypeHash;
98 format!("__combine_{:x}", Self::type_hash())
99 }
100 }
101
102 impl $crate::Pack for $Combine {
103 fn size_int() -> usize {
104 let sizes = [
105 $( <$Material>::size_int(), )+
106 ];
107 sizes.into_iter().sum::<usize>()
108 }
109 fn size_float() -> usize {
110 let sizes = [
111 $( 1 + <$Material>::size_float(), )+
112 ];
113 sizes.into_iter().sum::<usize>()
114 }
115 fn pack_to(&self, buffer_int: &mut [i32], buffer_float: &mut [f32]) {
116 use $crate::pack::*;
117 Packer::new(buffer_int, buffer_float)
118 $(
119 .pack(&self.$field.0)
120 .pack(&self.$field.1)
121 )+;
122 }
123 }
124 };
125}
126
127#[cfg(test)]
128#[allow(dead_code)]
129mod check {
130 use crate::{
131 material::test::TestMaterial,
132 material_combine,
133 };
134
135 material_combine!(TestCombine {
136 m1: TestMaterial<i32>,
137 m2: TestMaterial<f32>,
138 });
139}