clay_core/object/
covered.rs

1use std::collections::HashSet;
2use crate::{
3    prelude::*,
4    shape::*,
5    material::*,
6    object::*,
7};
8
9
10#[derive(Clone, Debug, Default)]
11/// Object obtained by covering a shape with a material.
12pub struct Covered<S: Shape, M: Material> {
13    pub shape: S,
14    pub material: M,
15}
16
17impl<S: Shape, M: Material> Covered<S, M> {
18    pub fn new(shape: S, material: M) -> Self {
19        Self { shape, material }
20    }
21
22    fn shape_source(cache: &mut HashSet<u64>) -> String {
23        [
24            S::source(cache),
25            ShapeClass::methods().into_iter().map(|method| {
26                format!(
27                    "#define {}_{} {}_{}",
28                    Self::inst_name(), method,
29                    S::inst_name(), method,
30                )
31            }).collect::<Vec<_>>().join("\n"),
32        ].join("\n")
33    }
34
35    fn material_source(cache: &mut HashSet<u64>) -> String {
36        [
37            M::source(cache),
38            MaterialClass::methods().into_iter().map(|method| {
39                let cpref = format!("{}_{}", MaterialClass::name(), method).to_uppercase();
40                [
41                    &format!("{}_RET {}_{}(", cpref, Self::inst_name(), method),
42                    &format!("\t{}_ARGS_DEF", cpref),
43                    ") {",
44                    &format!(
45                        "\treturn {}_{}({}_ARGS_B({}, {}));",
46                        M::inst_name(), method, cpref, S::size_int(), S::size_float(),
47                    ),
48                    "}",
49                ].join("\n")
50            }).collect::<Vec<_>>().join("\n"),
51        ].join("\n")
52    }
53}
54
55impl<S: Shape, M: Material> Object for Covered<S, M> {}
56
57impl<S: Shape, M: Material> Instance<ObjectClass> for Covered<S, M> {
58    fn source(cache: &mut HashSet<u64>) -> String {
59        if !cache.insert(Self::type_hash()) {
60            return String::new()
61        }
62        [
63            Self::shape_source(cache),
64            Self::material_source(cache),
65        ].join("\n")
66    }
67    fn inst_name() -> String {
68        format!("__covered_{:x}", Self::type_hash())
69    }
70}
71
72impl<S: Shape, M: Material> Pack for Covered<S, M> {
73    fn size_int() -> usize {
74        S::size_int() + M::size_int()
75    }
76    fn size_float() -> usize {
77        S::size_float() + M::size_float()
78    }
79
80    fn pack_to(&self, buffer_int: &mut [i32], buffer_float: &mut [f32]) {
81        Packer::new(buffer_int, buffer_float)
82        .pack(&self.shape)
83        .pack(&self.material);
84    }
85}
86
87impl<B: Bound, S: Shape + Bounded<B>, M: Material> Bounded<B> for Covered<S, M> {
88    fn bound(&self) -> Option<B> {
89        self.shape.bound()
90    }
91}
92
93impl<T: Bound + Target, S: Shape + Bounded<T>, M: Material> Targeted<T> for Covered<S, M> {
94    fn target(&self) -> Option<(T, f64)> {
95        self.shape.bound()
96        .map(|t| (t, self.material.brightness()))
97    }
98}