Skip to main content

gltf_tool/
gltf_tool.rs

1//! Small deterministic interoperability helper used by CI and by humans.
2
3use std::io;
4use std::path::PathBuf;
5
6use draco_gltf::{CompressionOptions, Import, MeshIndex, OutputFormat};
7
8fn decoded_draco_stats(import: &Import) -> Result<(usize, usize), Box<dyn std::error::Error>> {
9    let mut primitives = 0usize;
10    let mut faces = 0usize;
11    for primitive in import.draco_primitives() {
12        let mesh = import.decode_draco_primitive(primitive)?;
13        if mesh.num_faces() == 0 {
14            return Err(io::Error::new(
15                io::ErrorKind::InvalidData,
16                "Draco primitive decoded to zero faces",
17            )
18            .into());
19        }
20        primitives = primitives.checked_add(1).ok_or_else(|| {
21            io::Error::new(
22                io::ErrorKind::InvalidData,
23                "decoded primitive count overflow",
24            )
25        })?;
26        faces = faces.checked_add(mesh.num_faces()).ok_or_else(|| {
27            io::Error::new(io::ErrorKind::InvalidData, "decoded face count overflow")
28        })?;
29    }
30    if primitives == 0 || faces == 0 {
31        return Err(io::Error::new(
32            io::ErrorKind::InvalidData,
33            "document contains no decodable Draco triangle faces",
34        )
35        .into());
36    }
37    Ok((primitives, faces))
38}
39
40fn main() -> Result<(), Box<dyn std::error::Error>> {
41    let mut args = std::env::args_os().skip(1);
42    let input = PathBuf::from(args.next().ok_or_else(|| {
43        io::Error::new(
44            io::ErrorKind::InvalidInput,
45            "usage: gltf_tool <input.gltf|input.glb> [output.glb]",
46        )
47    })?);
48    let output = args.next().map(PathBuf::from);
49    if args.next().is_some() {
50        return Err(io::Error::new(io::ErrorKind::InvalidInput, "too many arguments").into());
51    }
52
53    let mut import = draco_gltf::import(&input)?;
54    if let Some(output) = output {
55        let report = import.compress_primitive(MeshIndex(0), 0, CompressionOptions::default())?;
56        let bytes = import.to_bytes(OutputFormat::GlbV2)?;
57        std::fs::write(output, bytes)?;
58        println!("compression_report={report:?}");
59    } else {
60        let (primitives, faces) = decoded_draco_stats(&import)?;
61        println!("decoded_draco_primitives={primitives} decoded_faces={faces}");
62    }
63    Ok(())
64}