#![allow(dead_code)]
#[derive(Clone, Debug, Default)]
pub struct PlyBinaryExport {
pub positions: Vec<[f32; 3]>,
pub normals: Vec<[f32; 3]>,
pub indices: Vec<u32>,
}
pub fn new_ply_binary_export() -> PlyBinaryExport {
PlyBinaryExport::default()
}
pub fn ply_binary_set_mesh(
doc: &mut PlyBinaryExport,
positions: Vec<[f32; 3]>,
normals: Vec<[f32; 3]>,
indices: Vec<u32>,
) {
doc.positions = positions;
doc.normals = normals;
doc.indices = indices;
}
pub fn ply_binary_vertex_count(doc: &PlyBinaryExport) -> usize {
doc.positions.len()
}
pub fn ply_binary_face_count(doc: &PlyBinaryExport) -> usize {
doc.indices.len() / 3
}
pub fn ply_binary_header(doc: &PlyBinaryExport) -> String {
let has_normals = !doc.normals.is_empty();
let mut h = String::from("ply\nformat binary_little_endian 1.0\n");
h.push_str(&format!(
"element vertex {}\n",
ply_binary_vertex_count(doc)
));
h.push_str("property float x\nproperty float y\nproperty float z\n");
if has_normals {
h.push_str("property float nx\nproperty float ny\nproperty float nz\n");
}
h.push_str(&format!("element face {}\n", ply_binary_face_count(doc)));
h.push_str("property list uchar uint vertex_indices\n");
h.push_str("end_header\n");
h
}
pub fn ply_binary_vertex_bytes(doc: &PlyBinaryExport) -> Vec<u8> {
let has_normals = !doc.normals.is_empty();
let mut out = Vec::new();
for (i, &p) in doc.positions.iter().enumerate() {
out.extend_from_slice(&p[0].to_le_bytes());
out.extend_from_slice(&p[1].to_le_bytes());
out.extend_from_slice(&p[2].to_le_bytes());
if has_normals {
if let Some(&n) = doc.normals.get(i) {
out.extend_from_slice(&n[0].to_le_bytes());
out.extend_from_slice(&n[1].to_le_bytes());
out.extend_from_slice(&n[2].to_le_bytes());
}
}
}
out
}
pub fn ply_binary_face_bytes(doc: &PlyBinaryExport) -> Vec<u8> {
let mut out = Vec::new();
let tri_count = doc.indices.len() / 3;
for t in 0..tri_count {
out.push(3u8); for k in 0..3 {
let idx = doc.indices[t * 3 + k];
out.extend_from_slice(&idx.to_le_bytes());
}
}
out
}
pub fn export_ply_binary(doc: &PlyBinaryExport) -> Vec<u8> {
let header = ply_binary_header(doc);
let mut out = header.into_bytes();
out.extend(ply_binary_vertex_bytes(doc));
out.extend(ply_binary_face_bytes(doc));
out
}
pub fn ply_binary_size_estimate(doc: &PlyBinaryExport) -> usize {
let has_normals = !doc.normals.is_empty();
let verts_per_vertex = if has_normals { 6 } else { 3 };
let vertex_bytes = ply_binary_vertex_count(doc) * verts_per_vertex * 4;
let face_bytes = ply_binary_face_count(doc) * (1 + 3 * 4);
ply_binary_header(doc).len() + vertex_bytes + face_bytes
}
pub fn validate_ply_binary(doc: &PlyBinaryExport) -> bool {
if doc.positions.is_empty() {
return false;
}
let n = doc.positions.len() as u32;
doc.indices.iter().all(|&i| i < n)
}
#[cfg(test)]
mod tests {
use super::*;
fn simple() -> PlyBinaryExport {
let mut d = new_ply_binary_export();
ply_binary_set_mesh(
&mut d,
vec![[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]],
vec![],
vec![0, 1, 2],
);
d
}
#[test]
fn vertex_count() {
let d = simple();
assert_eq!(ply_binary_vertex_count(&d), 3);
}
#[test]
fn face_count() {
let d = simple();
assert_eq!(ply_binary_face_count(&d), 1);
}
#[test]
fn header_contains_ply() {
let d = simple();
let h = ply_binary_header(&d);
assert!(h.starts_with("ply\n"));
}
#[test]
fn header_contains_binary() {
let d = simple();
let h = ply_binary_header(&d);
assert!(h.contains("binary_little_endian"));
}
#[test]
fn vertex_bytes_correct_size() {
let d = simple();
let bytes = ply_binary_vertex_bytes(&d);
assert_eq!(bytes.len(), 3 * 3 * 4); }
#[test]
fn face_bytes_correct_size() {
let d = simple();
let bytes = ply_binary_face_bytes(&d);
assert_eq!(bytes.len(), 1 + 3 * 4); }
#[test]
fn export_ply_binary_non_empty() {
let d = simple();
let bytes = export_ply_binary(&d);
assert!(!bytes.is_empty());
}
#[test]
fn validate_valid() {
let d = simple();
assert!(validate_ply_binary(&d));
}
}