Refactor with macros
This commit is contained in:
parent
00000540b4
commit
973e03df4d
1 changed files with 147 additions and 78 deletions
|
@ -1,15 +1,18 @@
|
||||||
use std::{fs::File, io::Read, path::Path};
|
use std::{fs::File, io::Read, path::Path, str::FromStr};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use itertools::Itertools;
|
||||||
|
use nalgebra::{Vector2, Vector3};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
image::Color,
|
||||||
scene::{
|
scene::{
|
||||||
cylinder::Cylinder,
|
cylinder::Cylinder,
|
||||||
data::{Attenuation, Light, LightKind, Material, Object},
|
data::{Attenuation, Light, LightKind, Material, Object},
|
||||||
sphere::Sphere,
|
sphere::Sphere,
|
||||||
Scene,
|
Scene,
|
||||||
},
|
},
|
||||||
Point,
|
Point, Vector,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::data::{DepthCueing, ObjectKind};
|
use super::data::{DepthCueing, ObjectKind};
|
||||||
|
@ -51,99 +54,114 @@ impl Scene {
|
||||||
}
|
}
|
||||||
// Do float parsing instead
|
// Do float parsing instead
|
||||||
else {
|
else {
|
||||||
let parts = parts
|
/// Shortcut for reading something from the iterator and converting it
|
||||||
.map(|s| s.parse::<f64>().map_err(|e| e.into()))
|
/// into the appropriate format
|
||||||
.collect::<Result<Vec<_>>>()?;
|
macro_rules! r {
|
||||||
|
($ty:ty) => {
|
||||||
|
<$ty>::construct(&mut parts, ())?
|
||||||
|
};
|
||||||
|
|
||||||
let read_vec3 = |start: usize| {
|
($ty:ty, $($ex:expr),* $(,)?) => {
|
||||||
ensure!(parts.len() >= start + 3, "Vec3 requires 3 components.");
|
<$ty>::construct(&mut parts, $($ex,)*)?
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Point::new(parts[start], parts[start + 1], parts[start + 2]))
|
/// Shortcut for getting material color
|
||||||
};
|
macro_rules! mat {
|
||||||
|
() => {
|
||||||
|
match material_color {
|
||||||
|
Some(v) => v,
|
||||||
|
None => {
|
||||||
|
bail!("Each sphere must be preceded by a `mtlcolor` line")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
match keyword {
|
match keyword {
|
||||||
"eye" => scene.eye_pos = read_vec3(0)?,
|
"eye" => scene.eye_pos = r!(Vector3<f64>),
|
||||||
"viewdir" => scene.view_dir = read_vec3(0)?,
|
"viewdir" => scene.view_dir = r!(Vector3<f64>),
|
||||||
"updir" => scene.up_dir = read_vec3(0)?,
|
"updir" => scene.up_dir = r!(Vector3<f64>),
|
||||||
|
|
||||||
"hfov" => scene.hfov = parts[0],
|
"hfov" => scene.hfov = r!(f64),
|
||||||
"bkgcolor" => scene.bkg_color = read_vec3(0)?,
|
"bkgcolor" => scene.bkg_color = r!(Color),
|
||||||
|
|
||||||
// light x y z w r g b
|
// light x y z w r g b
|
||||||
"light" => {
|
"light" => {
|
||||||
ensure!(parts.len() == 7, "Light requires 7 params");
|
let vec3 = r!(Vector3<f64>);
|
||||||
|
let w = r!(usize);
|
||||||
|
let color = r!(Color);
|
||||||
|
|
||||||
let kind = match parts[3] as usize {
|
let kind = match w as usize {
|
||||||
0 => LightKind::Directional {
|
0 => LightKind::Directional { direction: vec3 },
|
||||||
direction: read_vec3(0)?,
|
|
||||||
},
|
|
||||||
1 => LightKind::Point {
|
1 => LightKind::Point {
|
||||||
location: read_vec3(0)?,
|
location: vec3,
|
||||||
attenuation: None,
|
attenuation: None,
|
||||||
},
|
},
|
||||||
_ => bail!("Invalid w; must be either 0 or 1"),
|
_ => bail!("Invalid w; must be either 0 or 1"),
|
||||||
};
|
};
|
||||||
let light = Light {
|
|
||||||
kind,
|
let light = Light { kind, color };
|
||||||
color: read_vec3(4)?,
|
|
||||||
};
|
|
||||||
scene.lights.push(light);
|
scene.lights.push(light);
|
||||||
}
|
}
|
||||||
|
|
||||||
// attlight x y z w r g b c1 c2 c3
|
// attlight x y z w r g b c1 c2 c3
|
||||||
"attlight" => {
|
"attlight" => {
|
||||||
ensure!(parts.len() == 10, "Attenuated light requires 10 params");
|
let vec3 = r!(Vector3<f64>);
|
||||||
|
let w = r!(usize);
|
||||||
|
let color = r!(Color);
|
||||||
|
let c = r!(Vector3<f64>);
|
||||||
|
|
||||||
let kind = match parts[3] as usize {
|
let kind = match w as usize {
|
||||||
// TODO: Is this even defined? Pending TA answer
|
0 => LightKind::Directional { direction: vec3 },
|
||||||
0 => LightKind::Directional {
|
|
||||||
direction: read_vec3(0)?,
|
|
||||||
},
|
|
||||||
1 => LightKind::Point {
|
1 => LightKind::Point {
|
||||||
location: read_vec3(0)?,
|
location: vec3,
|
||||||
attenuation: Some(Attenuation {
|
attenuation: Some(Attenuation {
|
||||||
c1: parts[7],
|
c1: c.x,
|
||||||
c2: parts[8],
|
c2: c.y,
|
||||||
c3: parts[9],
|
c3: c.z,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
_ => bail!("Invalid w; must be either 0 or 1"),
|
_ => bail!("Invalid w; must be either 0 or 1"),
|
||||||
};
|
};
|
||||||
let light = Light {
|
|
||||||
kind,
|
let light = Light { kind, color };
|
||||||
color: read_vec3(4)?,
|
|
||||||
};
|
|
||||||
scene.lights.push(light);
|
scene.lights.push(light);
|
||||||
}
|
}
|
||||||
|
|
||||||
// depthcueing dcr dcg dcb amax amin distmax distmin
|
// depthcueing dcr dcg dcb amax amin distmax distmin
|
||||||
"depthcueing" => {
|
"depthcueing" => {
|
||||||
ensure!(parts.len() == 7, "Depth cueing requires 7 params");
|
let color = r!(Color);
|
||||||
|
let a_max = r!(f64);
|
||||||
|
let a_min = r!(f64);
|
||||||
|
let dist_max = r!(f64);
|
||||||
|
let dist_min = r!(f64);
|
||||||
|
|
||||||
let color = read_vec3(0)?;
|
|
||||||
scene.depth_cueing = DepthCueing {
|
scene.depth_cueing = DepthCueing {
|
||||||
color,
|
color,
|
||||||
a_max: parts[3],
|
a_max,
|
||||||
a_min: parts[4],
|
a_min,
|
||||||
dist_max: parts[5],
|
dist_max,
|
||||||
dist_min: parts[6],
|
dist_min,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// mtlcolor Odr Odg Odb Osr Osg Osb ka kd ks n
|
// mtlcolor Odr Odg Odb Osr Osg Osb ka kd ks n
|
||||||
"mtlcolor" => {
|
"mtlcolor" => {
|
||||||
ensure!(parts.len() == 10, "Material color requires 10 params");
|
let diffuse_color = r!(Color);
|
||||||
|
let specular_color = r!(Color);
|
||||||
let diffuse_color = read_vec3(0)?;
|
let k_a = r!(f64);
|
||||||
let specular_color = read_vec3(3)?;
|
let k_d = r!(f64);
|
||||||
|
let k_s = r!(f64);
|
||||||
|
let exponent = r!(f64);
|
||||||
|
|
||||||
let material = Material {
|
let material = Material {
|
||||||
diffuse_color,
|
diffuse_color,
|
||||||
specular_color,
|
specular_color,
|
||||||
k_a: parts[6],
|
k_a,
|
||||||
k_d: parts[7],
|
k_d,
|
||||||
k_s: parts[8],
|
k_s,
|
||||||
exponent: parts[9],
|
exponent,
|
||||||
};
|
};
|
||||||
|
|
||||||
let idx = scene.materials.len();
|
let idx = scene.materials.len();
|
||||||
|
@ -151,33 +169,32 @@ impl Scene {
|
||||||
scene.materials.push(material);
|
scene.materials.push(material);
|
||||||
}
|
}
|
||||||
|
|
||||||
"sphere" => scene.objects.push(Object {
|
"sphere" => {
|
||||||
kind: ObjectKind::Sphere(Sphere {
|
let center = r!(Point);
|
||||||
center: read_vec3(0)?,
|
let radius = r!(f64);
|
||||||
radius: parts[3],
|
|
||||||
}),
|
|
||||||
material: match material_color {
|
|
||||||
Some(v) => v,
|
|
||||||
None => {
|
|
||||||
bail!("Each sphere must be preceded by a `mtlcolor` line")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
|
|
||||||
"cylinder" => scene.objects.push(Object {
|
scene.objects.push(Object {
|
||||||
kind: ObjectKind::Cylinder(Cylinder {
|
kind: ObjectKind::Sphere(Sphere { center, radius }),
|
||||||
center: read_vec3(0)?,
|
material: mat!(),
|
||||||
direction: read_vec3(3)?,
|
});
|
||||||
radius: parts[6],
|
}
|
||||||
length: parts[7],
|
|
||||||
}),
|
"cylinder" => {
|
||||||
material: match material_color {
|
let center = r!(Point);
|
||||||
Some(v) => v,
|
let direction = r!(Vector);
|
||||||
None => {
|
let radius = r!(f64);
|
||||||
bail!("Each sphere must be preceded by a `mtlcolor` line")
|
let length = r!(f64);
|
||||||
}
|
|
||||||
},
|
scene.objects.push(Object {
|
||||||
}),
|
kind: ObjectKind::Cylinder(Cylinder {
|
||||||
|
center,
|
||||||
|
direction,
|
||||||
|
radius,
|
||||||
|
length,
|
||||||
|
}),
|
||||||
|
material: mat!(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
_ => bail!("Unknown keyword {keyword}"),
|
_ => bail!("Unknown keyword {keyword}"),
|
||||||
}
|
}
|
||||||
|
@ -187,3 +204,55 @@ impl Scene {
|
||||||
Ok(scene)
|
Ok(scene)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait Construct: Sized {
|
||||||
|
type Args;
|
||||||
|
|
||||||
|
/// Construct an element of this type from an iterator over strings.
|
||||||
|
fn construct<'a, I>(it: &mut I, args: Self::Args) -> Result<Self>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = &'a str>;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_construct {
|
||||||
|
($ty:ty) => {
|
||||||
|
impl Construct for $ty {
|
||||||
|
type Args = ();
|
||||||
|
|
||||||
|
fn construct<'a, I>(it: &mut I, args: Self::Args) -> Result<Self>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = &'a str>,
|
||||||
|
{
|
||||||
|
let item = match it.next() {
|
||||||
|
Some(v) => v,
|
||||||
|
None => bail!("Ran out of items"),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(item.parse()?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_construct!(f64);
|
||||||
|
impl_construct!(usize);
|
||||||
|
|
||||||
|
impl Construct for Vector3<f64> {
|
||||||
|
type Args = ();
|
||||||
|
|
||||||
|
fn construct<'a, I>(it: &mut I, args: Self::Args) -> Result<Self>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = &'a str>,
|
||||||
|
{
|
||||||
|
let (x, y, z) = match it.next_tuple() {
|
||||||
|
Some(v) => v,
|
||||||
|
None => bail!("Expected 3 values"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let x: f64 = x.parse()?;
|
||||||
|
let y: f64 = y.parse()?;
|
||||||
|
let z: f64 = z.parse()?;
|
||||||
|
|
||||||
|
Ok(Vector3::new(x, y, z))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue