This allows the error messages to be more informative by including dynamically determined information. Also made a utility function for ensuring that nodes get closed.
178 lines
5.2 KiB
Rust
178 lines
5.2 KiB
Rust
#![allow(dead_code)]
|
|
|
|
use std::{io::BufRead, result::Result};
|
|
|
|
use nom::{sequence::tuple, IResult};
|
|
|
|
use kioku::Arena;
|
|
|
|
use data_tree::{reader::DataTreeReader, Event};
|
|
|
|
use crate::{
|
|
math::{Normal, Point},
|
|
surface::triangle_mesh::TriangleMesh,
|
|
};
|
|
|
|
use super::{
|
|
parse_utils::{ws_f32, ws_usize},
|
|
psy::{PsyError, PsyResult},
|
|
};
|
|
|
|
// pub struct TriangleMesh {
|
|
// time_samples: usize,
|
|
// geo: Vec<(Point, Point, Point)>,
|
|
// indices: Vec<usize>,
|
|
// accel: BVH,
|
|
// }
|
|
|
|
pub fn parse_mesh_surface<'a>(
|
|
arena: &'a Arena,
|
|
events: &mut DataTreeReader<impl BufRead>,
|
|
) -> PsyResult<TriangleMesh<'a>> {
|
|
let mut verts = Vec::new(); // Vec of vecs, one for each time sample
|
|
let mut normals = Vec::new(); // Vec of vecs, on for each time sample
|
|
let mut face_vert_counts = Vec::new();
|
|
let mut face_vert_indices = Vec::new();
|
|
|
|
loop {
|
|
match events.next_event()? {
|
|
Event::Leaf {
|
|
type_name: "SurfaceShaderBind",
|
|
..
|
|
} => {
|
|
// TODO
|
|
}
|
|
|
|
Event::Leaf {
|
|
type_name: "Vertices",
|
|
contents,
|
|
..
|
|
} => {
|
|
// Collect verts for this time sample
|
|
let mut text = contents;
|
|
let mut tverts = Vec::new();
|
|
while let IResult::Ok((remaining, vert)) = tuple((ws_f32, ws_f32, ws_f32))(text) {
|
|
text = remaining;
|
|
|
|
tverts.push(Point::new(vert.0, vert.1, vert.2));
|
|
}
|
|
verts.push(tverts);
|
|
}
|
|
|
|
Event::Leaf {
|
|
type_name: "Normals",
|
|
contents,
|
|
..
|
|
} => {
|
|
// Collect normals for this time sample
|
|
let mut text = contents;
|
|
let mut tnormals = Vec::new();
|
|
while let IResult::Ok((remaining, nor)) = tuple((ws_f32, ws_f32, ws_f32))(text) {
|
|
text = remaining;
|
|
|
|
tnormals.push(Normal::new(nor.0, nor.1, nor.2).normalized());
|
|
}
|
|
normals.push(tnormals);
|
|
}
|
|
|
|
Event::Leaf {
|
|
type_name: "FaceVertCounts",
|
|
contents,
|
|
byte_offset,
|
|
} => {
|
|
if !face_vert_counts.is_empty() {
|
|
return Err(PsyError::WrongNodeCount(
|
|
byte_offset,
|
|
"Meshes can only have one FaceVertCounts section.".into(),
|
|
));
|
|
}
|
|
let mut text = contents;
|
|
while let IResult::Ok((remaining, count)) = ws_usize(text) {
|
|
text = remaining;
|
|
face_vert_counts.push(count);
|
|
}
|
|
}
|
|
|
|
Event::Leaf {
|
|
type_name: "FaceVertIndices",
|
|
contents,
|
|
byte_offset,
|
|
} => {
|
|
if !face_vert_indices.is_empty() {
|
|
return Err(PsyError::WrongNodeCount(
|
|
byte_offset,
|
|
"Meshes can only have one FaceVertIndices section.".into(),
|
|
));
|
|
}
|
|
let mut text = contents;
|
|
while let IResult::Ok((remaining, index)) = ws_usize(text) {
|
|
text = remaining;
|
|
face_vert_indices.push(index);
|
|
}
|
|
}
|
|
|
|
Event::InnerClose { .. } => {
|
|
break;
|
|
}
|
|
|
|
_ => {
|
|
todo!(); // Return error.
|
|
}
|
|
}
|
|
}
|
|
|
|
// Validation: make sure all time samples have same vert count.
|
|
let vert_count = verts[0].len();
|
|
for vs in &verts {
|
|
assert_eq!(vert_count, vs.len());
|
|
}
|
|
|
|
// Validation: make sure normal's time samples and vert count match
|
|
// the vertices.
|
|
if !normals.is_empty() {
|
|
assert_eq!(normals.len(), verts.len());
|
|
for ns in &normals {
|
|
assert_eq!(vert_count, ns.len());
|
|
}
|
|
}
|
|
|
|
// Validation: make sure we have any mesh data.
|
|
if verts.is_empty() || face_vert_counts.is_empty() || face_vert_indices.is_empty() {
|
|
todo!("Meshes must have at least one non-empty of each of the following sections: Vertices, FaceVertCounts, FaceVertIndices.");
|
|
// Return an error.
|
|
}
|
|
|
|
// Build triangle mesh
|
|
let mut tri_vert_indices = Vec::new();
|
|
let mut ii = 0;
|
|
for fvc in &face_vert_counts {
|
|
if *fvc >= 3 {
|
|
// Store the polygon, split up into triangles if >3 verts
|
|
let v1 = ii;
|
|
for vi in 0..(fvc - 2) {
|
|
tri_vert_indices.push((
|
|
face_vert_indices[v1],
|
|
face_vert_indices[v1 + vi + 1],
|
|
face_vert_indices[v1 + vi + 2],
|
|
));
|
|
}
|
|
} else {
|
|
// TODO: proper error
|
|
panic!("Cannot handle polygons with less than three vertices.");
|
|
}
|
|
|
|
ii += *fvc;
|
|
}
|
|
|
|
Ok(TriangleMesh::from_verts_and_indices(
|
|
arena,
|
|
&verts,
|
|
&if normals.is_empty() {
|
|
None
|
|
} else {
|
|
Some(normals)
|
|
},
|
|
&tri_vert_indices,
|
|
))
|
|
}
|