1use std::rc::Rc;
4
5use crate::color::Color;
6use crate::matrix::Matrix;
7use crate::shape::Shape;
8use crate::tuple::Tuple;
9
10pub mod solid_color;
11pub mod stripe;
12
13pub trait Texture {
21 fn color_at_shape(&self, point: Tuple, shape: Rc<dyn Shape>) -> Color {
22 let point = shape.transform_inverse() * point;
23 let point = self.transform_inverse() * point;
24 self.color_at(point)
25 }
26 fn color_at_texture(&self, point: Tuple) -> Color {
27 let point = self.transform_inverse() * point;
28 self.color_at(point)
29 }
30 fn color_at(&self, point: Tuple) -> Color;
31
32 fn transform(&self) -> &Matrix;
33 fn transform_inverse(&self) -> &Matrix;
34 fn set_transform(&mut self, transform: Matrix);
35}
36
37#[cfg(test)]
38mod tests {
39 use super::*;
40 use crate::shape::sphere::Sphere;
41
42 struct MockTexture {
43 transform: Matrix,
44 transform_inverse: Matrix,
45 }
46
47 impl MockTexture {
48 fn new() -> Self {
49 Self {
50 transform: Matrix::eye(),
51 transform_inverse: Matrix::eye(),
52 }
53 }
54 }
55
56 impl Texture for MockTexture {
57 fn color_at(&self, point: Tuple) -> Color {
58 Color::new(point.x(), point.y(), point.z())
59 }
60
61 fn transform(&self) -> &Matrix {
62 &self.transform
63 }
64
65 fn transform_inverse(&self) -> &Matrix {
66 &self.transform_inverse
67 }
68
69 fn set_transform(&mut self, transform: Matrix) {
70 self.transform_inverse = transform.inverse();
71 self.transform = transform;
72 }
73 }
74
75 #[test]
76 fn color_at_shape_with_shape_transformation() {
77 let mut shape = Sphere::new();
78 shape.set_transform(Matrix::scaling(2.0, 2.0, 2.0));
79 let texture = MockTexture::new();
80 let color = texture.color_at_shape(Tuple::point(2.0, 3.0, 4.0), Rc::new(shape));
81 assert_eq!(color, Color::new(1.0, 1.5, 2.0));
82 }
83
84 #[test]
85 fn color_at_shape_with_texture_transformation() {
86 let shape = Sphere::new();
87 let mut texture = MockTexture::new();
88 texture.set_transform(Matrix::scaling(2.0, 2.0, 2.0));
89 let color = texture.color_at_shape(Tuple::point(2.0, 3.0, 4.0), Rc::new(shape));
90 assert_eq!(color, Color::new(1.0, 1.5, 2.0));
91 }
92
93 #[test]
94 fn color_at_shape_with_shape_and_texture_transformation() {
95 let mut shape = Sphere::new();
96 shape.set_transform(Matrix::scaling(2.0, 2.0, 2.0));
97 let mut texture = MockTexture::new();
98 texture.set_transform(Matrix::translation(0.5, 1.0, 1.5));
99 let color = texture.color_at_shape(Tuple::point(2.5, 3.0, 3.5), Rc::new(shape));
100 assert_eq!(color, Color::new(0.75, 0.5, 0.25));
101 }
102}