ray_tracing_core/
texture.rs

1use crate::types::{ColorRGBA, Point3, TextureCoordinate};
2use std::error::Error;
3
4mod bitmap_texture;
5pub use self::bitmap_texture::BitmapTexture;
6
7mod checker_texture;
8pub use self::checker_texture::CheckerTexture;
9
10mod blend_texture;
11pub use self::blend_texture::BlendTexture;
12
13mod constant_texture;
14pub use self::constant_texture::ConstantTexture;
15
16mod noise_texture;
17pub use self::noise_texture::{NoiseTexture, NoiseType};
18
19mod color_filter;
20pub use self::color_filter::ColorFilter;
21
22pub trait Texture: Sync + Send {
23    fn get_id(&self) -> usize;
24
25    /// Look up color in texture
26    fn value(&self, uv: &TextureCoordinate, p: &Point3) -> ColorRGBA;
27
28    fn has_alpha(&self) -> bool;
29
30    fn accept(&self, visitor: &mut dyn Visitor) -> Result<(), Box<dyn Error>>;
31}
32
33pub trait Visitor {
34    fn visit_constant_texture(&mut self, t: &ConstantTexture) -> Result<(), Box<dyn Error>>;
35    fn visit_bitmap_texture(&mut self, t: &BitmapTexture) -> Result<(), Box<dyn Error>>;
36    fn visit_checker_texture(&mut self, t: &CheckerTexture) -> Result<(), Box<dyn Error>>;
37    fn visit_blend_texture(&mut self, t: &BlendTexture) -> Result<(), Box<dyn Error>>;
38    fn visit_noise_texture(&mut self, t: &NoiseTexture) -> Result<(), Box<dyn Error>>;
39    fn visit_color_filter(&mut self, t: &ColorFilter) -> Result<(), Box<dyn Error>>;
40}
41
42#[cfg(test)]
43mod test_visitor {
44    use super::*;
45    use crate::types::{ColorRGBA, Vector3};
46    use std::sync::Arc;
47
48    struct TestVisitor {
49        pub count: Vec<usize>,
50    }
51
52    impl TestVisitor {
53        pub fn default() -> TestVisitor {
54            TestVisitor {
55                count: vec![0, 0, 0, 0, 0, 0],
56            }
57        }
58
59        pub fn evaluate(&self, index: usize, expected: usize) {
60            for (i, count) in self.count.iter().enumerate() {
61                assert_eq!(count, &if i == index { expected } else { 0 });
62            }
63        }
64    }
65
66    impl Visitor for TestVisitor {
67        fn visit_constant_texture(&mut self, _: &ConstantTexture) -> Result<(), Box<dyn Error>> {
68            self.count[0] += 1;
69            Ok(())
70        }
71        fn visit_bitmap_texture(&mut self, _: &BitmapTexture) -> Result<(), Box<dyn Error>> {
72            self.count[1] += 1;
73            Ok(())
74        }
75        fn visit_checker_texture(&mut self, _: &CheckerTexture) -> Result<(), Box<dyn Error>> {
76            self.count[2] += 1;
77            Ok(())
78        }
79        fn visit_blend_texture(&mut self, _: &BlendTexture) -> Result<(), Box<dyn Error>> {
80            self.count[3] += 1;
81            Ok(())
82        }
83        fn visit_noise_texture(&mut self, _: &NoiseTexture) -> Result<(), Box<dyn Error>> {
84            self.count[4] += 1;
85            Ok(())
86        }
87        fn visit_color_filter(&mut self, _: &ColorFilter) -> Result<(), Box<dyn Error>> {
88            self.count[5] += 1;
89            Ok(())
90        }
91    }
92
93    #[test]
94    pub fn test_visitor_constant_texture() {
95        let t = ConstantTexture::new(ColorRGBA::new(0.0, 0.0, 0.0, 1.0));
96        let mut v = TestVisitor::default();
97        t.accept(&mut v).unwrap();
98        v.evaluate(0, 1);
99    }
100
101    #[test]
102    pub fn test_visitor_bitmap_texture() {
103        let t = BitmapTexture::new(1, 1, vec![255, 0, 0, 255]);
104        let mut v = TestVisitor::default();
105        t.accept(&mut v).unwrap();
106        v.evaluate(1, 1);
107    }
108
109    #[test]
110    pub fn test_visitor_checker_texture() {
111        let e = ConstantTexture::new(ColorRGBA::new(0.0, 0.0, 0.0, 1.0));
112        let o = ConstantTexture::new(ColorRGBA::new(1.0, 1.0, 1.0, 1.0));
113        let t = CheckerTexture::new(Vector3::new(0.0, 0.0, 0.0), Arc::new(e), Arc::new(o));
114        let mut v = TestVisitor::default();
115        t.accept(&mut v).unwrap();
116        v.evaluate(2, 1);
117    }
118
119    #[test]
120    pub fn test_visitor_blend_texture() {
121        let ct1 = ConstantTexture::new(ColorRGBA::new(0.0, 0.0, 0.0, 1.0));
122        let ct2 = ConstantTexture::new(ColorRGBA::new(1.0, 1.0, 1.0, 1.0));
123        let mt = ConstantTexture::new(ColorRGBA::new(1.0, 1.0, 1.0, 1.0));
124        let t = BlendTexture::new(
125            Vector3::new(0.0, 0.0, 0.0),
126            Arc::new(ct1),
127            Arc::new(ct2),
128            Arc::new(mt),
129        );
130        let mut v = TestVisitor::default();
131        t.accept(&mut v).unwrap();
132        v.evaluate(3, 1);
133    }
134
135    #[test]
136    pub fn test_visitor_noise_texture() {
137        let ct1 = ConstantTexture::new(ColorRGBA::new(0.0, 0.0, 0.0, 1.0));
138        let ct2 = ConstantTexture::new(ColorRGBA::new(1.0, 1.0, 1.0, 1.0));
139        let t = NoiseTexture::new(1.0, NoiseType::Default, Arc::new(ct1), Arc::new(ct2));
140        let mut v = TestVisitor::default();
141        t.accept(&mut v).unwrap();
142        v.evaluate(4, 1);
143    }
144
145    #[test]
146    pub fn test_visitor_color_filter() {
147        let ct = ConstantTexture::new(ColorRGBA::new(1.0, 1.0, 1.0, 1.0));
148        let t = ColorFilter::new(
149            ColorRGBA::new(0.0, 0.0, 0.0, 0.0),
150            ColorRGBA::new(0.0, 0.5, 0.5, 1.0),
151            ColorRGBA::new(0.0, 0.0, 0.0, 0.0),
152            Arc::new(ct),
153        );
154        let mut v = TestVisitor::default();
155        t.accept(&mut v).unwrap();
156        v.evaluate(5, 1);
157    }
158}