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 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}