summaryrefslogtreecommitdiff
path: root/racer-tracer/src/scene.rs
diff options
context:
space:
mode:
authorSakarias Johansson <sakarias.johansson@goodbyekansas.com>2023-01-18 21:01:24 +0100
committerSakarias Johansson <sakarias.johansson@goodbyekansas.com>2023-01-18 21:01:24 +0100
commit2abf48d9ce2968f7e999a9e0faf6d0ebfa752c7c (patch)
tree3b58470a7f382634187ba155a1ed398595247a35 /racer-tracer/src/scene.rs
parent38e9bf130fc1075d576626f0c2ade582ccc3c57f (diff)
downloadracer-tracer-2abf48d9ce2968f7e999a9e0faf6d0ebfa752c7c.tar.gz
racer-tracer-2abf48d9ce2968f7e999a9e0faf6d0ebfa752c7c.tar.xz
racer-tracer-2abf48d9ce2968f7e999a9e0faf6d0ebfa752c7c.zip
🏙️ Add support for reading scene from file
Diffstat (limited to 'racer-tracer/src/scene.rs')
-rw-r--r--racer-tracer/src/scene.rs100
1 files changed, 99 insertions, 1 deletions
diff --git a/racer-tracer/src/scene.rs b/racer-tracer/src/scene.rs
index c5e76da..91fa252 100644
--- a/racer-tracer/src/scene.rs
+++ b/racer-tracer/src/scene.rs
@@ -1,4 +1,14 @@
-use crate::geometry::Hittable;
+use std::{collections::HashMap, path::Path, sync::Arc};
+
+use config::File;
+use serde::Deserialize;
+
+use crate::{
+ error::TracerError,
+ geometry::{sphere::Sphere, Hittable},
+ material::{dialectric::Dialectric, lambertian::Lambertian, metal::Metal, SharedMaterial},
+ vec3::{Color, Vec3},
+};
pub struct Scene {
objects: Vec<Box<dyn Hittable>>,
@@ -14,6 +24,10 @@ impl Scene {
pub fn add(&mut self, hittable: Box<dyn Hittable>) {
self.objects.push(hittable);
}
+
+ pub fn from_file<P: AsRef<Path>>(file: P) -> Result<Self, TracerError> {
+ SceneData::from_file(file)?.try_into()
+ }
}
impl Hittable for Scene {
@@ -36,3 +50,87 @@ impl Hittable for Scene {
rec
}
}
+
+#[derive(Debug, Deserialize)]
+enum MaterialData {
+ Lambertian { color: Color },
+ Metal { color: Color, fuzz: f64 },
+ Dialectric { refraction_index: f64 },
+}
+
+#[derive(Debug, Deserialize)]
+enum GeometryData {
+ Sphere {
+ pos: Vec3,
+ radius: f64,
+ material: String,
+ },
+}
+
+#[derive(Deserialize)]
+struct SceneData {
+ materials: HashMap<String, MaterialData>,
+ geometry: Vec<GeometryData>,
+}
+
+impl SceneData {
+ pub fn from_file<P: AsRef<Path>>(file: P) -> Result<Self, TracerError> {
+ config::Config::builder()
+ .add_source(File::from(file.as_ref()))
+ .build()
+ .map_err(|e| {
+ TracerError::Configuration(
+ file.as_ref().to_string_lossy().into_owned(),
+ e.to_string(),
+ )
+ })?
+ .try_deserialize()
+ .map_err(|e| {
+ TracerError::Configuration(
+ file.as_ref().to_string_lossy().into_owned(),
+ e.to_string(),
+ )
+ })
+ }
+}
+
+impl TryInto<Scene> for SceneData {
+ type Error = TracerError;
+ fn try_into(self) -> Result<Scene, TracerError> {
+ let mut materials: HashMap<String, SharedMaterial> = HashMap::new();
+ self.materials
+ .into_iter()
+ .for_each(|(id, material)| match material {
+ MaterialData::Lambertian { color } => {
+ materials.insert(id, Arc::new(Box::new(Lambertian::new(color))));
+ }
+ MaterialData::Metal { color, fuzz } => {
+ materials.insert(id, Arc::new(Box::new(Metal::new(color, fuzz))));
+ }
+ MaterialData::Dialectric { refraction_index } => {
+ materials.insert(id, Arc::new(Box::new(Dialectric::new(refraction_index))));
+ }
+ });
+
+ let geometry: Vec<Box<dyn Hittable>> = self
+ .geometry
+ .into_iter()
+ .map(|geo| match geo {
+ GeometryData::Sphere {
+ pos,
+ radius,
+ material,
+ } => materials
+ .get(&material)
+ .ok_or(TracerError::UnknownMaterial(material))
+ .map(|mat| {
+ let apa: Box<dyn Hittable> =
+ Box::new(Sphere::new(pos, radius, Arc::clone(mat)));
+ apa
+ }),
+ })
+ .collect::<Result<Vec<Box<dyn Hittable>>, TracerError>>()?;
+
+ Ok(Scene { objects: geometry })
+ }
+}