bs_trace/trace/
description.rs

1use crate::image::prelude::Colour;
2use crate::trace::material::{Lambertian, Material, Metal};
3use crate::trace::prelude::{Hittable, Vec3};
4use crate::trace::world::{Sphere, World};
5use toml::{Table, Value};
6
7pub fn parse_scene_file(contents: &Table) -> Option<World> {
8    let objects = contents.get("objects")?.as_array()?;
9    let parsed_objects: Vec<Box<dyn Hittable + Send + Sync>> = objects
10        .iter()
11        .flat_map(|object| object.as_table().and_then(parse_object)) // TODO short circuit on None
12        .collect();
13    println!("Parsed {} objects", parsed_objects.len());
14    let mut world = World::new();
15    for object in parsed_objects {
16        world.add_object(object);
17    }
18    Some(world)
19}
20
21fn parse_object(object_description: &Table) -> Option<Box<dyn Hittable + Send + Sync>> {
22    let object_type = object_description.get("type")?.as_str()?;
23    match object_type {
24        "sphere" => {
25            let position = parse_position(object_description.get("position")?.as_table()?)?;
26            let radius = object_description.get("radius")?.as_float()?;
27            let material = parse_material(object_description.get("material")?.as_table()?)?;
28            let sphere = Sphere::new(position, radius, material);
29            Some(Box::new(sphere))
30        }
31        _ => None,
32    }
33}
34
35fn parse_material(material_description: &Table) -> Option<Box<dyn Material>> {
36    let material_type = material_description.get("type")?.as_str()?;
37    match material_type {
38        "lambertian" => parse_lambertian(material_description),
39        "metal" => parse_metal(material_description),
40        _ => None,
41    }
42}
43
44fn parse_position(position_description: &Table) -> Option<Vec3> {
45    let x = position_description.get("x")?.as_float()?;
46    let y = position_description.get("y")?.as_float()?;
47    let z = position_description.get("z")?.as_float()?;
48    Some(Vec3::new([x, y, z]))
49}
50
51fn parse_lambertian(material_description: &Table) -> Option<Box<dyn Material>> {
52    let colour = parse_colour(material_description.get("colour")?.as_table()?)?;
53    let lambertian_material = Lambertian::new(colour);
54    Some(Box::new(lambertian_material))
55}
56
57fn parse_metal(material_description: &Table) -> Option<Box<dyn Material>> {
58    let colour = parse_colour(material_description.get("colour")?.as_table()?)?;
59    let fuzz = material_description.get("fuzz")?.as_float()?;
60    let metal_material = Metal::new(colour, fuzz);
61    Some(Box::new(metal_material))
62}
63
64fn parse_colour(colour_description: &Table) -> Option<Colour> {
65    let r = colour_description.get("r")?.as_float()?;
66    let g = colour_description.get("g")?.as_float()?;
67    let b = colour_description.get("b")?.as_float()?;
68    Some(Colour::new(r, g, b))
69}