Skip to main content

mittens_engine/
example_support.rs

1//! Helpers intended for `cargo run --example ...` binaries.
2
3use std::path::Path;
4use std::process::Command;
5
6/// Ensures the optional example GLB bundle exists under `assets/models`.
7///
8/// Crates.io packages omit GLB files to keep the engine crate small. Examples
9/// call this before scene construction so a crate checkout or installed package
10/// can restore the model bundle from the repository. The check is intentionally
11/// generic: if `assets/models` already contains at least one `.glb`, this does
12/// nothing.
13pub fn ensure_model_assets() {
14    if models_dir_has_glb() {
15        return;
16    }
17
18    let script = Path::new(env!("CARGO_MANIFEST_DIR")).join("scripts/download-model-assets.sh");
19    if !script.is_file() {
20        eprintln!(
21            "[example-assets] no .glb files found in assets/models, and downloader script is missing: {}",
22            script.display()
23        );
24        return;
25    }
26
27    println!(
28        "[example-assets] no .glb files found in assets/models; running {}",
29        script.display()
30    );
31
32    let output = Command::new("sh")
33        .arg(&script)
34        .current_dir(env!("CARGO_MANIFEST_DIR"))
35        .output();
36
37    match output {
38        Ok(output) => {
39            if !output.stdout.is_empty() {
40                print!("{}", String::from_utf8_lossy(&output.stdout));
41            }
42            if !output.stderr.is_empty() {
43                eprint!("{}", String::from_utf8_lossy(&output.stderr));
44            }
45            if !output.status.success() {
46                eprintln!(
47                    "[example-assets] model downloader exited with status {}",
48                    output.status
49                );
50            }
51        }
52        Err(error) => {
53            eprintln!(
54                "[example-assets] failed to run model downloader '{}': {error}",
55                script.display()
56            );
57        }
58    }
59}
60
61fn models_dir_has_glb() -> bool {
62    let models_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("assets/models");
63    let Ok(entries) = std::fs::read_dir(models_dir) else {
64        return false;
65    };
66
67    entries.filter_map(Result::ok).any(|entry| {
68        entry
69            .path()
70            .extension()
71            .and_then(|extension| extension.to_str())
72            .map(|extension| extension.eq_ignore_ascii_case("glb"))
73            .unwrap_or(false)
74    })
75}