diff options
Diffstat (limited to 'racer-tracer/src/scene')
| -rw-r--r-- | racer-tracer/src/scene/none.rs | 15 | ||||
| -rw-r--r-- | racer-tracer/src/scene/random.rs | 87 | ||||
| -rw-r--r-- | racer-tracer/src/scene/yml.rs | 116 |
3 files changed, 218 insertions, 0 deletions
diff --git a/racer-tracer/src/scene/none.rs b/racer-tracer/src/scene/none.rs new file mode 100644 index 0000000..2aed105 --- /dev/null +++ b/racer-tracer/src/scene/none.rs @@ -0,0 +1,15 @@ +use crate::{error::TracerError, scene::SceneLoader}; + +pub struct NoneLoader {} + +impl NoneLoader { + pub fn new() -> Self { + Self {} + } +} + +impl SceneLoader for NoneLoader { + fn load(&self) -> Result<Vec<Box<dyn crate::geometry::Hittable>>, TracerError> { + Ok(Vec::new()) + } +} diff --git a/racer-tracer/src/scene/random.rs b/racer-tracer/src/scene/random.rs new file mode 100644 index 0000000..ddbcfc1 --- /dev/null +++ b/racer-tracer/src/scene/random.rs @@ -0,0 +1,87 @@ +use std::sync::Arc; + +use crate::{ + error::TracerError, + geometry::{sphere::Sphere, Hittable}, + material::{dialectric::Dialectric, lambertian::Lambertian, metal::Metal, SharedMaterial}, + scene::SceneLoader, + util::{random_double, random_double_range}, + vec3::{Color, Vec3}, +}; + +pub struct Random {} + +impl Random { + pub fn new() -> Self { + Self {} + } +} + +impl SceneLoader for Random { + fn load(&self) -> Result<Vec<Box<dyn crate::geometry::Hittable>>, TracerError> { + let mut geometry: Vec<Box<dyn Hittable>> = Vec::new(); + let ground_material: SharedMaterial = + Arc::new(Box::new(Lambertian::new(Color::new(0.5, 0.5, 0.5)))); + geometry.push(Box::new(Sphere::new( + Vec3::new(0.0, -1000.0, 0.0), + 1000.0, + ground_material, + ))); + + for a in -11..11 { + for b in -11..11 { + let choose_mat = random_double(); + let center = Vec3::new( + a as f64 + 0.9 * random_double(), + 0.2, + b as f64 + 0.9 * random_double(), + ); + + if (center - Vec3::new(4.0, 0.2, 0.0)).length() > 0.9 { + if choose_mat < 0.8 { + // diffuse + let albedo = Color::random() * Color::random(); + let mat: SharedMaterial = Arc::new(Box::new(Lambertian::new(albedo))); + geometry.push(Box::new(Sphere::new(center, 0.2, mat))); + } else if choose_mat > 0.95 { + // metal + let albedo = Color::random_range(0.5, 1.0); + let fuzz = random_double_range(0.0, 0.5); + let mat: SharedMaterial = Arc::new(Box::new(Metal::new(albedo, fuzz))); + geometry.push(Box::new(Sphere::new(center, 0.2, mat))); + } else { + // glass + let mat: SharedMaterial = Arc::new(Box::new(Dialectric::new(1.5))); + geometry.push(Box::new(Sphere::new(center, 0.2, mat))); + } + } + } + } + + let dial_mat: SharedMaterial = Arc::new(Box::new(Dialectric::new(1.5))); + geometry.push(Box::new(Sphere::new( + Vec3::new(0.0, 1.0, 0.0), + 1.0, + dial_mat, + ))); + + let lamb_mat: SharedMaterial = + Arc::new(Box::new(Lambertian::new(Color::new(0.4, 0.2, 0.1)))); + geometry.push(Box::new(Sphere::new( + Vec3::new(-4.0, 1.0, 0.0), + 1.0, + lamb_mat, + ))); + + let metal_mat: SharedMaterial = + Arc::new(Box::new(Metal::new(Color::new(0.7, 0.6, 0.5), 0.0))); + + geometry.push(Box::new(Sphere::new( + Vec3::new(4.0, 1.0, 0.0), + 1.0, + metal_mat, + ))); + + Ok(geometry) + } +} diff --git a/racer-tracer/src/scene/yml.rs b/racer-tracer/src/scene/yml.rs new file mode 100644 index 0000000..3e69786 --- /dev/null +++ b/racer-tracer/src/scene/yml.rs @@ -0,0 +1,116 @@ +use std::{ + collections::HashMap, + path::{Path, PathBuf}, + sync::Arc, +}; + +use serde::Deserialize; + +use crate::{ + error::TracerError, + geometry::{sphere::Sphere, Hittable}, + material::{dialectric::Dialectric, lambertian::Lambertian, metal::Metal, SharedMaterial}, + scene::SceneLoader, + vec3::{Color, Vec3}, +}; + +use config::File; + +pub struct YmlLoader { + path: PathBuf, +} + +impl YmlLoader { + pub fn new(path: PathBuf) -> Self { + Self { path } + } +} + +impl SceneLoader for YmlLoader { + fn load(&self) -> Result<Vec<Box<dyn crate::geometry::Hittable>>, TracerError> { + let datta = SceneData::from_file(PathBuf::from(&self.path))?; + datta.try_into() + } +} + +#[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(), + dbg!(e).to_string(), + ) + })? + .try_deserialize() + .map_err(|e| { + TracerError::Configuration( + file.as_ref().to_string_lossy().into_owned(), + dbg!(e).to_string(), + ) + }) + } +} + +impl TryInto<Vec<Box<dyn Hittable>>> for SceneData { + type Error = TracerError; + fn try_into(self) -> Result<Vec<Box<dyn Hittable>>, 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| { + Box::new(Sphere::new(pos, radius, Arc::clone(mat))) as Box<dyn Hittable> + }), + }) + .collect::<Result<Vec<Box<dyn Hittable>>, TracerError>>()?; + + Ok(geometry) + } +} |
