use std::{fs::File, path::Path};
extern crate ply_rs;
use ply_rs::{
self as ply,
ply::{Property, PropertyAccess},
};
use crate::{Model3D, ModelError};
#[derive(Debug, Default, Clone, Copy)]
struct Vertex {
x: f32,
y: f32,
z: f32,
x_norm: Option<f32>,
y_norm: Option<f32>,
z_norm: Option<f32>,
tex_x: Option<f32>,
tex_y: Option<f32>,
}
impl PropertyAccess for Vertex {
fn new() -> Self {
Self::default()
}
fn set_property(&mut self, key: String, property: Property) {
match (key.as_ref(), property) {
("x", Property::Float(v)) => self.x = v,
("y", Property::Float(v)) => self.y = v,
("z", Property::Float(v)) => self.z = v,
("nx", Property::Float(v)) => self.x_norm = Some(v),
("ny", Property::Float(v)) => self.y_norm = Some(v),
("nz", Property::Float(v)) => self.z_norm = Some(v),
("u" | "s" | "tx" | "texture_u", Property::Float(v)) => self.tex_x = Some(v),
("v" | "t" | "ty" | "texture_v", Property::Float(v)) => self.tex_y = Some(v),
(k, _) => eprintln!("Vertex: Unexpected key/value combination: key: {k}"),
}
}
}
#[derive(Debug)]
struct Face {
vertex_index: Vec<u32>,
}
impl PropertyAccess for Face {
fn new() -> Self {
Self {
vertex_index: Vec::new(),
}
}
fn set_property(&mut self, key: String, property: Property) {
match (key.as_ref(), property) {
("vertex_index" | "vertex_indices", Property::ListUInt(vec)) => self.vertex_index = vec,
(k, _) => eprintln!("Face: Unexpected key/value combination: key: {k}"),
}
}
}
pub fn load(path: &Path) -> Result<Model3D, ModelError> {
let mut file = File::open(path).map_err(|e| ModelError::OpenFile(e.to_string()))?;
let mut reader = std::io::BufReader::new(&mut file);
let vertex_parser = ply::parser::Parser::<Vertex>::new();
let face_parser = ply::parser::Parser::<Face>::new();
let header = vertex_parser.read_header(&mut reader).unwrap();
let mut vertex_list = Vec::new();
let mut face_list = Vec::new();
for (_ignore_key, element) in &header.elements {
match element.name.as_ref() {
"vertex" => {
vertex_list = vertex_parser
.read_payload_for_element(&mut reader, element, &header)
.unwrap();
}
"face" => {
face_list = face_parser
.read_payload_for_element(&mut reader, element, &header)
.unwrap();
}
_ => panic!("Enexpeced element!"),
}
}
let mut vertices = Vec::new();
for face in face_list {
let vertex = vertex_list[face.vertex_index[0] as usize];
let vertex1 = vertex_list[face.vertex_index[1] as usize];
let vertex2 = vertex_list[face.vertex_index[2] as usize];
let mut normal = None;
let mut tex_coord = None;
if let Some(x) = vertex.x_norm {
if let Some(y) = vertex.z_norm {
if let Some(z) = vertex.z_norm {
normal = Some([x, y, z]);
}
}
}
if let Some(x) = vertex.tex_x {
if let Some(y) = vertex.tex_y {
tex_coord = Some([x, y]);
}
}
let v1 = crate::Vertex {
position: [vertex.x, vertex.y, vertex.z],
tex_coord,
color: None,
normal,
};
if let Some(x) = vertex1.x_norm {
if let Some(y) = vertex1.z_norm {
if let Some(z) = vertex1.z_norm {
normal = Some([x, y, z]);
}
}
}
if let Some(x) = vertex1.tex_x {
if let Some(y) = vertex1.tex_y {
tex_coord = Some([x, y]);
}
}
let v2 = crate::Vertex {
position: [vertex1.x, vertex1.y, vertex1.z],
tex_coord,
color: None,
normal,
};
if let Some(x) = vertex2.x_norm {
if let Some(y) = vertex2.z_norm {
if let Some(z) = vertex2.z_norm {
normal = Some([x, y, z]);
}
}
}
if let Some(x) = vertex2.tex_x {
if let Some(y) = vertex2.tex_y {
tex_coord = Some([x, y]);
}
}
let v3 = crate::Vertex {
position: [vertex2.x, vertex2.y, vertex2.z],
tex_coord,
color: None,
normal,
};
vertices.push(v1);
vertices.push(v2);
vertices.push(v3);
}
let mesh = crate::Mesh {
vertices,
indices: None,
material_index: None,
mode: crate::RenderMode::TriangleFan,
name: None,
};
Ok(Model3D {
meshes: vec![mesh],
materials: vec![],
format: crate::ModelFormat::PLY,
})
}