Added exporter

This commit is contained in:
Thomas Forgione
2018-02-23 14:34:25 +01:00
parent dd8e9be0d9
commit ac010c0530
4 changed files with 150 additions and 13 deletions
+53
View File
@@ -0,0 +1,53 @@
//! Module containing all the logic for exporting 3D models.
pub mod obj;
use parser::Element;
use model::Model;
use std::io;
use std::io::Write;
use std::fmt;
/// An error occured during export.
pub enum ExportError {
/// An IO error occured when creating files or directories.
IoError(io::Error),
}
impl fmt::Display for ExportError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ExportError::IoError(ref e) =>
write!(f, "IoError occured: {}", e),
}
}
}
impl From<io::Error> for ExportError {
fn from(e: io::Error) -> Self {
ExportError::IoError(e)
}
}
/// Exports a 3D model to a certain format.
pub trait Exporter {
/// The type of errors the exporter will return in case of errors.
///
/// The errors can be of many things, we can't know everything in this create, so this type
/// will enable you to use custom errors.
type Error;
/// Performs the export in the specified output directory.
fn export(&self, model: &Model, output_dir: &str) -> Result<(), Self::Error>;
}
/// Serialize a 3D element.
pub trait ElementSerializer {
/// Performs the serialization.
///
/// Writes the serialization on the output and returns Err if an error occured.
fn serialize<W: Write>(&self, element: Element, output: &mut W) -> Result<(), ExportError>;
}
+83
View File
@@ -0,0 +1,83 @@
//! Module containing the logic for Wavefront OBJ serialization.
use std::io::Write;
use model;
use exporter::ExportError;
use exporter::ElementSerializer;
use parser::Element;
use parser::Element::{Vertex, TextureCoordinate, Normal, UseMaterial, Face};
/// Serializer for elements using the wavefront obj format.
pub struct ObjElementSerializer {
}
impl ObjElementSerializer {
/// Create an obj element serializer.
pub fn new() -> ObjElementSerializer {
ObjElementSerializer {
}
}
/// Writes a face to a writable output.
pub fn write_face<W: Write>(&self, f: model::Face, output: &mut W) -> Result<(), ExportError> {
if f.a.texture_coordinate.is_none() && f.a.normal.is_none() {
// Only vertices
writeln!(output, "f {} {} {}", f.a.vertex + 1, f.b.vertex + 1, f.c.vertex + 1)?;
} else if f.a.normal.is_none() {
// Vertices + tex coords
writeln!(output, "f {}/{} {}/{} {}/{}",
f.a.vertex + 1, f.a.texture_coordinate.unwrap() + 1,
f.b.vertex + 1, f.b.texture_coordinate.unwrap() + 1,
f.c.vertex + 1, f.c.texture_coordinate.unwrap() + 1)?;
} else if f.a.texture_coordinate.is_none() {
// Vertices + normals
writeln!(output, "f {}//{} {}//{} {}//{}",
f.a.vertex + 1, f.a.normal.unwrap() + 1,
f.b.vertex + 1, f.b.normal.unwrap() + 1,
f.c.vertex + 1, f.c.normal.unwrap() + 1)?;
} else {
// All
writeln!(output, "f {}/{}/{} {}/{}/{} {}/{}/{}",
f.a.vertex + 1, f.a.texture_coordinate.unwrap() + 1, f.a.normal.unwrap() + 1,
f.b.vertex + 1, f.b.texture_coordinate.unwrap() + 1, f.b.normal.unwrap() + 1,
f.c.vertex + 1, f.c.texture_coordinate.unwrap() + 1, f.c.normal.unwrap() + 1)?;
}
Ok(())
}
}
impl ElementSerializer for ObjElementSerializer {
/// Serializes an element using the wavefront obj format.
///
/// ```
/// # use model_converter::math::vector::Vector3;
/// # use model_converter::parser::Element::Vertex;
/// # use model_converter::exporter::obj::ObjElementSerializer;
/// use model_converter::exporter::ElementSerializer;
/// let s = ObjElementSerializer::new();
/// let vertex = Vertex(Vector3::new(1.0, 2.0, 3.0));
/// let mut output = vec![];
/// let serialized = s.serialize(vertex, &mut output).ok().unwrap();
/// let result = String::from_utf8(output).unwrap();
/// assert_eq!(result, "v 1 2 3\n");
/// ```
fn serialize<W: Write>(&self, element: Element, output: &mut W) -> Result<(), ExportError> {
match element {
Vertex(v) => writeln!(output, "v {} {} {}", v.x(), v.y(), v.z())?,
TextureCoordinate(vt) => writeln!(output, "vt {} {}", vt.x(), vt.y())?,
Normal(n) => writeln!(output, "vn {} {} {}", n.x(), n.y(), n.z())?,
Face(f) => self.write_face(f, output)?,
UseMaterial(ref n) => writeln!(output, "usemtl {}", n)?,
_ => (),
}
Ok(())
}
}