#![allow(dead_code)]
#[derive(Clone, Debug)]
pub struct WrlShape {
pub positions: Vec<[f32; 3]>,
pub indices: Vec<i32>,
pub diffuse_color: [f32; 3],
}
#[derive(Clone, Debug, Default)]
pub struct WrlDocument {
pub shapes: Vec<WrlShape>,
}
pub fn new_wrl_document() -> WrlDocument {
WrlDocument::default()
}
pub fn wrl_add_shape(
doc: &mut WrlDocument,
positions: Vec<[f32; 3]>,
indices: Vec<u32>,
color: [f32; 3],
) {
let mut vrml_idx: Vec<i32> = Vec::new();
for chunk in indices.chunks(3) {
if chunk.len() == 3 {
vrml_idx.push(chunk[0] as i32);
vrml_idx.push(chunk[1] as i32);
vrml_idx.push(chunk[2] as i32);
vrml_idx.push(-1);
}
}
doc.shapes.push(WrlShape {
positions,
indices: vrml_idx,
diffuse_color: color,
});
}
pub fn wrl_shape_count(doc: &WrlDocument) -> usize {
doc.shapes.len()
}
pub fn wrl_total_vertex_count(doc: &WrlDocument) -> usize {
doc.shapes.iter().map(|s| s.positions.len()).sum()
}
pub fn render_wrl(doc: &WrlDocument) -> String {
let mut out = String::from("#VRML V2.0 utf8\n# Generated by oxihuman\n");
for shape in &doc.shapes {
let [r, g, b] = shape.diffuse_color;
let pts: Vec<String> = shape
.positions
.iter()
.map(|p| format!("{:.4} {:.4} {:.4}", p[0], p[1], p[2]))
.collect();
let idx: Vec<String> = shape.indices.iter().map(|i| i.to_string()).collect();
out.push_str("Shape {\n");
out.push_str(&format!(
" appearance Appearance {{ material Material {{ diffuseColor {:.4} {:.4} {:.4} }} }}\n",
r, g, b
));
out.push_str(" geometry IndexedFaceSet {\n");
out.push_str(&format!(
" coord Coordinate {{ point [ {} ] }}\n",
pts.join(", ")
));
out.push_str(&format!(" coordIndex [ {} ]\n", idx.join(", ")));
out.push_str(" }\n}\n");
}
out
}
pub fn wrl_size_estimate(doc: &WrlDocument) -> usize {
render_wrl(doc).len()
}
pub fn validate_wrl(doc: &WrlDocument) -> bool {
doc.shapes.iter().all(|s| {
!s.positions.is_empty() && s.diffuse_color.iter().all(|&c| (0.0..=1.0).contains(&c))
})
}
pub fn export_mesh_as_wrl(positions: &[[f32; 3]], indices: &[u32], color: [f32; 3]) -> WrlDocument {
let mut doc = new_wrl_document();
wrl_add_shape(&mut doc, positions.to_vec(), indices.to_vec(), color);
doc
}
#[cfg(test)]
mod tests {
use super::*;
fn simple_doc() -> WrlDocument {
export_mesh_as_wrl(
&[[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]],
&[0, 1, 2],
[0.8, 0.5, 0.2],
)
}
#[test]
fn shape_count_one() {
let d = simple_doc();
assert_eq!(wrl_shape_count(&d), 1);
}
#[test]
fn total_vertex_count() {
let d = simple_doc();
assert_eq!(wrl_total_vertex_count(&d), 3);
}
#[test]
fn render_starts_with_vrml() {
let d = simple_doc();
assert!(render_wrl(&d).starts_with("#VRML V2.0"));
}
#[test]
fn render_contains_shape() {
let d = simple_doc();
assert!(render_wrl(&d).contains("Shape {"));
}
#[test]
fn render_contains_indexed_face_set() {
let d = simple_doc();
assert!(render_wrl(&d).contains("IndexedFaceSet"));
}
#[test]
fn validate_valid_doc() {
let d = simple_doc();
assert!(validate_wrl(&d));
}
#[test]
fn wrl_size_estimate_positive() {
let d = simple_doc();
assert!(wrl_size_estimate(&d) > 0);
}
#[test]
fn indices_have_minus_one_terminator() {
let d = simple_doc();
let shape = &d.shapes[0];
assert!(shape.indices.contains(&-1));
}
}