extern crate image;

pub mod point;
pub mod rendering;
pub mod scene;
pub mod vector;

use image::GenericImage;
use image::Pixel;
use scene::Scene;

pub fn render(scene: &Scene) -> image::DynamicImage {
    let mut image = image::DynamicImage::new_rgb8(scene.width, scene.height);
    let black = image::Rgba::from_channels(0, 0, 0, 0);
    for x in 0..scene.width {
        for y in 0..scene.height {
            let ray = rendering::Ray::create_prime(x, y, scene);

            if let Some(intersection) = scene.trace(&ray) {
                let hit_point = ray.origin + (&ray.direction * intersection.distance);
                let surface_normal = intersection.object.surface_normal(&hit_point);
                let direction_to_light = -scene.light.direction;
                let c = &intersection.object.color();
                image.put_pixel(x, y, image::Rgba(c.to_rgba()))
            } else {
                image.put_pixel(x, y, black);
            }
        }
    }
    image
}

#[test]
fn test_can_render_scene() {
    use point::Point;
    use rendering::Element;
    use rendering::Plane;
    use rendering::Sphere;
    use scene::Color;
    use scene::Light;
    use vector::Vector3;

    let scene = Scene {
        width: 800,
        height: 600,
        fov: 90.0,
        elements: vec![
            Element::Plane(Plane {
                origin: Point {
                    x: 0.0,
                    y: -2.0,
                    z: -5.0,
                },
                normal: Vector3 {
                    x: 0.0,
                    y: -1.0,
                    z: 0.0,
                },
                color: Color {
                    red: 0.2,
                    green: 0.2,
                    blue: 0.3,
                },
            }),
            Element::Plane(Plane {
                origin: Point {
                    x: 0.0,
                    y: 0.0,
                    z: -20.0,
                },
                normal: Vector3 {
                    x: 0.0,
                    y: 0.0,
                    z: -1.0,
                },
                color: Color {
                    red: 0.2,
                    green: 0.3,
                    blue: 1.0,
                },
            }),
            Element::Sphere(Sphere {
                center: Point {
                    x: 2.0,
                    y: 1.0,
                    z: -4.0,
                },
                radius: 1.5,
                color: Color {
                    red: 1.0,
                    green: 0.2,
                    blue: 0.2,
                },
            }),
            Element::Sphere(Sphere {
                center: Point {
                    x: 0.0,
                    y: 0.0,
                    z: -5.0,
                },
                radius: 1.0,
                color: Color {
                    red: 0.2,
                    green: 1.0,
                    blue: 0.2,
                },
            }),
            Element::Sphere(Sphere {
                center: Point {
                    x: -3.0,
                    y: 1.0,
                    z: -6.0,
                },
                radius: 2.0,
                color: Color {
                    red: 0.2,
                    green: 0.2,
                    blue: 1.0,
                },
            }),
            Element::Sphere(Sphere {
                center: Point {
                    x: 2.0,
                    y: 1.0,
                    z: -10.0,
                },
                radius: 5.0,
                color: Color {
                    red: 1.0,
                    green: 1.0,
                    blue: 1.0,
                },
            }),
        ],
        light: Light {
            direction: Vector3 {
                x: 0.0,
                y: 0.0,
                z: -1.0,
            },
            color: Color {
                red: 1.0,
                green: 1.0,
                blue: 1.0,
            },
            intensity: 0.0,
        },
    };

    let img: image::DynamicImage = render(&scene);
    assert_eq!(scene.width, img.width());
    assert_eq!(scene.height, img.height());
    img.save("/tmp/bheisler.png").unwrap();
}
