use error::ObjResult;
use raw::lexer::lex;
use std::collections::HashMap;
use std::io::BufRead;
use vec_map::VecMap;
macro_rules! f {
($args:expr) => (
&{
let mut ret = Vec::<f32>::new();
ret.reserve($args.len());
for arg in $args {
ret.push(arg.parse()?)
}
ret
}[..]
)
}
macro_rules! idx ( ($i:expr, $l:expr) => ({
let i = $i;
if i < 0 {
let i = (i * -1) as usize;
$l.len() - i
} else {
(i - 1) as usize
}
}));
pub fn parse_obj<T: BufRead>(input: T) -> ObjResult<RawObj> {
let mut name = None;
let mut material_libraries = Vec::new();
let mut positions = Vec::new();
let mut tex_coords = Vec::new();
let mut normals = Vec::new();
let mut param_vertices = Vec::new();
let mut points = Vec::new();
let mut lines = Vec::new();
let mut polygons = Vec::new();
let counter = Counter::new(&points, &lines, &polygons);
let mut group_builder = counter.hash_map("default".to_string());
let mut mesh_builder = counter.hash_map(String::new());
let mut smoothing_builder = counter.vec_map();
let mut merging_builder = counter.vec_map();
lex(input, |stmt, args| {
match stmt {
"v" => {
let args = f!(args);
positions.push(match args.len() {
4 => (args[0], args[1], args[2], args[3]),
3 => (args[0], args[1], args[2], 1.0),
_ => error!(WrongNumberOfArguments, "Expected 3 or 4 arguments"),
})
}
"vt" => {
let args = f!(args);
tex_coords.push(match args.len() {
3 => (args[0], args[1], args[2]),
2 => (args[0], args[1], 0.0),
1 => (args[0], 0.0, 0.0),
_ => error!(WrongNumberOfArguments, "Expected 1, 2 or 3 arguments"),
})
}
"vn" => {
let args = f!(args);
normals.push(match args.len() {
3 => (args[0], args[1], args[2]),
_ => error!(WrongNumberOfArguments, "Expected 3 arguments"),
})
}
"vp" => {
let args = f!(args);
param_vertices.push(match args.len() {
3 => (args[0], args[1], args[2]),
2 => (args[0], args[1], 1.0),
1 => (args[0], 0.0, 1.0),
_ => error!(WrongNumberOfArguments, "Expected 1, 2 or 3 arguments"),
})
}
"cstype" => {
let _rational: bool;
let geometry = match args.len() {
2 if args[0] == "rat" => {
_rational = true;
args[1]
}
1 => {
_rational = false;
args[0]
}
_ => error!(WrongTypeOfArguments, "Expected 'rat xxx' or 'xxx' format"),
};
match geometry {
"bmatrix" => unimplemented!(),
"bezier" => unimplemented!(),
"bspline" => unimplemented!(),
"cardinal" => unimplemented!(),
"taylor" => unimplemented!(),
_ => error!(
WrongTypeOfArguments,
"Expected one of 'bmatrix', 'bezier', 'bspline', 'cardinal' and 'taylor'"
),
}
}
"deg" => {
let args = f!(args);
match args.len() {
2 => unimplemented!(),
1 => unimplemented!(),
_ => error!(WrongNumberOfArguments, "Expected 1 or 2 arguments"),
}
}
"bmat" => unimplemented!(),
"step" => unimplemented!(),
"p" => {
for v in args {
let v: i32 = v.parse()?;
let v = idx!(v, positions);
points.push(v);
}
}
"l" => {
if args.len() < 2 {
error!(WrongNumberOfArguments, "Expected at least 2 arguments")
}
let mut args = args.iter();
let first = args.next().unwrap();
let rest = args;
let group = parse_vertex_group(first)?;
let line = match group {
(p, 0, 0) => {
let mut points = vec![idx!(p, positions)];
for gs in rest {
let group = parse_vertex_group(gs)?;
if group.1 != 0 || group.2 != 0 {
error!(WrongTypeOfArguments, "Unexpected vertex format");
}
points.push(idx!(group.0, positions));
}
Line::P(points)
}
(p, t, 0) => {
let mut points = vec![(idx!(p, positions), idx!(t, tex_coords))];
for gs in rest {
let group = parse_vertex_group(gs)?;
if group.2 != 0 {
error!(WrongTypeOfArguments, "Unexpected vertex format");
}
points.push((idx!(group.0, positions), idx!(group.1, tex_coords)));
}
Line::PT(points)
}
_ => {
error!(
WrongTypeOfArguments,
"Unexpected vertex format, expected `#` or `#/#`"
);
}
};
lines.push(line);
}
"fo" | "f" => {
if args.len() < 3 {
error!(WrongNumberOfArguments, "Expected at least 3 arguments")
}
let mut args = args.iter();
let first = args.next().unwrap();
let rest = args;
let group = parse_vertex_group(first)?;
let polygon = match group {
(p, 0, 0) => {
let mut polygon = vec![idx!(p, positions)];
for gs in rest {
let group = parse_vertex_group(gs)?;
if group.1 != 0 || group.2 != 0 {
error!(WrongTypeOfArguments, "Unexpected vertex format");
}
polygon.push(idx!(group.0, positions));
}
Polygon::P(polygon)
}
(p, t, 0) => {
let mut polygon = vec![(idx!(p, positions), idx!(t, tex_coords))];
for gs in rest {
let group = parse_vertex_group(gs)?;
if group.2 != 0 {
error!(WrongTypeOfArguments, "Unexpected vertex format");
}
polygon.push((idx!(group.0, positions), idx!(group.1, tex_coords)));
}
Polygon::PT(polygon)
}
(p, 0, n) => {
let mut polygon = vec![(idx!(p, positions), idx!(n, normals))];
for gs in rest {
let group = parse_vertex_group(gs)?;
if group.1 != 0 {
error!(WrongTypeOfArguments, "Unexpected vertex format");
}
polygon.push((idx!(group.0, positions), idx!(group.2, normals)));
}
Polygon::PN(polygon)
}
(p, t, n) => {
let mut polygon =
vec![(idx!(p, positions), idx!(t, tex_coords), idx!(n, normals))];
for gs in rest {
let group = parse_vertex_group(gs)?;
polygon.push((
idx!(group.0, positions),
idx!(group.1, tex_coords),
idx!(group.2, normals),
));
}
Polygon::PTN(polygon)
}
};
polygons.push(polygon);
}
"curv" => unimplemented!(),
"curv2" => unimplemented!(),
"surf" => unimplemented!(),
"parm" => unimplemented!(),
"trim" => unimplemented!(),
"hole" => unimplemented!(),
"scrv" => unimplemented!(),
"sp" => unimplemented!(),
"end" => unimplemented!(),
"con" => unimplemented!(),
"g" => match args.len() {
1 => group_builder.start(args[0].to_string()),
_ => error!(
WrongNumberOfArguments,
"Expected group name parameter, but nothing has been supplied"
),
},
"s" => match args.len() {
1 if (args[0] == "off" || args[0] == "0") => smoothing_builder.end(),
1 => smoothing_builder.start(args[0].parse()?),
_ => error!(WrongNumberOfArguments, "Expected only 1 argument"),
},
"mg" => match args.len() {
1 if (args[0] == "off" || args[0] == "0") => merging_builder.end(),
1 => merging_builder.start(args[0].parse()?),
_ => error!(WrongNumberOfArguments, "Expected only 1 argument"),
},
"o" => {
name = match args.len() {
0 => None,
_ => Some(args.join(" ")),
}
}
"bevel" => unimplemented!(),
"c_interp" => unimplemented!(),
"d_interp" => unimplemented!(),
"lod" => unimplemented!(),
"usemtl" => match args.len() {
1 => mesh_builder.start(args[0].to_string()),
_ => error!(WrongNumberOfArguments, "Expected only 1 argument"),
},
"mtllib" => {
material_libraries.reserve(args.len());
for path in args {
material_libraries.push(path.to_string());
}
}
"shadow_obj" => unimplemented!(),
"trace_obj" => unimplemented!(),
"ctech" => unimplemented!(),
"stech" => unimplemented!(),
_ => error!(UnexpectedStatement, "Received unknown statement"),
}
Ok(())
})?;
group_builder.end();
mesh_builder.end();
smoothing_builder.end();
merging_builder.end();
Ok(RawObj {
name: name,
material_libraries: material_libraries,
positions: positions,
tex_coords: tex_coords,
normals: normals,
param_vertices: param_vertices,
points: points,
lines: lines,
polygons: polygons,
groups: group_builder.result,
meshes: mesh_builder.result,
smoothing_groups: smoothing_builder.result,
merging_groups: merging_builder.result,
})
}
fn parse_vertex_group(s: &str) -> ObjResult<(i32, i32, i32)> {
let mut indices = s.split('/');
let first = indices.next().unwrap_or("");
let second = indices.next().unwrap_or("");
let third = indices.next().unwrap_or("");
let first = first.parse()?;
let second = if second == "" { 0 } else { second.parse()? };
let third = if third == "" { 0 } else { third.parse()? };
Ok((first, second, third))
}
struct Counter {
points: *const Vec<Point>,
lines: *const Vec<Line>,
polygons: *const Vec<Polygon>,
}
impl Counter {
fn new(
points: *const Vec<Point>,
lines: *const Vec<Line>,
polygons: *const Vec<Polygon>,
) -> Self {
Counter {
points: points,
lines: lines,
polygons: polygons,
}
}
fn get(&self) -> (usize, usize, usize) {
unsafe {
(
(*self.points).len(),
(*self.lines).len(),
(*self.polygons).len(),
)
}
}
fn hash_map<'a>(&'a self, input: String) -> GroupBuilder<'a, HashMap<String, Group>, String> {
let mut result = HashMap::with_capacity(1);
result.insert(input.clone(), Group::new((0, 0, 0)));
GroupBuilder {
counter: self,
current: Some(input),
result: result,
}
}
fn vec_map<'a>(&'a self) -> GroupBuilder<'a, VecMap<Group>, usize> {
GroupBuilder {
counter: self,
current: None,
result: VecMap::new(),
}
}
}
struct GroupBuilder<'a, T, K> {
counter: &'a Counter,
current: Option<K>,
result: T,
}
impl<'a, T, K> GroupBuilder<'a, T, K>
where
T: Map<K, Group>,
K: Clone + Key,
{
fn start(&mut self, input: K) {
let count = self.counter.get();
if let Some(ref current) = self.current {
if *current == input {
return;
}
if self.result.get_mut(current).unwrap().end(count) {
let res = self.result.remove(¤t);
assert!(res.is_some());
}
}
(|| {
if let Some(ref mut group) = self.result.get_mut(&input) {
group.start(count);
return;
}
let res = self.result.insert(input.clone(), Group::new(count));
assert!(res.is_none());
})();
self.current = Some(input);
}
fn end(&mut self) {
if let Some(ref current) = self.current {
if self
.result
.get_mut(current)
.unwrap()
.end(self.counter.get())
{
let result = self.result.remove(current);
assert!(result.is_some());
}
} else {
return;
}
self.current = None;
}
}
const UNDEFINED: usize = ::std::usize::MAX;
impl Group {
fn new(count: (usize, usize, usize)) -> Self {
let mut ret = Group {
points: Vec::with_capacity(1),
lines: Vec::with_capacity(1),
polygons: Vec::with_capacity(1),
};
ret.start(count);
ret
}
fn start(&mut self, count: (usize, usize, usize)) {
self.points.push(Range {
start: count.0,
end: UNDEFINED,
});
self.lines.push(Range {
start: count.1,
end: UNDEFINED,
});
self.polygons.push(Range {
start: count.2,
end: UNDEFINED,
})
}
fn end(&mut self, count: (usize, usize, usize)) -> bool {
end(&mut self.points, count.0);
end(&mut self.lines, count.1);
end(&mut self.polygons, count.2);
fn end(vec: &mut Vec<Range>, end: usize) {
let last = vec.len() - 1;
assert_eq!(vec[last].end, UNDEFINED);
if vec[last].start != end {
vec[last].end = end;
} else {
vec.pop();
}
}
self.points.is_empty() && self.lines.is_empty() && self.polygons.is_empty()
}
}
trait Map<K: Key, V> {
fn insert(&mut self, K, V) -> Option<V>;
fn get_mut(&mut self, k: &K) -> Option<&mut V>;
fn remove(&mut self, k: &K) -> Option<V>;
}
impl<V> Map<String, V> for HashMap<String, V> {
fn insert(&mut self, k: String, v: V) -> Option<V> {
self.insert(k, v)
}
fn get_mut(&mut self, k: &String) -> Option<&mut V> {
self.get_mut(k)
}
fn remove(&mut self, k: &String) -> Option<V> {
self.remove(k)
}
}
impl<V> Map<usize, V> for VecMap<V> {
fn insert(&mut self, k: usize, v: V) -> Option<V> {
self.insert(k, v)
}
fn get_mut(&mut self, k: &usize) -> Option<&mut V> {
self.get_mut(*k)
}
fn remove(&mut self, k: &usize) -> Option<V> {
self.remove(*k)
}
}
trait Key: Eq {}
impl Key for String {}
impl Key for usize {}
pub struct RawObj {
pub name: Option<String>,
pub material_libraries: Vec<String>,
pub positions: Vec<(f32, f32, f32, f32)>,
pub tex_coords: Vec<(f32, f32, f32)>,
pub normals: Vec<(f32, f32, f32)>,
pub param_vertices: Vec<(f32, f32, f32)>,
pub points: Vec<Point>,
pub lines: Vec<Line>,
pub polygons: Vec<Polygon>,
pub groups: HashMap<String, Group>,
pub meshes: HashMap<String, Group>,
pub smoothing_groups: VecMap<Group>,
pub merging_groups: VecMap<Group>,
}
pub type Point = usize;
#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Line {
P(Vec<usize>),
PT(Vec<(usize, usize)>),
}
#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Polygon {
P(Vec<usize>),
PT(Vec<(usize, usize)>),
PN(Vec<(usize, usize)>),
PTN(Vec<(usize, usize, usize)>),
}
#[derive(Clone, Debug)]
pub struct Group {
pub points: Vec<Range>,
pub lines: Vec<Range>,
pub polygons: Vec<Range>,
}
#[derive(Copy, PartialEq, Eq, Clone, Debug)]
pub struct Range {
pub start: usize,
pub end: usize,
}