bs_trace/trace/
description.rs1use 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)) .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}