bs-trace 0.3.0

Free RayTracing software
Documentation
use crate::image::prelude::Colour;
use crate::trace::material::{Lambertian, Material, Metal};
use crate::trace::prelude::{Hittable, Vec3};
use crate::trace::world::{Sphere, World};
use toml::{Table, Value};

pub fn parse_scene_file(contents: &Table) -> Option<World> {
    let objects = contents.get("objects")?.as_array()?;
    let parsed_objects: Vec<Box<dyn Hittable + Send + Sync>> = objects
        .iter()
        .flat_map(|object| object.as_table().and_then(parse_object)) // TODO short circuit on None
        .collect();
    println!("Parsed {} objects", parsed_objects.len());
    let mut world = World::new();
    for object in parsed_objects {
        world.add_object(object);
    }
    Some(world)
}

fn parse_object(object_description: &Table) -> Option<Box<dyn Hittable + Send + Sync>> {
    let object_type = object_description.get("type")?.as_str()?;
    match object_type {
        "sphere" => {
            let position = parse_position(object_description.get("position")?.as_table()?)?;
            let radius = object_description.get("radius")?.as_float()?;
            let material = parse_material(object_description.get("material")?.as_table()?)?;
            let sphere = Sphere::new(position, radius, material);
            Some(Box::new(sphere))
        }
        _ => None,
    }
}

fn parse_material(material_description: &Table) -> Option<Box<dyn Material>> {
    let material_type = material_description.get("type")?.as_str()?;
    match material_type {
        "lambertian" => parse_lambertian(material_description),
        "metal" => parse_metal(material_description),
        _ => None,
    }
}

fn parse_position(position_description: &Table) -> Option<Vec3> {
    let x = position_description.get("x")?.as_float()?;
    let y = position_description.get("y")?.as_float()?;
    let z = position_description.get("z")?.as_float()?;
    Some(Vec3::new([x, y, z]))
}

fn parse_lambertian(material_description: &Table) -> Option<Box<dyn Material>> {
    let colour = parse_colour(material_description.get("colour")?.as_table()?)?;
    let lambertian_material = Lambertian::new(colour);
    Some(Box::new(lambertian_material))
}

fn parse_metal(material_description: &Table) -> Option<Box<dyn Material>> {
    let colour = parse_colour(material_description.get("colour")?.as_table()?)?;
    let fuzz = material_description.get("fuzz")?.as_float()?;
    let metal_material = Metal::new(colour, fuzz);
    Some(Box::new(metal_material))
}

fn parse_colour(colour_description: &Table) -> Option<Colour> {
    let r = colour_description.get("r")?.as_float()?;
    let g = colour_description.get("g")?.as_float()?;
    let b = colour_description.get("b")?.as_float()?;
    Some(Colour::new(r, g, b))
}