1use std::rc::Rc;
2
3use truster::canvas::Canvas;
4use truster::color::Color;
5use truster::intersection::Hit;
6use truster::light::PointLight;
7use truster::material::Material;
8use truster::matrix::Matrix;
9use truster::ray::Ray;
10use truster::shape::{sphere::Sphere, Shape};
11use truster::texture::solid_color::SolidColor;
12use truster::tuple::Tuple;
13
14fn main() -> Result<(), Box<dyn std::error::Error>> {
15 let ray_origin = Tuple::point(0.0, 0.0, -5.0);
16 let wall_z = 10.0;
17 let wall_size = 7.0;
18
19 let canvas_pixels: usize = 100;
20 let pixel_size = wall_size / canvas_pixels as f64;
21 let half = wall_size / 2.0;
22
23 let mut canvas = Canvas::new(canvas_pixels, canvas_pixels);
24 let mut shape = Sphere::new();
25 shape.set_transform(
26 Matrix::shearing(1.0, 0.0, 0.0, 0.0, 0.0, 0.0) * &Matrix::scaling(0.5, 1.0, 1.0),
27 );
28 shape.set_material(Material {
29 texture: Rc::new(SolidColor::new(Color::new(1.0, 0.2, 1.0))),
30 ..Material::default()
31 });
32 let shape: Rc<dyn Shape> = Rc::new(shape);
33
34 let light = PointLight::new(Tuple::point(-10.0, 10.0, -10.0), Color::new(1.0, 1.0, 1.0));
35
36 for y in (0..canvas_pixels).rev() {
37 let world_y = half - pixel_size * y as f64;
38
39 for x in 0..canvas_pixels {
40 let world_x = pixel_size * x as f64 - half;
41
42 let position = Tuple::point(world_x, world_y, wall_z);
43
44 let ray = Ray::new(ray_origin, (position - ray_origin).normalized());
45 let intersections = shape.intersect(&ray);
46
47 if let Some(hit) = intersections.hit() {
48 let point = ray.at(hit.t());
49 let normal = hit.shape().normal_at(point);
50 let eye = -ray.direction();
51
52 let color = hit.shape().material().lighting(
53 Rc::clone(&shape),
54 &light,
55 point,
56 eye,
57 normal,
58 false,
59 );
60
61 canvas[[x, y]] = color;
62 }
63 }
64 }
65
66 canvas.to_ppm(&mut std::io::stdout())?;
67
68 Ok(())
69}