Parsing more stuff.
This commit is contained in:
parent
96a24fcc28
commit
8fcf815dbf
3 changed files with 253 additions and 17 deletions
|
|
@ -9,6 +9,11 @@ pub struct AffineTransform {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AffineTransform {
|
impl AffineTransform {
|
||||||
|
pub fn new(mat: [[Float; 4]; 3]) -> Option<Self> {
|
||||||
|
let inv = Self::invert(mat)?;
|
||||||
|
Some(Self { mat, inv })
|
||||||
|
}
|
||||||
|
|
||||||
pub fn identity() -> Self {
|
pub fn identity() -> Self {
|
||||||
Self {
|
Self {
|
||||||
mat: [
|
mat: [
|
||||||
|
|
@ -77,7 +82,7 @@ impl AffineTransform {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn look_at(pos: Pos3, look: Pos3, up: Dir3) -> Self {
|
pub fn look_at(pos: Pos3, look: Pos3, up: Dir3) -> Option<Self> {
|
||||||
let dir = (look - pos).normalize();
|
let dir = (look - pos).normalize();
|
||||||
let right = Dir3::cross(up.normalize(), dir).normalize();
|
let right = Dir3::cross(up.normalize(), dir).normalize();
|
||||||
let new_up = Dir3::cross(dir, right);
|
let new_up = Dir3::cross(dir, right);
|
||||||
|
|
@ -88,14 +93,55 @@ impl AffineTransform {
|
||||||
[right.z(), new_up.z(), dir.z(), pos.z()],
|
[right.z(), new_up.z(), dir.z(), pos.z()],
|
||||||
];
|
];
|
||||||
|
|
||||||
let inv = Self::invert(mat);
|
Self::new(mat)
|
||||||
|
|
||||||
Self { mat, inv }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn invert(mat: [[Float; 4]; 3]) -> [[Float; 3]; 3] {
|
fn invert(mat: [[Float; 4]; 3]) -> Option<[[Float; 3]; 3]> {
|
||||||
eprintln!("Matrix inversion not implemented");
|
// using cramers rule
|
||||||
[[0.0; 3]; 3]
|
let adj = |y, x| {
|
||||||
|
let cofactor_indices = |p| match p {
|
||||||
|
0 => (1, 2),
|
||||||
|
1 => (0, 2),
|
||||||
|
2 => (0, 1),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
let (y1, y2) = cofactor_indices(y);
|
||||||
|
let (x1, x2) = cofactor_indices(x);
|
||||||
|
|
||||||
|
(if (x + y) % 2 == 0 { 1.0 } else { -1.0 })
|
||||||
|
* (mat[y1][x1] * mat[y2][x2] - mat[y1][x2] * mat[y2][x1])
|
||||||
|
};
|
||||||
|
|
||||||
|
let det = mat[0][0] * mat[1][1] * mat[2][2]
|
||||||
|
+ mat[0][1] * mat[1][2] * mat[2][0]
|
||||||
|
+ mat[0][2] * mat[1][0] * mat[2][1]
|
||||||
|
- mat[0][2] * mat[1][1] * mat[2][0]
|
||||||
|
- mat[0][1] * mat[1][0] * mat[2][2]
|
||||||
|
- mat[0][0] * mat[1][2] * mat[2][1];
|
||||||
|
|
||||||
|
if det != 0.0 {
|
||||||
|
let det_frac = 1.0 / det;
|
||||||
|
|
||||||
|
Some([
|
||||||
|
[
|
||||||
|
adj(0, 0) * det_frac,
|
||||||
|
adj(1, 0) * det_frac,
|
||||||
|
adj(2, 0) * det_frac,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
adj(0, 1) * det_frac,
|
||||||
|
adj(1, 1) * det_frac,
|
||||||
|
adj(2, 1) * det_frac,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
adj(0, 2) * det_frac,
|
||||||
|
adj(1, 2) * det_frac,
|
||||||
|
adj(2, 2) * det_frac,
|
||||||
|
],
|
||||||
|
])
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn transform_pos(&self, pos: Pos3) -> Pos3 {
|
pub fn transform_pos(&self, pos: Pos3) -> Pos3 {
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,9 @@ struct Args {
|
||||||
fn main() -> Result<(), miette::Error> {
|
fn main() -> Result<(), miette::Error> {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
|
||||||
dbg!(parse_pbrt_v4(args.filename)?);
|
let t = parse_pbrt_v4(args.filename)?;
|
||||||
|
|
||||||
|
// dbg!(t);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,7 @@ enum Statement {
|
||||||
ConcatTransform(AffineTransform),
|
ConcatTransform(AffineTransform),
|
||||||
Shape(ShapeType),
|
Shape(ShapeType),
|
||||||
Unknown(String, Vec<String>),
|
Unknown(String, Vec<String>),
|
||||||
|
Transform(AffineTransform),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_look_at(iter: &mut impl Iterator<Item = Result<String>>) -> Result<Statement> {
|
fn parse_look_at(iter: &mut impl Iterator<Item = Result<String>>) -> Result<Statement> {
|
||||||
|
|
@ -165,9 +166,10 @@ fn parse_look_at(iter: &mut impl Iterator<Item = Result<String>>) -> Result<Stat
|
||||||
.into_diagnostic()?,
|
.into_diagnostic()?,
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(Statement::ConcatTransform(AffineTransform::look_at(
|
Ok(Statement::ConcatTransform(
|
||||||
eye, look_at, up,
|
AffineTransform::look_at(eye, look_at, up)
|
||||||
)))
|
.ok_or(miette!("Unable to calculate inverse of matrix"))?,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_parameter<I, T>(iter: &mut Peekable<Tokenizer<I>>) -> Result<T>
|
fn parse_parameter<I, T>(iter: &mut Peekable<Tokenizer<I>>) -> Result<T>
|
||||||
|
|
@ -383,7 +385,7 @@ fn parse_shape<I: Iterator<Item = Result<char>>>(
|
||||||
"\"normal N\"" => {
|
"\"normal N\"" => {
|
||||||
parse_list_3(iter, &mut n, Dir3::new)?;
|
parse_list_3(iter, &mut n, Dir3::new)?;
|
||||||
}
|
}
|
||||||
"\"vector N\"" => {
|
"\"vector S\"" => {
|
||||||
parse_list_3(iter, &mut s, Dir3::new)?;
|
parse_list_3(iter, &mut s, Dir3::new)?;
|
||||||
}
|
}
|
||||||
"\"point2 uv\"" => {
|
"\"point2 uv\"" => {
|
||||||
|
|
@ -427,8 +429,9 @@ fn parse_shape<I: Iterator<Item = Result<char>>>(
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
"\"bilinearmesh\"" => {
|
"\"bilinearmesh\"" => {
|
||||||
|
let mut indices = Vec::new();
|
||||||
let mut p = Vec::new();
|
let mut p = Vec::new();
|
||||||
|
let mut n = Vec::new();
|
||||||
let mut uv = Vec::new();
|
let mut uv = Vec::new();
|
||||||
|
|
||||||
while let Some(q) = iter
|
while let Some(q) = iter
|
||||||
|
|
@ -436,21 +439,50 @@ fn parse_shape<I: Iterator<Item = Result<char>>>(
|
||||||
.transpose()?
|
.transpose()?
|
||||||
{
|
{
|
||||||
match q.as_str() {
|
match q.as_str() {
|
||||||
|
"\"integer indices\"" => {
|
||||||
|
parse_list(iter, &mut indices)?;
|
||||||
|
}
|
||||||
"\"point3 P\"" => {
|
"\"point3 P\"" => {
|
||||||
parse_list_3(iter, &mut p, Pos3::new)?;
|
parse_list_3(iter, &mut p, Pos3::new)?;
|
||||||
}
|
}
|
||||||
"\"point2 uv\"" => {
|
"\"point2 uv\"" => {
|
||||||
parse_list_2(iter, &mut uv, |u, v| [u, v])?;
|
parse_list_2(iter, &mut uv, |u, v| [u, v])?;
|
||||||
}
|
}
|
||||||
|
"\"vector N\"" => {
|
||||||
|
parse_list_3(iter, &mut n, Dir3::new)?;
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
bail!("unknown argument {}", q)
|
bail!("unknown argument {}", q)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if p.len() < 4 {
|
||||||
|
bail!("At least 3 points required.")
|
||||||
|
}
|
||||||
|
if indices.is_empty() && p.len() != 4 {
|
||||||
|
bail!("Indices required for trianglemesh with more than 3 points.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if indices.len() % 4 != 0 {
|
||||||
|
bail!(
|
||||||
|
"number of indices must be divisible by 4. num indices: {}",
|
||||||
|
indices.len()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !n.is_empty() && n.len() != p.len() {
|
||||||
|
bail!("Number of normals not equal to number of positions.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !uv.is_empty() && uv.len() != p.len() {
|
||||||
|
bail!("Number of uvs not equal to number of positions.")
|
||||||
|
}
|
||||||
Ok(Statement::Shape(ShapeType::BilinearMesh {
|
Ok(Statement::Shape(ShapeType::BilinearMesh {
|
||||||
p: [p[0], p[1], p[2], p[3]],
|
indices,
|
||||||
uv: [uv[0], uv[1], uv[2], uv[3]],
|
p,
|
||||||
|
n,
|
||||||
|
uv,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -494,6 +526,34 @@ fn parse_shape<I: Iterator<Item = Result<char>>>(
|
||||||
p,
|
p,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
"\"disk\"" => {
|
||||||
|
let mut height = 0.0;
|
||||||
|
let mut radius = 1.0;
|
||||||
|
let mut innerradius = 0.0;
|
||||||
|
let mut phimax = 360.0;
|
||||||
|
|
||||||
|
while let Some(q) = iter
|
||||||
|
.next_if(|p| p.as_ref().is_ok_and(|p| p.starts_with('"')))
|
||||||
|
.transpose()?
|
||||||
|
{
|
||||||
|
match q.as_str() {
|
||||||
|
"\"float height\"" => height = parse_parameter(iter)?,
|
||||||
|
"\"float radius\"" => radius = parse_parameter(iter)?,
|
||||||
|
"\"float innerradius\"" => innerradius = parse_parameter(iter)?,
|
||||||
|
"\"float phimax\"" => phimax = parse_parameter(iter)?,
|
||||||
|
_ => {
|
||||||
|
bail!("unknown argument {}", q)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Statement::Shape(ShapeType::Disk {
|
||||||
|
height,
|
||||||
|
radius,
|
||||||
|
innerradius,
|
||||||
|
phimax,
|
||||||
|
}))
|
||||||
|
}
|
||||||
_ => Err(miette!("Unknown shape {}", shape_type)),
|
_ => Err(miette!("Unknown shape {}", shape_type)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -517,7 +577,16 @@ impl<I: Iterator<Item = Result<char>>> Lexer<I> {
|
||||||
}
|
}
|
||||||
"LookAt" => Some(parse_look_at(&mut self.input)),
|
"LookAt" => Some(parse_look_at(&mut self.input)),
|
||||||
"Identity" => Some(Ok(Statement::ConcatTransform(AffineTransform::identity()))),
|
"Identity" => Some(Ok(Statement::ConcatTransform(AffineTransform::identity()))),
|
||||||
|
"Translate" => Some(parse_translate(&mut self.input)),
|
||||||
|
"Scale" => Some(parse_scale(&mut self.input)),
|
||||||
"Shape" => Some(parse_shape(&mut self.input)),
|
"Shape" => Some(parse_shape(&mut self.input)),
|
||||||
|
"Rotate" => Some(parse_rotate(&mut self.input)),
|
||||||
|
"Transform" => {
|
||||||
|
Some(parse_transform(&mut self.input).map(|a| Statement::Transform(a)))
|
||||||
|
}
|
||||||
|
"ConcatTransform" => {
|
||||||
|
Some(parse_transform(&mut self.input).map(|a| Statement::ConcatTransform(a)))
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
if s.chars().any(|c| !c.is_ascii_alphabetic()) {
|
if s.chars().any(|c| !c.is_ascii_alphabetic()) {
|
||||||
Some(Err(miette!("malformed identifier")))
|
Some(Err(miette!("malformed identifier")))
|
||||||
|
|
@ -544,6 +613,114 @@ impl<I: Iterator<Item = Result<char>>> Lexer<I> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_transform<I: Iterator<Item = Result<char>>>(
|
||||||
|
input: &mut Peekable<Tokenizer<I>>,
|
||||||
|
) -> Result<AffineTransform> {
|
||||||
|
if !input
|
||||||
|
.next()
|
||||||
|
.is_none_or(|p| p.is_ok_and(|p| p.as_str() == "["))
|
||||||
|
{
|
||||||
|
bail!("expected list.")
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut v = [0.0; 16];
|
||||||
|
|
||||||
|
for i in 0..16 {
|
||||||
|
v[i] = input
|
||||||
|
.next()
|
||||||
|
.ok_or(miette!("value expected"))??
|
||||||
|
.parse::<Float>()
|
||||||
|
.into_diagnostic()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !input
|
||||||
|
.next()
|
||||||
|
.is_none_or(|p| p.is_ok_and(|p| p.as_str() == "]"))
|
||||||
|
{
|
||||||
|
bail!("expected list end.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if v[3] != 0.0 || v[7] != 0.0 || v[11] != 0.0 || v[15] != 1.0 {
|
||||||
|
bail!("invalid transform entry")
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(AffineTransform::new([
|
||||||
|
[v[0], v[4], v[8], v[12]],
|
||||||
|
[v[1], v[5], v[9], v[13]],
|
||||||
|
[v[2], v[6], v[10], v[14]],
|
||||||
|
])
|
||||||
|
.ok_or(miette!("Unable to invert transformation"))?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_translate<I: Iterator<Item = Result<char>>>(
|
||||||
|
iter: &mut Peekable<Tokenizer<I>>,
|
||||||
|
) -> Result<Statement> {
|
||||||
|
let pos = Pos3::new(
|
||||||
|
iter.next()
|
||||||
|
.ok_or(miette!("missing argument"))??
|
||||||
|
.parse()
|
||||||
|
.into_diagnostic()?,
|
||||||
|
iter.next()
|
||||||
|
.ok_or(miette!("missing argument"))??
|
||||||
|
.parse()
|
||||||
|
.into_diagnostic()?,
|
||||||
|
iter.next()
|
||||||
|
.ok_or(miette!("missing argument"))??
|
||||||
|
.parse()
|
||||||
|
.into_diagnostic()?,
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(Statement::ConcatTransform(AffineTransform::translation(
|
||||||
|
pos,
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_scale<I: Iterator<Item = Result<char>>>(
|
||||||
|
iter: &mut Peekable<Tokenizer<I>>,
|
||||||
|
) -> Result<Statement> {
|
||||||
|
Ok(Statement::ConcatTransform(AffineTransform::scale(
|
||||||
|
iter.next()
|
||||||
|
.ok_or(miette!("missing argument"))??
|
||||||
|
.parse()
|
||||||
|
.into_diagnostic()?,
|
||||||
|
iter.next()
|
||||||
|
.ok_or(miette!("missing argument"))??
|
||||||
|
.parse()
|
||||||
|
.into_diagnostic()?,
|
||||||
|
iter.next()
|
||||||
|
.ok_or(miette!("missing argument"))??
|
||||||
|
.parse()
|
||||||
|
.into_diagnostic()?,
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_rotate<I: Iterator<Item = Result<char>>>(
|
||||||
|
iter: &mut Peekable<Tokenizer<I>>,
|
||||||
|
) -> Result<Statement> {
|
||||||
|
let angle = iter
|
||||||
|
.next()
|
||||||
|
.ok_or(miette!("missing argument"))??
|
||||||
|
.parse()
|
||||||
|
.into_diagnostic()?;
|
||||||
|
let dir = Dir3::new(
|
||||||
|
iter.next()
|
||||||
|
.ok_or(miette!("missing argument"))??
|
||||||
|
.parse()
|
||||||
|
.into_diagnostic()?,
|
||||||
|
iter.next()
|
||||||
|
.ok_or(miette!("missing argument"))??
|
||||||
|
.parse()
|
||||||
|
.into_diagnostic()?,
|
||||||
|
iter.next()
|
||||||
|
.ok_or(miette!("missing argument"))??
|
||||||
|
.parse()
|
||||||
|
.into_diagnostic()?,
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(Statement::ConcatTransform(AffineTransform::rotation(
|
||||||
|
angle, dir,
|
||||||
|
)))
|
||||||
|
}
|
||||||
struct BytesToChar<I> {
|
struct BytesToChar<I> {
|
||||||
iter: I,
|
iter: I,
|
||||||
}
|
}
|
||||||
|
|
@ -623,14 +800,22 @@ enum ShapeType {
|
||||||
uv: Vec<[Float; 2]>,
|
uv: Vec<[Float; 2]>,
|
||||||
},
|
},
|
||||||
BilinearMesh {
|
BilinearMesh {
|
||||||
p: [Pos3; 4],
|
indices: Vec<usize>,
|
||||||
uv: [[Float; 2]; 4],
|
p: Vec<Pos3>,
|
||||||
|
n: Vec<Dir3>,
|
||||||
|
uv: Vec<[Float; 2]>,
|
||||||
},
|
},
|
||||||
LoopSubDiv {
|
LoopSubDiv {
|
||||||
levels: u32,
|
levels: u32,
|
||||||
indices: Vec<usize>,
|
indices: Vec<usize>,
|
||||||
p: Vec<Pos3>,
|
p: Vec<Pos3>,
|
||||||
},
|
},
|
||||||
|
Disk {
|
||||||
|
height: f64,
|
||||||
|
radius: f64,
|
||||||
|
innerradius: f64,
|
||||||
|
phimax: f64,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -698,6 +883,9 @@ fn inner_parse_pbrt(
|
||||||
Statement::ConcatTransform(affine_transform) => {
|
Statement::ConcatTransform(affine_transform) => {
|
||||||
context.last_mut().ok_or(miette!(""))?.ctm *= affine_transform
|
context.last_mut().ok_or(miette!(""))?.ctm *= affine_transform
|
||||||
}
|
}
|
||||||
|
Statement::Transform(affine_transform) => {
|
||||||
|
context.last_mut().ok_or(miette!(""))?.ctm = dbg!(affine_transform)
|
||||||
|
}
|
||||||
Statement::Shape(shape_type) => {
|
Statement::Shape(shape_type) => {
|
||||||
pbrt.scene.shapes.push(Shape {
|
pbrt.scene.shapes.push(Shape {
|
||||||
ctm: context.last().unwrap().ctm,
|
ctm: context.last().unwrap().ctm,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue