From 4b7532ca0d6ff21d5531febb749b43112d0451e8 Mon Sep 17 00:00:00 2001 From: Charlotte Pabst Date: Sat, 23 Mar 2024 16:54:20 +0100 Subject: --- src/obj_export.rs | 154 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 src/obj_export.rs (limited to 'src/obj_export.rs') diff --git a/src/obj_export.rs b/src/obj_export.rs new file mode 100644 index 0000000..7998112 --- /dev/null +++ b/src/obj_export.rs @@ -0,0 +1,154 @@ +use crate::*; + +struct VertAttr { + func: F, + items: Vec, + local: HashMap>, + // global: HashMap, + marker: std::marker::PhantomData<(V, L)>, +} + +impl VertAttr +where + F: FnMut(L, &V) -> Option, + T: Copy, // + Hash + Eq, +{ + fn new(func: F) -> Self { + Self { + func, + items: Vec::new(), + local: HashMap::new(), + // global: HashMap::new(), + marker: std::marker::PhantomData, + } + } + + fn add(&mut self, local: L, vert_id: usize, vert_data: &V) -> Option { + *self.local.entry(vert_id).or_insert_with(|| { + let item = (self.func)(local, vert_data); + + //*self.global.entry(item).or_insert_with(|| { + item.map(|item| { + self.items.push(item); + self.items.len() + }) + //}) + }) + } +} + +pub struct ObjExport<'tok, 'brand, 'arena, V, W, VPos, VTex, VNorm> { + writer: &'tok mut W, + dcel: &'tok Dcel<'brand, 'arena, V>, + vertex_pos: VPos, + pos_ids: HashMap, + textures: VertAttr)>), V>, + normals: VertAttr, +} + +impl<'tok, 'brand, 'arena, V, W, VPos, VTex, VNorm> + ObjExport<'tok, 'brand, 'arena, V, W, VPos, VTex, VNorm> +where + W: std::io::Write, + VPos: FnMut(&V) -> (f64, f64, f64, Option), + VTex: FnMut(lens!(Face), &V) -> Option<(f64, Option<(f64, Option)>)>, + VNorm: FnMut(lens!(Face), &V) -> Option<(f64, f64, f64)>, +{ + pub fn export( + writer: &'tok mut W, + dcel: &'tok Dcel<'brand, 'arena, V>, + vertex_pos: VPos, + vertex_texture: VTex, + vertex_normal: VNorm, + ) -> std::io::Result<()> { + Self { + writer, + dcel, + vertex_pos, + pos_ids: HashMap::new(), + textures: VertAttr::new(vertex_texture), + normals: VertAttr::new(vertex_normal), + } + .write() + } + + fn write(&mut self) -> std::io::Result<()> { + let mut next_id = 1; + for shell in self.dcel.iter_bodies().flat_map(Lens::iter_shells) { + for vertex in shell.iter_vertices() { + self.pos_ids.insert(vertex.id(), next_id); + next_id += 1; + + let (x, y, z, w) = (self.vertex_pos)(vertex.data()); + write!(self.writer, "v {x} {y} {z}")?; + if let Some(w) = w { + write!(self.writer, " {w}")?; + } + writeln!(self.writer)?; + } + + for face in shell.iter_faces() { + write!(self.writer, "f")?; + + for inner in face.iter_inner_loops() { + self.write_vertex(face, face.outer_loop().half_edges())?; + for h in inner.iter_half_edges() { + self.write_vertex(face, h)?; + } + } + + for h in face.outer_loop().iter_half_edges() { + self.write_vertex(face, h)?; + } + + self.textures.local.clear(); + self.normals.local.clear(); + + writeln!(self.writer)?; + } + } + + for (u, vw) in &self.textures.items { + write!(self.writer, "vt {u}")?; + if let Some((v, w)) = vw { + write!(self.writer, " {v}")?; + if let Some(w) = w { + write!(self.writer, " {w}")?; + } + } + writeln!(self.writer)?; + } + + for (x, y, z) in &self.normals.items { + writeln!(self.writer, "vn {x} {y} {z}")?; + } + + Ok(()) + } + + fn write_vertex( + &mut self, + face: lens!(Face), + half_edge: lens!(HalfEdge), + ) -> std::io::Result<()> { + let vert = half_edge.origin(); + write!(self.writer, " {}", self.pos_ids[&vert.id()])?; + + let t = self.textures.add(face, vert.id(), vert.data()); + let n = self.normals.add(face, vert.id(), vert.data()); + + if t.is_some() || n.is_some() { + write!(self.writer, "/")?; + } + + if let Some(t) = t { + write!(self.writer, "{t}")?; + } + + if let Some(n) = n { + write!(self.writer, "/{n}")?; + } + + Ok(()) + } +} -- cgit v1.2.3