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 {
|
||||
pub fn new(mat: [[Float; 4]; 3]) -> Option<Self> {
|
||||
let inv = Self::invert(mat)?;
|
||||
Some(Self { mat, inv })
|
||||
}
|
||||
|
||||
pub fn identity() -> Self {
|
||||
Self {
|
||||
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 right = Dir3::cross(up.normalize(), dir).normalize();
|
||||
let new_up = Dir3::cross(dir, right);
|
||||
|
|
@ -88,14 +93,55 @@ impl AffineTransform {
|
|||
[right.z(), new_up.z(), dir.z(), pos.z()],
|
||||
];
|
||||
|
||||
let inv = Self::invert(mat);
|
||||
|
||||
Self { mat, inv }
|
||||
Self::new(mat)
|
||||
}
|
||||
|
||||
fn invert(mat: [[Float; 4]; 3]) -> [[Float; 3]; 3] {
|
||||
eprintln!("Matrix inversion not implemented");
|
||||
[[0.0; 3]; 3]
|
||||
fn invert(mat: [[Float; 4]; 3]) -> Option<[[Float; 3]; 3]> {
|
||||
// using cramers rule
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,9 @@ struct Args {
|
|||
fn main() -> Result<(), miette::Error> {
|
||||
let args = Args::parse();
|
||||
|
||||
dbg!(parse_pbrt_v4(args.filename)?);
|
||||
let t = parse_pbrt_v4(args.filename)?;
|
||||
|
||||
// dbg!(t);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ enum Statement {
|
|||
ConcatTransform(AffineTransform),
|
||||
Shape(ShapeType),
|
||||
Unknown(String, Vec<String>),
|
||||
Transform(AffineTransform),
|
||||
}
|
||||
|
||||
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()?,
|
||||
);
|
||||
|
||||
Ok(Statement::ConcatTransform(AffineTransform::look_at(
|
||||
eye, look_at, up,
|
||||
)))
|
||||
Ok(Statement::ConcatTransform(
|
||||
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>
|
||||
|
|
@ -383,7 +385,7 @@ fn parse_shape<I: Iterator<Item = Result<char>>>(
|
|||
"\"normal N\"" => {
|
||||
parse_list_3(iter, &mut n, Dir3::new)?;
|
||||
}
|
||||
"\"vector N\"" => {
|
||||
"\"vector S\"" => {
|
||||
parse_list_3(iter, &mut s, Dir3::new)?;
|
||||
}
|
||||
"\"point2 uv\"" => {
|
||||
|
|
@ -427,8 +429,9 @@ fn parse_shape<I: Iterator<Item = Result<char>>>(
|
|||
}))
|
||||
}
|
||||
"\"bilinearmesh\"" => {
|
||||
let mut indices = Vec::new();
|
||||
let mut p = Vec::new();
|
||||
|
||||
let mut n = Vec::new();
|
||||
let mut uv = Vec::new();
|
||||
|
||||
while let Some(q) = iter
|
||||
|
|
@ -436,21 +439,50 @@ fn parse_shape<I: Iterator<Item = Result<char>>>(
|
|||
.transpose()?
|
||||
{
|
||||
match q.as_str() {
|
||||
"\"integer indices\"" => {
|
||||
parse_list(iter, &mut indices)?;
|
||||
}
|
||||
"\"point3 P\"" => {
|
||||
parse_list_3(iter, &mut p, Pos3::new)?;
|
||||
}
|
||||
"\"point2 uv\"" => {
|
||||
parse_list_2(iter, &mut uv, |u, v| [u, v])?;
|
||||
}
|
||||
"\"vector N\"" => {
|
||||
parse_list_3(iter, &mut n, Dir3::new)?;
|
||||
}
|
||||
_ => {
|
||||
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 {
|
||||
p: [p[0], p[1], p[2], p[3]],
|
||||
uv: [uv[0], uv[1], uv[2], uv[3]],
|
||||
indices,
|
||||
p,
|
||||
n,
|
||||
uv,
|
||||
}))
|
||||
}
|
||||
|
||||
|
|
@ -494,6 +526,34 @@ fn parse_shape<I: Iterator<Item = Result<char>>>(
|
|||
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)),
|
||||
}
|
||||
}
|
||||
|
|
@ -517,7 +577,16 @@ impl<I: Iterator<Item = Result<char>>> Lexer<I> {
|
|||
}
|
||||
"LookAt" => Some(parse_look_at(&mut self.input)),
|
||||
"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)),
|
||||
"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()) {
|
||||
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> {
|
||||
iter: I,
|
||||
}
|
||||
|
|
@ -623,14 +800,22 @@ enum ShapeType {
|
|||
uv: Vec<[Float; 2]>,
|
||||
},
|
||||
BilinearMesh {
|
||||
p: [Pos3; 4],
|
||||
uv: [[Float; 2]; 4],
|
||||
indices: Vec<usize>,
|
||||
p: Vec<Pos3>,
|
||||
n: Vec<Dir3>,
|
||||
uv: Vec<[Float; 2]>,
|
||||
},
|
||||
LoopSubDiv {
|
||||
levels: u32,
|
||||
indices: Vec<usize>,
|
||||
p: Vec<Pos3>,
|
||||
},
|
||||
Disk {
|
||||
height: f64,
|
||||
radius: f64,
|
||||
innerradius: f64,
|
||||
phimax: f64,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -698,6 +883,9 @@ fn inner_parse_pbrt(
|
|||
Statement::ConcatTransform(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) => {
|
||||
pbrt.scene.shapes.push(Shape {
|
||||
ctm: context.last().unwrap().ctm,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue