Added exporter
This commit is contained in:
parent
dd8e9be0d9
commit
ac010c0530
|
@ -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>;
|
||||
}
|
|
@ -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(())
|
||||
}
|
||||
}
|
|
@ -6,3 +6,4 @@ extern crate verbose_log;
|
|||
pub mod math;
|
||||
pub mod model;
|
||||
pub mod parser;
|
||||
pub mod exporter;
|
||||
|
|
|
@ -45,9 +45,9 @@ impl ObjParser {
|
|||
/// Parses an obj vertex line.
|
||||
///
|
||||
/// ```
|
||||
/// # use dash_3d_exporter::math::vector::Vector3;
|
||||
/// # use dash_3d_exporter::parser::obj::ObjParser;
|
||||
/// # use dash_3d_exporter::parser::Element::Vertex;
|
||||
/// # use model_converter::math::vector::Vector3;
|
||||
/// # use model_converter::parser::obj::ObjParser;
|
||||
/// # use model_converter::parser::Element::Vertex;
|
||||
/// let obj = ObjParser::new();
|
||||
/// let vertex = obj.parse_vertex(0, "v 1 2 3", "file.obj").unwrap();
|
||||
/// assert_eq!(vertex, Vertex(Vector3::new(1.0, 2.0, 3.0)));
|
||||
|
@ -65,9 +65,9 @@ impl ObjParser {
|
|||
/// Parses an obj texture coordinate line.
|
||||
///
|
||||
/// ```
|
||||
/// # use dash_3d_exporter::math::vector::Vector2;
|
||||
/// # use dash_3d_exporter::parser::obj::ObjParser;
|
||||
/// # use dash_3d_exporter::parser::Element::TextureCoordinate;
|
||||
/// # use model_converter::math::vector::Vector2;
|
||||
/// # use model_converter::parser::obj::ObjParser;
|
||||
/// # use model_converter::parser::Element::TextureCoordinate;
|
||||
/// let obj = ObjParser::new();
|
||||
/// let texture_coordinate = obj.parse_texture_coordinate(0, "vt 1 2", "file.obj").unwrap();
|
||||
/// assert_eq!(texture_coordinate, TextureCoordinate(Vector2::new(1.0, 2.0)));
|
||||
|
@ -84,9 +84,9 @@ impl ObjParser {
|
|||
/// Parses an obj normal line.
|
||||
///
|
||||
/// ```
|
||||
/// # use dash_3d_exporter::math::vector::Vector3;
|
||||
/// # use dash_3d_exporter::parser::obj::ObjParser;
|
||||
/// # use dash_3d_exporter::parser::Element::Normal;
|
||||
/// # use model_converter::math::vector::Vector3;
|
||||
/// # use model_converter::parser::obj::ObjParser;
|
||||
/// # use model_converter::parser::Element::Normal;
|
||||
/// let obj = ObjParser::new();
|
||||
/// let normal = obj.parse_normal(0, "vn 1 2 3", "file.obj").unwrap();
|
||||
/// assert_eq!(normal, Normal(Vector3::new(1.0, 2.0, 3.0)));
|
||||
|
@ -106,10 +106,10 @@ impl ObjParser {
|
|||
///
|
||||
/// The index is changed to start from 0.
|
||||
/// ```
|
||||
/// # use dash_3d_exporter::math::vector::Vector3;
|
||||
/// # use dash_3d_exporter::parser::obj::ObjParser;
|
||||
/// # use dash_3d_exporter::parser::Element;
|
||||
/// # use dash_3d_exporter::model::{Face, FaceVertex};
|
||||
/// # use model_converter::math::vector::Vector3;
|
||||
/// # use model_converter::parser::obj::ObjParser;
|
||||
/// # use model_converter::parser::Element;
|
||||
/// # use model_converter::model::{Face, FaceVertex};
|
||||
/// let obj = ObjParser::new();
|
||||
/// let face1 = obj.parse_face(0, "f 1 2 3", "file.obj").unwrap();
|
||||
/// let face2 = Element::Face(Face::new(
|
||||
|
|
Loading…
Reference in New Issue