Add obj parsing
This commit is contained in:
parent
0a70fbd8d4
commit
556f50274d
13 changed files with 1004 additions and 3 deletions
|
|
@ -4,5 +4,7 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
miette = { version = "7.2.0", features = ["fancy"] }
|
||||
nom = "7.1.3"
|
||||
ray-tracing-core = { path = "../ray-tracing-core" }
|
||||
ray-tracing-material = { path = "../ray-tracing-material" }
|
||||
|
|
|
|||
10
ray-tracing-scene/examples/parse_obj.rs
Normal file
10
ray-tracing-scene/examples/parse_obj.rs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
use miette::Result;
|
||||
use ray_tracing_scene::parse_obj::ObjData;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let obj = ObjData::new("obj/cornell_box.obj")?;
|
||||
|
||||
dbg!(obj);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
43
ray-tracing-scene/obj/box.obj
Normal file
43
ray-tracing-scene/obj/box.obj
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
o box
|
||||
|
||||
# left side
|
||||
v 0.5 -0.5 -0.5
|
||||
v 0.5 -0.5 0.5
|
||||
v 0.5 0.5 0.5
|
||||
v 0.5 0.5 -0.5
|
||||
f -4 -3 -2 -1
|
||||
|
||||
# right side
|
||||
v -0.5 -0.5 -0.5
|
||||
v -0.5 -0.5 0.5
|
||||
v -0.5 0.5 0.5
|
||||
v -0.5 0.5 -0.5
|
||||
f -4 -3 -2 -1
|
||||
|
||||
# bottom side
|
||||
v -0.5 -0.5 -0.5
|
||||
v -0.5 -0.5 0.5
|
||||
v 0.5 -0.5 0.5
|
||||
v 0.5 -0.5 -0.5
|
||||
f -4 -3 -2 -1
|
||||
|
||||
# top side
|
||||
v -0.5 0.5 -0.5
|
||||
v -0.5 0.5 0.5
|
||||
v 0.5 0.5 0.5
|
||||
v 0.5 0.5 -0.5
|
||||
f -4 -3 -2 -1
|
||||
|
||||
# front side
|
||||
v -0.5 -0.5 -0.5
|
||||
v -0.5 0.5 -0.5
|
||||
v 0.5 0.5 -0.5
|
||||
v 0.5 -0.5 -0.5
|
||||
f -4 -3 -2 -1
|
||||
|
||||
# back side
|
||||
v -0.5 -0.5 0.5
|
||||
v -0.5 0.5 0.5
|
||||
v 0.5 0.5 0.5
|
||||
v 0.5 -0.5 0.5
|
||||
f -4 -3 -2 -1
|
||||
38
ray-tracing-scene/obj/box2.obj
Normal file
38
ray-tracing-scene/obj/box2.obj
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# Blender 4.1.1
|
||||
# www.blender.org
|
||||
o box
|
||||
v -0.500000 -0.500000 0.500000
|
||||
v -0.500000 0.500000 0.500000
|
||||
v -0.500000 -0.500000 -0.500000
|
||||
v -0.500000 0.500000 -0.500000
|
||||
v 0.500000 -0.500000 0.500000
|
||||
v 0.500000 0.500000 0.500000
|
||||
v 0.500000 -0.500000 -0.500000
|
||||
v 0.500000 0.500000 -0.500000
|
||||
vn -1.0000 -0.0000 -0.0000
|
||||
vn -0.0000 -0.0000 -1.0000
|
||||
vn 1.0000 -0.0000 -0.0000
|
||||
vn -0.0000 -0.0000 1.0000
|
||||
vn -0.0000 -1.0000 -0.0000
|
||||
vn -0.0000 1.0000 -0.0000
|
||||
vt 0.375000 0.000000
|
||||
vt 0.625000 0.000000
|
||||
vt 0.625000 0.250000
|
||||
vt 0.375000 0.250000
|
||||
vt 0.625000 0.500000
|
||||
vt 0.375000 0.500000
|
||||
vt 0.625000 0.750000
|
||||
vt 0.375000 0.750000
|
||||
vt 0.625000 1.000000
|
||||
vt 0.375000 1.000000
|
||||
vt 0.125000 0.500000
|
||||
vt 0.125000 0.750000
|
||||
vt 0.875000 0.500000
|
||||
vt 0.875000 0.750000
|
||||
s 0
|
||||
f 1/1/1 2/2/1 4/3/1 3/4/1
|
||||
f 3/4/2 4/3/2 8/5/2 7/6/2
|
||||
f 7/6/3 8/5/3 6/7/3 5/8/3
|
||||
f 5/8/4 6/7/4 2/9/4 1/10/4
|
||||
f 3/11/5 7/6/5 5/8/5 1/12/5
|
||||
f 8/5/6 4/13/6 2/14/6 6/7/6
|
||||
27
ray-tracing-scene/obj/cornell_box.mtl
Normal file
27
ray-tracing-scene/obj/cornell_box.mtl
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
newmtl white
|
||||
Ka 0 0 0
|
||||
Kd 1 1 1
|
||||
Ks 0 0 0
|
||||
|
||||
newmtl red
|
||||
Ka 0 0 0
|
||||
Kd 1 0 0
|
||||
Ks 0 0 0
|
||||
|
||||
newmtl green
|
||||
Ka 0 0 0
|
||||
Kd 0 1 0
|
||||
Ks 0 0 0
|
||||
|
||||
newmtl blue
|
||||
Ka 0 0 0
|
||||
Kd 0 0 1
|
||||
Ks 0 0 0
|
||||
|
||||
newmtl light
|
||||
Ka 20 20 20
|
||||
Kd 1 1 1
|
||||
Ks 0 0 0
|
||||
|
||||
newmtl glass
|
||||
type glass
|
||||
140
ray-tracing-scene/obj/cornell_box.obj
Normal file
140
ray-tracing-scene/obj/cornell_box.obj
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
# original cornell box data
|
||||
|
||||
mtllib cornell_box.mtl
|
||||
|
||||
o floor
|
||||
usemtl white
|
||||
v 552.8 0.0 0.0
|
||||
v 0.0 0.0 0.0
|
||||
v 0.0 0.0 559.2
|
||||
v 549.6 0.0 559.2
|
||||
|
||||
v 130.0 0.0 65.0
|
||||
v 82.0 0.0 225.0
|
||||
v 240.0 0.0 272.0
|
||||
v 290.0 0.0 114.0
|
||||
|
||||
v 423.0 0.0 247.0
|
||||
v 265.0 0.0 296.0
|
||||
v 314.0 0.0 456.0
|
||||
v 472.0 0.0 406.0
|
||||
|
||||
f 1 2 3 4
|
||||
f 8 7 6 5
|
||||
f 12 11 10 9
|
||||
|
||||
o light
|
||||
usemtl light
|
||||
v 343.0 548.0 227.0
|
||||
v 343.0 548.0 332.0
|
||||
v 213.0 548.0 332.0
|
||||
v 213.0 548.0 227.0
|
||||
#f -4 -3 -2 -1
|
||||
|
||||
o ceiling
|
||||
usemtl white
|
||||
v 556.0 548.8 0.0
|
||||
v 556.0 548.8 559.2
|
||||
v 0.0 548.8 559.2
|
||||
v 0.0 548.8 0.0
|
||||
f -4 -3 -2 -1
|
||||
|
||||
o back_wall
|
||||
usemtl white
|
||||
v 549.6 0.0 559.2
|
||||
v 0.0 0.0 559.2
|
||||
v 0.0 548.8 559.2
|
||||
v 556.0 548.8 559.2
|
||||
f -4 -3 -2 -1
|
||||
|
||||
o front_wall
|
||||
usemtl blue
|
||||
v 549.6 0.0 0
|
||||
v 0.0 0.0 0
|
||||
v 0.0 548.8 0
|
||||
v 556.0 548.8 0
|
||||
#f -1 -2 -3 -4
|
||||
|
||||
o green_wall
|
||||
usemtl green
|
||||
v 0.0 0.0 559.2
|
||||
v 0.0 0.0 0.0
|
||||
v 0.0 548.8 0.0
|
||||
v 0.0 548.8 559.2
|
||||
f -4 -3 -2 -1
|
||||
|
||||
o red_wall
|
||||
usemtl red
|
||||
v 552.8 0.0 0.0
|
||||
v 549.6 0.0 559.2
|
||||
v 556.0 548.8 559.2
|
||||
v 556.0 548.8 0.0
|
||||
f -4 -3 -2 -1
|
||||
|
||||
o short_block
|
||||
usemtl glass
|
||||
|
||||
v 130.0 165.0 65.0
|
||||
v 82.0 165.0 225.0
|
||||
v 240.0 165.0 272.0
|
||||
v 290.0 165.0 114.0
|
||||
f -4 -3 -2 -1
|
||||
|
||||
v 290.0 0.0 114.0
|
||||
v 290.0 165.0 114.0
|
||||
v 240.0 165.0 272.0
|
||||
v 240.0 0.0 272.0
|
||||
f -4 -3 -2 -1
|
||||
|
||||
v 130.0 0.0 65.0
|
||||
v 130.0 165.0 65.0
|
||||
v 290.0 165.0 114.0
|
||||
v 290.0 0.0 114.0
|
||||
f -4 -3 -2 -1
|
||||
|
||||
v 82.0 0.0 225.0
|
||||
v 82.0 165.0 225.0
|
||||
v 130.0 165.0 65.0
|
||||
v 130.0 0.0 65.0
|
||||
f -4 -3 -2 -1
|
||||
|
||||
v 240.0 0.0 272.0
|
||||
v 240.0 165.0 272.0
|
||||
v 82.0 165.0 225.0
|
||||
v 82.0 0.0 225.0
|
||||
f -4 -3 -2 -1
|
||||
|
||||
o tall_block
|
||||
usemtl white
|
||||
|
||||
v 423.0 330.0 247.0
|
||||
v 265.0 330.0 296.0
|
||||
v 314.0 330.0 456.0
|
||||
v 472.0 330.0 406.0
|
||||
f -4 -3 -2 -1
|
||||
|
||||
usemtl white
|
||||
v 423.0 0.0 247.0
|
||||
v 423.0 330.0 247.0
|
||||
v 472.0 330.0 406.0
|
||||
v 472.0 0.0 406.0
|
||||
f -4 -3 -2 -1
|
||||
|
||||
v 472.0 0.0 406.0
|
||||
v 472.0 330.0 406.0
|
||||
v 314.0 330.0 456.0
|
||||
v 314.0 0.0 456.0
|
||||
f -4 -3 -2 -1
|
||||
|
||||
v 314.0 0.0 456.0
|
||||
v 314.0 330.0 456.0
|
||||
v 265.0 330.0 296.0
|
||||
v 265.0 0.0 296.0
|
||||
f -4 -3 -2 -1
|
||||
|
||||
v 265.0 0.0 296.0
|
||||
v 265.0 330.0 296.0
|
||||
v 423.0 330.0 247.0
|
||||
v 423.0 0.0 247.0
|
||||
f -4 -3 -2 -1
|
||||
|
||||
|
|
@ -1,2 +1,3 @@
|
|||
pub mod basic_scene;
|
||||
pub mod parse_obj;
|
||||
pub mod triangle_bvh;
|
||||
|
|
|
|||
403
ray-tracing-scene/src/parse_obj.rs
Normal file
403
ray-tracing-scene/src/parse_obj.rs
Normal file
|
|
@ -0,0 +1,403 @@
|
|||
use miette::{bail, miette, Context, IntoDiagnostic, LabeledSpan, Result, Severity};
|
||||
use nom::{
|
||||
branch::alt,
|
||||
bytes::complete::{tag, take_till, take_till1},
|
||||
character,
|
||||
error::Error,
|
||||
multi::{fill, many1},
|
||||
number::complete::double,
|
||||
Finish, IResult,
|
||||
};
|
||||
use ray_tracing_core::prelude::*;
|
||||
use std::{collections::HashMap, path::Path};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ObjData {
|
||||
pub vertices: Vec<Pos3>,
|
||||
pub normals: Vec<Dir3>,
|
||||
pub texcoord: Vec<[Float; 2]>,
|
||||
pub faces: Vec<Face>,
|
||||
pub materials: Vec<ObjMaterial>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ObjMaterial {
|
||||
name: String,
|
||||
map: HashMap<String, String>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Face {
|
||||
pub v: Vec<u32>,
|
||||
pub t: Option<Vec<u32>>,
|
||||
pub n: Option<Vec<u32>>,
|
||||
pub mat: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RelativeFace {
|
||||
pub v: Vec<i32>,
|
||||
pub t: Option<Vec<i32>>,
|
||||
pub n: Option<Vec<i32>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Line<'a> {
|
||||
Vertex(Pos3),
|
||||
Normal(Dir3),
|
||||
Texcoord([Float; 2]),
|
||||
Face(RelativeFace),
|
||||
Material(&'a str),
|
||||
Mtllib(&'a str),
|
||||
Empty,
|
||||
}
|
||||
|
||||
fn remove_whitespace(i: &str) -> IResult<&str, ()> {
|
||||
let (i, _) = take_till(|c| c != ' ')(i)?;
|
||||
Ok((i, ()))
|
||||
}
|
||||
|
||||
fn parse_float(i: &str) -> IResult<&str, Float> {
|
||||
let (i, _) = remove_whitespace(i)?;
|
||||
double(i).map(|(i, f)| (i, f as Float))
|
||||
}
|
||||
|
||||
fn parse_vertex(i: &str) -> IResult<&str, Line> {
|
||||
let mut v = [0.0; 3];
|
||||
let (i, _) = fill(parse_float, &mut v)(i)?;
|
||||
Ok((i, Line::Vertex(Pos3::new(v[0], v[1], v[2]))))
|
||||
}
|
||||
|
||||
fn parse_normal(i: &str) -> IResult<&str, Line> {
|
||||
let mut v = [0.0; 3];
|
||||
let (i, _) = fill(parse_float, &mut v)(i)?;
|
||||
Ok((i, Line::Normal(Dir3::new(v[0], v[1], v[2]))))
|
||||
}
|
||||
|
||||
fn parse_texcoord(i: &str) -> IResult<&str, Line> {
|
||||
let mut v = [0.0; 2];
|
||||
let (i, _) = fill(parse_float, &mut v)(i)?;
|
||||
Ok((i, Line::Texcoord(v)))
|
||||
}
|
||||
|
||||
fn parse_identifier(i: &str) -> IResult<&str, &str> {
|
||||
let (i, ()) = remove_whitespace(i)?;
|
||||
alt((tag("#"), take_till(|c| c == ' ')))(i)
|
||||
}
|
||||
|
||||
fn face_vertex_empty(i: &str) -> IResult<&str, i32> {
|
||||
let (i, _) = remove_whitespace(i)?;
|
||||
let (i, v) = character::complete::i32(i)?;
|
||||
|
||||
Ok((i, v))
|
||||
}
|
||||
fn face_vertex_normal(i: &str) -> IResult<&str, (i32, i32)> {
|
||||
let (i, _) = remove_whitespace(i)?;
|
||||
let (i, v) = character::complete::i32(i)?;
|
||||
let (i, _) = tag("//")(i)?;
|
||||
let (i, n) = character::complete::i32(i)?;
|
||||
|
||||
Ok((i, (v, n)))
|
||||
}
|
||||
fn face_vertex_tex(i: &str) -> IResult<&str, (i32, i32)> {
|
||||
let (i, _) = remove_whitespace(i)?;
|
||||
let (i, v) = character::complete::i32(i)?;
|
||||
let (i, _) = tag("/")(i)?;
|
||||
let (i, t) = character::complete::i32(i)?;
|
||||
|
||||
Ok((i, (v, t)))
|
||||
}
|
||||
fn face_vertex_normal_tex(i: &str) -> IResult<&str, (i32, i32, i32)> {
|
||||
let (i, _) = remove_whitespace(i)?;
|
||||
let (i, v) = character::complete::i32(i)?;
|
||||
let (i, _) = tag("/")(i)?;
|
||||
let (i, t) = character::complete::i32(i)?;
|
||||
let (i, _) = tag("/")(i)?;
|
||||
let (i, n) = character::complete::i32(i)?;
|
||||
|
||||
Ok((i, (v, t, n)))
|
||||
}
|
||||
|
||||
fn parse_face(i: &str) -> IResult<&str, Line> {
|
||||
if let Ok((i, s)) = many1(face_vertex_normal_tex)(i) {
|
||||
if s.len() >= 3 {
|
||||
Ok((
|
||||
i,
|
||||
Line::Face(RelativeFace {
|
||||
v: s.iter().map(|t| t.0).collect(),
|
||||
t: Some(s.iter().map(|t| t.1).collect()),
|
||||
n: Some(s.iter().map(|t| t.2).collect()),
|
||||
}),
|
||||
))
|
||||
} else {
|
||||
Err(nom::Err::Error(Error {
|
||||
input: i,
|
||||
code: nom::error::ErrorKind::Tag,
|
||||
}))
|
||||
}
|
||||
} else if let Ok((i, s)) = many1(face_vertex_normal)(i) {
|
||||
if s.len() >= 3 {
|
||||
Ok((
|
||||
i,
|
||||
Line::Face(RelativeFace {
|
||||
v: s.iter().map(|t| t.0).collect(),
|
||||
t: None,
|
||||
n: Some(s.iter().map(|t| t.1).collect()),
|
||||
}),
|
||||
))
|
||||
} else {
|
||||
Err(nom::Err::Error(Error {
|
||||
input: i,
|
||||
code: nom::error::ErrorKind::Tag,
|
||||
}))
|
||||
}
|
||||
} else if let Ok((i, s)) = many1(face_vertex_tex)(i) {
|
||||
if s.len() >= 3 {
|
||||
Ok((
|
||||
i,
|
||||
Line::Face(RelativeFace {
|
||||
v: s.iter().map(|t| t.0).collect(),
|
||||
t: Some(s.iter().map(|t| t.1).collect()),
|
||||
n: None,
|
||||
}),
|
||||
))
|
||||
} else {
|
||||
Err(nom::Err::Error(Error {
|
||||
input: i,
|
||||
code: nom::error::ErrorKind::Tag,
|
||||
}))
|
||||
}
|
||||
} else if let Ok((i, s)) = many1(face_vertex_empty)(i) {
|
||||
if s.len() >= 3 {
|
||||
Ok((
|
||||
i,
|
||||
Line::Face(RelativeFace {
|
||||
v: s,
|
||||
t: None,
|
||||
n: None,
|
||||
}),
|
||||
))
|
||||
} else {
|
||||
Err(nom::Err::Error(Error {
|
||||
input: i,
|
||||
code: nom::error::ErrorKind::Tag,
|
||||
}))
|
||||
}
|
||||
} else {
|
||||
Err(nom::Err::Error(Error {
|
||||
input: i,
|
||||
code: nom::error::ErrorKind::Tag,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_mtllib(i: &str) -> IResult<&str, Line> {
|
||||
let (i, s) = take_till(|c| c == ' ')(i)?;
|
||||
Ok((i, Line::Mtllib(s)))
|
||||
}
|
||||
|
||||
fn parse_mtl(i: &str) -> IResult<&str, Line> {
|
||||
let (i, s) = take_till(|c| c == ' ')(i)?;
|
||||
Ok((i, Line::Material(s)))
|
||||
}
|
||||
|
||||
fn parse_line(i: &str) -> IResult<&str, Line> {
|
||||
let (i, ident) = parse_identifier(i)?;
|
||||
let (i, _) = remove_whitespace(i)?;
|
||||
match ident {
|
||||
"v" => parse_vertex(i),
|
||||
"#" | "" => Ok((i, Line::Empty)),
|
||||
"f" => parse_face(i),
|
||||
"o" => Ok((i, Line::Empty)),
|
||||
"vn" => parse_normal(i),
|
||||
"vt" => parse_texcoord(i),
|
||||
"usemtl" => parse_mtl(i),
|
||||
"mtllib" => parse_mtllib(i),
|
||||
_ => Err(nom::Err::Failure(nom::error::Error {
|
||||
input: i,
|
||||
code: nom::error::ErrorKind::Fail,
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_relative(x: i32, len: i32) -> Result<u32> {
|
||||
if x == 0 {
|
||||
Err(miette!("Index cannot be 0"))
|
||||
} else if x > 0 {
|
||||
if x <= len {
|
||||
Ok(x as u32 - 1)
|
||||
} else {
|
||||
Err(miette!("Index {x} out of bounds"))
|
||||
}
|
||||
} else if len + x >= 0 {
|
||||
Ok((len + x) as u32)
|
||||
} else {
|
||||
Err(miette!("Index {x} out of bounds"))
|
||||
}
|
||||
}
|
||||
|
||||
enum MaterialsLine<'a> {
|
||||
Material(&'a str),
|
||||
KeyValue(&'a str, &'a str),
|
||||
Empty,
|
||||
}
|
||||
|
||||
fn parse_new_material(i: &str) -> IResult<&str, MaterialsLine> {
|
||||
let (i, ident) = take_till1(|c| c == ' ')(i)?;
|
||||
Ok((i, MaterialsLine::Material(ident)))
|
||||
}
|
||||
|
||||
fn parse_line_material(i: &str) -> IResult<&str, MaterialsLine> {
|
||||
let (i, ident) = parse_identifier(i)?;
|
||||
let (i, _) = remove_whitespace(i)?;
|
||||
match ident {
|
||||
"newmtl" => parse_new_material(i),
|
||||
"#" | "" => Ok((i, MaterialsLine::Empty)),
|
||||
_ => Ok((i, MaterialsLine::KeyValue(ident, i))),
|
||||
}
|
||||
}
|
||||
|
||||
fn read_mtllib(path: impl AsRef<Path>) -> Result<Vec<ObjMaterial>> {
|
||||
let string = std::fs::read_to_string(path.as_ref())
|
||||
.into_diagnostic()
|
||||
.with_context(|| format!("opening file {:?}", path.as_ref()))?;
|
||||
|
||||
let mut materials = Vec::new();
|
||||
|
||||
let mut current_material = None;
|
||||
|
||||
for (i, l) in string.lines().enumerate() {
|
||||
let t = match parse_line_material(l).finish() {
|
||||
Ok(t) => t.1,
|
||||
Err(e) => {
|
||||
return Err(miette!(
|
||||
severity = Severity::Error,
|
||||
code = e.code.description(),
|
||||
labels = vec![LabeledSpan::at_offset(l.len() - e.input.len(), "here")],
|
||||
"unable to parse line {}",
|
||||
i + 1
|
||||
)
|
||||
.with_source_code(l.to_string()));
|
||||
}
|
||||
};
|
||||
|
||||
match t {
|
||||
MaterialsLine::Material(name) => {
|
||||
if let Some(m) = current_material.take() {
|
||||
materials.push(m);
|
||||
}
|
||||
|
||||
current_material = Some(ObjMaterial {
|
||||
name: name.to_string(),
|
||||
map: HashMap::new(),
|
||||
});
|
||||
}
|
||||
MaterialsLine::KeyValue(k, v) => {
|
||||
if let Some(m) = current_material.as_mut() {
|
||||
m.map.insert(k.to_string(), v.to_string());
|
||||
} else {
|
||||
bail!("Material property appears multiple times in line {}", i + 1);
|
||||
}
|
||||
}
|
||||
MaterialsLine::Empty => (),
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(m) = current_material {
|
||||
materials.push(m);
|
||||
}
|
||||
|
||||
Ok(materials)
|
||||
}
|
||||
|
||||
impl ObjData {
|
||||
pub fn new(path: impl AsRef<Path>) -> Result<Self> {
|
||||
let string = std::fs::read_to_string(path.as_ref())
|
||||
.into_diagnostic()
|
||||
.with_context(|| format!("opening file {:?}", path.as_ref()))?;
|
||||
|
||||
let mut vertices = Vec::new();
|
||||
let mut normals = Vec::new();
|
||||
let mut texcoord = Vec::new();
|
||||
let mut faces = Vec::new();
|
||||
let mut materials = Vec::new();
|
||||
let mut materials_map = HashMap::new();
|
||||
|
||||
let mut current_material = None;
|
||||
|
||||
for (i, l) in string.lines().enumerate() {
|
||||
let t = match parse_line(l).finish() {
|
||||
Ok(t) => t.1,
|
||||
Err(e) => {
|
||||
return Err(miette!(
|
||||
severity = Severity::Error,
|
||||
code = e.code.description(),
|
||||
labels = vec![LabeledSpan::at_offset(l.len() - e.input.len(), "here")],
|
||||
"unable to parse line {}",
|
||||
i + 1
|
||||
)
|
||||
.with_source_code(l.to_string()));
|
||||
}
|
||||
};
|
||||
|
||||
match t {
|
||||
Line::Vertex(v) => vertices.push(v),
|
||||
Line::Normal(n) => normals.push(n),
|
||||
Line::Texcoord(t) => texcoord.push(t),
|
||||
Line::Face(f) => faces.push(Face {
|
||||
v: f.v
|
||||
.iter()
|
||||
.map(|&c| {
|
||||
handle_relative(c, vertices.len() as i32)
|
||||
.with_context(|| format!("In line {}", i + 1))
|
||||
})
|
||||
.collect::<Result<Vec<_>>>()?,
|
||||
t: f.t
|
||||
.map(|t| {
|
||||
t.iter()
|
||||
.map(|&c| {
|
||||
handle_relative(c, texcoord.len() as i32)
|
||||
.with_context(|| format!("In line {}", i + 1))
|
||||
})
|
||||
.collect::<Result<Vec<_>>>()
|
||||
})
|
||||
.transpose()?,
|
||||
n: f.n
|
||||
.map(|t| {
|
||||
t.iter()
|
||||
.map(|&c| {
|
||||
handle_relative(c, normals.len() as i32)
|
||||
.with_context(|| format!("In line {}", i + 1))
|
||||
})
|
||||
.collect::<Result<Vec<_>>>()
|
||||
})
|
||||
.transpose()?,
|
||||
mat: current_material,
|
||||
}),
|
||||
Line::Material(s) => {
|
||||
current_material = Some(
|
||||
*materials_map
|
||||
.get(s)
|
||||
.ok_or(miette!("Unknown material \"{s}\" in line {}", i + 1))?,
|
||||
);
|
||||
}
|
||||
Line::Mtllib(s) => {
|
||||
for m in read_mtllib(path.as_ref().parent().ok_or(miette!("Unable "))?.join(s))?
|
||||
{
|
||||
materials_map.insert(m.name.clone(), materials.len() as u32);
|
||||
materials.push(m);
|
||||
}
|
||||
}
|
||||
Line::Empty => (),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
vertices,
|
||||
normals,
|
||||
texcoord,
|
||||
faces,
|
||||
materials,
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue