#[macro_use]
extern crate lazy_static;
extern crate wavefront_obj;
use std::path::Path;
use std::io::{BufWriter, Result, Write};
use std::fs;
use wavefront_obj::obj;
pub use obj::{Geometry, GroupName, NormalIndex, ObjSet, Object, Primitive, Shape, TVertex,
TextureIndex, VTNIndex, Vertex, VertexIndex};
pub fn export<W: Write>(obj_set: &ObjSet, output: &mut W) -> Result<()> {
Exporter::new(output).export(obj_set)
}
pub fn export_to_file<P: AsRef<Path>>(obj_set: &ObjSet, path: P) -> Result<()> {
let file = fs::File::create(path)?;
let mut buffered = BufWriter::new(file);
export(obj_set, &mut buffered)
}
struct Exporter<'a, W: 'a + Write> {
output: &'a mut W,
v_base_id: usize,
uv_base_id: usize,
n_base_id: usize,
current_groups: Vec<GroupName>,
current_smoothing_groups: Vec<u32>,
}
impl<'a, W: 'a + Write> Exporter<'a, W> {
fn new(output: &'a mut W) -> Exporter<W> {
Exporter {
output,
v_base_id: 1,
uv_base_id: 1,
n_base_id: 1,
current_groups: DEFAULT_GROUPS.clone(),
current_smoothing_groups: vec![0],
}
}
fn export(&mut self, obj_set: &ObjSet) -> Result<()> {
for object in &obj_set.objects {
self.serialize_object(object)?;
}
Ok(())
}
fn serialize_object(&mut self, object: &Object) -> Result<()> {
write!(self.output, "o {}\n", object.name)?;
self.serialize_vertex_data(object)?;
for g in &object.geometry {
self.serialize_geometry(g)?;
}
self.update_base_indices(object);
Ok(())
}
fn serialize_vertex_data(&mut self, object: &Object) -> Result<()> {
for v in &object.vertices {
self.serialize_vertex(v, "v")?;
}
for uv in &object.tex_vertices {
self.serialize_uv(uv)?;
}
for n in &object.normals {
self.serialize_vertex(n, "vn")?
}
Ok(())
}
fn serialize_geometry(&mut self, geometry: &Geometry) -> Result<()> {
for s in &geometry.shapes {
self.serialize_shape(s)?;
}
Ok(())
}
fn serialize_vertex(&mut self, v: &Vertex, prefix: &str) -> Result<()> {
write!(self.output, "{} {:.6} {:.6} {:.6}\n", prefix, v.x, v.y, v.z)
}
fn serialize_uv(&mut self, uv: &TVertex) -> Result<()> {
if uv.w == 0.0 {
write!(self.output, "vt {:.6} {:.6}\n", uv.u, uv.v)
} else {
write!(self.output, "vt {:.6} {:.6} {:.6}\n", uv.u, uv.v, uv.w)
}
}
fn serialize_shape(&mut self, shape: &Shape) -> Result<()> {
self.update_and_serialize_groups(&shape.groups)?;
self.update_and_serialize_smoothing_groups(&shape.smoothing_groups)?;
self.serialize_primitive(&shape.primitive)
}
fn update_and_serialize_groups(&mut self, groups: &[GroupName]) -> Result<()> {
let normalized_groups = groups_or_default(groups);
if self.current_groups != normalized_groups {
write!(self.output, "g")?;
for g in normalized_groups {
write!(self.output, " {}", g)?;
}
writeln!(self.output, "")?;
self.current_groups = normalized_groups.to_owned();
}
Ok(())
}
fn update_and_serialize_smoothing_groups(&mut self, smoothing_groups: &[u32]) -> Result<()> {
let normalized_groups = smoothing_groups_or_default(smoothing_groups);
if self.current_smoothing_groups != normalized_groups {
write!(self.output, "s")?;
for g in normalized_groups {
write!(self.output, " {}", g)?;
}
writeln!(self.output, "")?;
self.current_smoothing_groups = normalized_groups.to_owned();
}
Ok(())
}
fn serialize_primitive(&mut self, primitive: &Primitive) -> Result<()> {
match *primitive {
Primitive::Point(vtn) => {
write!(self.output, "p")?;
self.serialize_vtn(vtn)?;
}
Primitive::Line(vtn1, vtn2) => {
write!(self.output, "l")?;
self.serialize_vtn(vtn1)?;
self.serialize_vtn(vtn2)?;
}
Primitive::Triangle(vtn1, vtn2, vtn3) => {
write!(self.output, "f")?;
self.serialize_vtn(vtn1)?;
self.serialize_vtn(vtn2)?;
self.serialize_vtn(vtn3)?;
}
}
writeln!(self.output, "")
}
fn serialize_vtn(&mut self, vtn: VTNIndex) -> Result<()> {
match vtn {
(vi, None, None) => write!(self.output, " {}", vi + self.v_base_id),
(vi, Some(ti), None) => write!(
self.output,
" {}/{}",
vi + self.v_base_id,
ti + self.uv_base_id
),
(vi, Some(ti), Some(ni)) => write!(
self.output,
" {}/{}/{}",
vi + self.v_base_id,
ti + self.uv_base_id,
ni + self.n_base_id
),
(vi, None, Some(ni)) => write!(
self.output,
" {}//{}",
vi + self.v_base_id,
ni + self.n_base_id
),
}
}
fn update_base_indices(&mut self, object: &Object) {
self.v_base_id += object.vertices.len();
self.uv_base_id += object.tex_vertices.len();
self.n_base_id += object.normals.len();
}
}
lazy_static! {
static ref DEFAULT_GROUPS: Vec<GroupName> = vec!["default".to_owned()];
static ref DEFAULT_SMOOTHING_GROUPS: Vec<u32> = vec![0];
}
fn groups_or_default(groups: &[GroupName]) -> &[GroupName] {
if groups.is_empty() || groups[0].is_empty() {
&DEFAULT_GROUPS
} else {
groups
}
}
fn smoothing_groups_or_default(smoothing_groups: &[u32]) -> &[u32] {
if smoothing_groups.is_empty() {
&DEFAULT_SMOOTHING_GROUPS
} else {
smoothing_groups
}
}