| 44 | } |
| 45 | |
| 46 | fn main() -> Result<(), Box<dyn std::error::Error>> { |
| 47 | let cli = Cli::parse(); |
| 48 | |
| 49 | if cli.grid == 0 || cli.cell == 0 { |
| 50 | return Err("grid and cell must be > 0".into()); |
| 51 | } |
| 52 | |
| 53 | let output = cli.output.clone().unwrap_or_else(|| { |
| 54 | let mut p = cli.input.clone(); |
| 55 | let stem = p.file_stem().unwrap_or_default().to_string_lossy().to_string(); |
| 56 | p.set_file_name(format!("{stem}.imposter.png")); |
| 57 | p |
| 58 | }); |
| 59 | |
| 60 | println!("[imposter-baker] loading {}", cli.input.display()); |
| 61 | let mesh = gltf_load::load_glb(&cli.input)?; |
| 62 | println!( |
| 63 | "[imposter-baker] mesh: {} verts, {} indices, AABB [{:.3?} → {:.3?}], radius {:.3}", |
| 64 | mesh.positions.len(), |
| 65 | mesh.indices.len(), |
| 66 | mesh.aabb_min, |
| 67 | mesh.aabb_max, |
| 68 | mesh.radius() |
| 69 | ); |
| 70 | |
| 71 | let atlas_px = cli.grid * cli.cell; |
| 72 | println!( |
| 73 | "[imposter-baker] baking {0}x{0} grid @ {1}px/cell → {2}x{2} atlas", |
| 74 | cli.grid, cli.cell, atlas_px |
| 75 | ); |
| 76 | |
| 77 | let baked = render::bake(render::BakeOptions { |
| 78 | grid: cli.grid, |
| 79 | cell_px: cli.cell, |
| 80 | bake_color: true, |
| 81 | bake_normal: cli.normal.is_some(), |
| 82 | bake_depth: cli.depth.is_some(), |
| 83 | mesh: &mesh, |
| 84 | })?; |
| 85 | |
| 86 | if let Some(bytes) = &baked.color { |
| 87 | save_rgba(bytes, baked.width, baked.height, &output)?; |
| 88 | println!("[imposter-baker] color → {}", output.display()); |
| 89 | } |
| 90 | if let (Some(bytes), Some(path)) = (&baked.normal, &cli.normal) { |
| 91 | save_rgba(bytes, baked.width, baked.height, path)?; |
| 92 | println!("[imposter-baker] normal → {}", path.display()); |
| 93 | } |
| 94 | if let (Some(bytes), Some(path)) = (&baked.depth, &cli.depth) { |
| 95 | save_r8(bytes, baked.width, baked.height, path)?; |
| 96 | println!("[imposter-baker] depth → {}", path.display()); |
| 97 | } |
| 98 | |
| 99 | Ok(()) |
| 100 | } |
| 101 | |
| 102 | fn save_rgba(bytes: &[u8], w: u32, h: u32, path: &std::path::Path) -> Result<(), Box<dyn std::error::Error>> { |
| 103 | let img: image::RgbaImage = image::ImageBuffer::from_raw(w, h, bytes.to_vec()) |