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
13pub fn export<W: Write>(obj_set: &ObjSet, output: &mut W) -> Result<()> {
15 Exporter::new(output).export(obj_set)
16}
17
18pub 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}