use std::io::{self, Write};
use std::path::Path;
#[cfg(any(
feature = "obj-writer",
feature = "ply-writer",
feature = "stl-writer",
feature = "fbx-writer"
))]
use draco_core::geometry_indices::PointIndex;
use draco_core::mesh::Mesh;
pub trait Writer: Sized {
fn new() -> Self;
fn add_mesh(&mut self, mesh: &Mesh, name: Option<&str>) -> io::Result<()>;
fn write<P: AsRef<Path>>(&self, path: P) -> io::Result<()>;
fn vertex_count(&self) -> usize;
fn face_count(&self) -> usize {
0
}
}
pub trait Reader: Sized {
fn open<P: AsRef<Path>>(path: P) -> io::Result<Self>;
fn read_meshes(&mut self) -> io::Result<Vec<Mesh>>;
fn read_mesh(&mut self) -> io::Result<Mesh> {
let meshes = self.read_meshes()?;
if let Some(m) = meshes.into_iter().next() {
Ok(m)
} else {
Err(io::Error::new(io::ErrorKind::InvalidData, "No mesh found"))
}
}
}
pub trait ReadFromBytes: Sized {
fn from_bytes(bytes: &[u8]) -> io::Result<Self>;
}
pub trait WriteToBytes: Writer {
fn write_to_vec(&self) -> io::Result<Vec<u8>>;
fn write_to<W: Write>(&self, writer: &mut W) -> io::Result<()> {
writer.write_all(&self.write_to_vec()?)
}
}
pub trait PointCloudWriter: Writer {
fn add_points(&mut self, points: &[[f32; 3]]);
fn add_point(&mut self, point: [f32; 3]) {
self.add_points(&[point]);
}
}
pub trait PointCloudReader: Reader {
fn read_points(&mut self) -> io::Result<Vec<[f32; 3]>>;
}
#[cfg(any(
feature = "obj-writer",
feature = "ply-writer",
feature = "stl-writer",
feature = "fbx-writer"
))]
pub(crate) fn ensure_attributes_cover_points(mesh: &Mesh, format: &str) -> io::Result<()> {
let num_points = mesh.num_points();
for att_id in 0..mesh.num_attributes() {
let attribute = mesh.attribute(att_id);
if attribute.is_mapping_identity() {
if attribute.size() < num_points {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!(
"{format} writer: attribute {att_id} ({:?}) holds {} values for {num_points} points",
attribute.attribute_type(),
attribute.size(),
),
));
}
continue;
}
for point in 0..num_points {
let value = attribute.mapped_index(PointIndex(point as u32)).0 as usize;
if value >= attribute.size() {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!(
"{format} writer: attribute {att_id} ({:?}) maps point {point} to value {value} of {}",
attribute.attribute_type(),
attribute.size(),
),
));
}
}
}
Ok(())
}
#[cfg(any(
feature = "obj-writer",
feature = "ply-writer",
feature = "stl-writer",
feature = "fbx-writer"
))]
pub(crate) fn value_offset(attribute: &draco_core::PointAttribute, point: usize) -> usize {
let value = if attribute.is_mapping_identity() {
point
} else {
attribute.mapped_index(PointIndex(point as u32)).0 as usize
};
value.saturating_mul(attribute.byte_stride() as usize)
}
#[cfg(any(feature = "obj-reader", feature = "ply-reader"))]
pub(crate) fn finalize_mesh(mesh: &mut draco_core::mesh::Mesh) -> std::io::Result<()> {
mesh.finalize()
.map_err(|error| std::io::Error::new(std::io::ErrorKind::InvalidData, error.to_string()))
}