1use crate::error::Result;
7use crate::mesher::MesherOutput;
8use std::fmt::Write;
9
10pub fn export_obj(output: &MesherOutput, name: &str) -> Result<(String, String)> {
15 let mesh = output.mesh();
17 let mut obj = String::new();
18 let mut mtl = String::new();
19
20 writeln!(obj, "# Schematic Mesher OBJ Export").unwrap();
22 writeln!(obj, "# Vertices: {}", mesh.vertex_count()).unwrap();
23 writeln!(obj, "# Triangles: {}", mesh.triangle_count()).unwrap();
24 writeln!(obj).unwrap();
25
26 writeln!(obj, "mtllib {}.mtl", name).unwrap();
28 writeln!(obj).unwrap();
29
30 writeln!(obj, "o {}", name).unwrap();
32 writeln!(obj).unwrap();
33
34 for vertex in &mesh.vertices {
37 writeln!(
38 obj,
39 "v {} {} {} {} {} {}",
40 vertex.position[0],
41 vertex.position[1],
42 vertex.position[2],
43 vertex.color[0],
44 vertex.color[1],
45 vertex.color[2]
46 )
47 .unwrap();
48 }
49 writeln!(obj).unwrap();
50
51 for vertex in &mesh.vertices {
53 writeln!(obj, "vt {} {}", vertex.uv[0], vertex.uv[1]).unwrap();
54 }
55 writeln!(obj).unwrap();
56
57 for vertex in &mesh.vertices {
59 writeln!(
60 obj,
61 "vn {} {} {}",
62 vertex.normal[0], vertex.normal[1], vertex.normal[2]
63 )
64 .unwrap();
65 }
66 writeln!(obj).unwrap();
67
68 writeln!(obj, "usemtl {}_material", name).unwrap();
70 writeln!(obj).unwrap();
71
72 for i in (0..mesh.indices.len()).step_by(3) {
75 let i0 = mesh.indices[i] as usize + 1;
76 let i1 = mesh.indices[i + 1] as usize + 1;
77 let i2 = mesh.indices[i + 2] as usize + 1;
78 writeln!(
79 obj,
80 "f {}/{}/{} {}/{}/{} {}/{}/{}",
81 i0, i0, i0, i1, i1, i1, i2, i2, i2
82 )
83 .unwrap();
84 }
85
86 writeln!(mtl, "# Schematic Mesher Material").unwrap();
88 writeln!(mtl).unwrap();
89 writeln!(mtl, "newmtl {}_material", name).unwrap();
90 writeln!(mtl, "Ka 1.0 1.0 1.0").unwrap(); writeln!(mtl, "Kd 1.0 1.0 1.0").unwrap(); writeln!(mtl, "Ks 0.0 0.0 0.0").unwrap(); writeln!(mtl, "Ns 10.0").unwrap(); writeln!(mtl, "d 1.0").unwrap(); writeln!(mtl, "illum 1").unwrap(); writeln!(mtl, "map_Kd {}_atlas.png", name).unwrap(); Ok((obj, mtl))
99}
100
101pub struct ObjExport {
103 pub obj: String,
104 pub mtl: String,
105 pub texture_png: Vec<u8>,
106}
107
108impl ObjExport {
109 pub fn from_output(output: &MesherOutput, name: &str) -> Result<Self> {
110 let (obj, mtl) = export_obj(output, name)?;
111 let texture_png = output.atlas.to_png()?;
112 Ok(Self {
113 obj,
114 mtl,
115 texture_png,
116 })
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123 use crate::atlas::TextureAtlas;
124 use crate::mesher::geometry::{Mesh, Vertex};
125 use crate::types::BoundingBox;
126
127 #[test]
128 fn test_export_simple_obj() {
129 let mut mesh = Mesh::new();
130
131 let v0 = mesh.add_vertex(Vertex::new([0.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0]));
133 let v1 = mesh.add_vertex(Vertex::new([1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [1.0, 0.0]));
134 let v2 = mesh.add_vertex(Vertex::new([0.0, 0.0, 1.0], [0.0, 1.0, 0.0], [0.0, 1.0]));
135 mesh.add_triangle(v0, v1, v2);
136
137 let output = MesherOutput {
138 opaque_mesh: mesh,
139 transparent_mesh: Mesh::new(),
140 atlas: TextureAtlas::empty(),
141 bounds: BoundingBox::new([0.0, 0.0, 0.0], [1.0, 0.0, 1.0]),
142 };
143
144 let (obj, mtl) = export_obj(&output, "test").unwrap();
145
146 assert!(obj.contains("v 0 0 0"));
147 assert!(obj.contains("vt 0 0"));
148 assert!(obj.contains("vn 0 1 0"));
149 assert!(obj.contains("f 1/1/1 2/2/2 3/3/3"));
150 assert!(mtl.contains("newmtl test_material"));
151 }
152}