obj_exporter/
lib.rs

1#[macro_use]
2extern crate lazy_static;
3extern crate wavefront_obj;
4
5use std::path::Path;
6use std::io::{BufWriter, Result, Write};
7use std::fs;
8
9use wavefront_obj::obj;
10pub use obj::{Geometry, GroupName, NormalIndex, ObjSet, Object, Primitive, Shape, TVertex,
11              TextureIndex, VTNIndex, Vertex, VertexIndex};
12
13/// Exports `ObjSet` to given output.
14pub fn export<W: Write>(obj_set: &ObjSet, output: &mut W) -> Result<()> {
15    Exporter::new(output).export(obj_set)
16}
17
18/// Exports `ObjSet`to file.
19pub fn export_to_file<P: AsRef<Path>>(obj_set: &ObjSet, path: P) -> Result<()> {
20    let file = fs::File::create(path)?;
21    let mut buffered = BufWriter::new(file);
22    export(obj_set, &mut buffered)
23}
24
25struct Exporter<'a, W: 'a + Write> {
26    output: &'a mut W,
27    v_base_id: usize,
28    uv_base_id: usize,
29    n_base_id: usize,
30    current_groups: Vec<GroupName>,
31    current_smoothing_groups: Vec<u32>,
32}
33
34impl<'a, W: 'a + Write> Exporter<'a, W> {
35    fn new(output: &'a mut W) -> Exporter<W> {
36        Exporter {
37            output,
38            v_base_id: 1,
39            uv_base_id: 1,
40            n_base_id: 1,
41            current_groups: DEFAULT_GROUPS.clone(),
42            current_smoothing_groups: vec![0],
43        }
44    }
45
46    fn export(&mut self, obj_set: &ObjSet) -> Result<()> {
47        for object in &obj_set.objects {
48            self.serialize_object(object)?;
49        }
50        Ok(())
51    }
52
53    fn serialize_object(&mut self, object: &Object) -> Result<()> {
54        write!(self.output, "o {}\n", object.name)?;
55        self.serialize_vertex_data(object)?;
56        for g in &object.geometry {
57            self.serialize_geometry(g)?;
58        }
59        self.update_base_indices(object);
60        Ok(())
61    }
62
63    fn serialize_vertex_data(&mut self, object: &Object) -> Result<()> {
64        for v in &object.vertices {
65            self.serialize_vertex(v, "v")?;
66        }
67        for uv in &object.tex_vertices {
68            self.serialize_uv(uv)?;
69        }
70        for n in &object.normals {
71            self.serialize_vertex(n, "vn")?
72        }
73        Ok(())
74    }
75
76    fn serialize_geometry(&mut self, geometry: &Geometry) -> Result<()> {
77        for s in &geometry.shapes {
78            self.serialize_shape(s)?;
79        }
80        Ok(())
81    }
82
83    fn serialize_vertex(&mut self, v: &Vertex, prefix: &str) -> Result<()> {
84        write!(self.output, "{} {:.6} {:.6} {:.6}\n", prefix, v.x, v.y, v.z)
85    }
86
87    fn serialize_uv(&mut self, uv: &TVertex) -> Result<()> {
88        if uv.w == 0.0 {
89            write!(self.output, "vt {:.6} {:.6}\n", uv.u, uv.v)
90        } else {
91            write!(self.output, "vt {:.6} {:.6} {:.6}\n", uv.u, uv.v, uv.w)
92        }
93    }
94
95    fn serialize_shape(&mut self, shape: &Shape) -> Result<()> {
96        self.update_and_serialize_groups(&shape.groups)?;
97        self.update_and_serialize_smoothing_groups(&shape.smoothing_groups)?;
98        self.serialize_primitive(&shape.primitive)
99    }
100
101    fn update_and_serialize_groups(&mut self, groups: &[GroupName]) -> Result<()> {
102        let normalized_groups = groups_or_default(groups);
103        if self.current_groups != normalized_groups {
104            write!(self.output, "g")?;
105            for g in normalized_groups {
106                write!(self.output, " {}", g)?;
107            }
108            writeln!(self.output, "")?;
109            self.current_groups = normalized_groups.to_owned();
110        }
111        Ok(())
112    }
113
114    fn update_and_serialize_smoothing_groups(&mut self, smoothing_groups: &[u32]) -> Result<()> {
115        let normalized_groups = smoothing_groups_or_default(smoothing_groups);
116        if self.current_smoothing_groups != normalized_groups {
117            write!(self.output, "s")?;
118            for g in normalized_groups {
119                write!(self.output, " {}", g)?;
120            }
121            writeln!(self.output, "")?;
122            self.current_smoothing_groups = normalized_groups.to_owned();
123        }
124        Ok(())
125    }
126
127    fn serialize_primitive(&mut self, primitive: &Primitive) -> Result<()> {
128        match *primitive {
129            Primitive::Point(vtn) => {
130                write!(self.output, "p")?;
131                self.serialize_vtn(vtn)?;
132            }
133            Primitive::Line(vtn1, vtn2) => {
134                write!(self.output, "l")?;
135                self.serialize_vtn(vtn1)?;
136                self.serialize_vtn(vtn2)?;
137            }
138            Primitive::Triangle(vtn1, vtn2, vtn3) => {
139                write!(self.output, "f")?;
140                self.serialize_vtn(vtn1)?;
141                self.serialize_vtn(vtn2)?;
142                self.serialize_vtn(vtn3)?;
143            }
144        }
145        writeln!(self.output, "")
146    }
147
148    fn serialize_vtn(&mut self, vtn: VTNIndex) -> Result<()> {
149        match vtn {
150            (vi, None, None) => write!(self.output, " {}", vi + self.v_base_id),
151            (vi, Some(ti), None) => write!(
152                self.output,
153                " {}/{}",
154                vi + self.v_base_id,
155                ti + self.uv_base_id
156            ),
157            (vi, Some(ti), Some(ni)) => write!(
158                self.output,
159                " {}/{}/{}",
160                vi + self.v_base_id,
161                ti + self.uv_base_id,
162                ni + self.n_base_id
163            ),
164            (vi, None, Some(ni)) => write!(
165                self.output,
166                " {}//{}",
167                vi + self.v_base_id,
168                ni + self.n_base_id
169            ),
170        }
171    }
172
173    fn update_base_indices(&mut self, object: &Object) {
174        self.v_base_id += object.vertices.len();
175        self.uv_base_id += object.tex_vertices.len();
176        self.n_base_id += object.normals.len();
177    }
178}
179
180lazy_static! {
181    static ref DEFAULT_GROUPS: Vec<GroupName> = vec!["default".to_owned()];
182    static ref DEFAULT_SMOOTHING_GROUPS: Vec<u32> = vec![0];
183}
184
185fn groups_or_default(groups: &[GroupName]) -> &[GroupName] {
186    if groups.is_empty() || groups[0].is_empty() {
187        &DEFAULT_GROUPS
188    } else {
189        groups
190    }
191}
192
193fn smoothing_groups_or_default(smoothing_groups: &[u32]) -> &[u32] {
194    if smoothing_groups.is_empty() {
195        &DEFAULT_SMOOTHING_GROUPS
196    } else {
197        smoothing_groups
198    }
199}