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