//! **El camino de vuelta**: lo que se compone acá sale al editor ajeno. //! //! Arma un par de casas procedurales (cada una con su semilla) y las escribe como //! escena `.vox` — modelos + grafo de colocación, que es lo que MagicaVoxel abre con //! las piezas separadas y ubicadas, no fundidas en un bloque. Después la vuelve a //! leer y **compara**, que es la única forma de saber que el archivo sirve sin //! abrirlo. //! //! ```bash //! cargo run -p llimphi-voxel --example exportar_vox --release //! ``` //! //! Deja `/tmp/tawasuyu_barrio.vox` (escena de dos casas) y `/tmp/tawasuyu_casa.vox` //! (una sola, `.vox` clásico). use foreign_vox::{Placement, Rot}; use llimphi_3d::VoxelGrid; use llimphi_voxel::{grid_to_model, save_grid, scene_to_grid, CasaTipo}; fn solidos(g: &VoxelGrid) -> usize { let d = g.dim(); let mut n = 0; for x in 0..d[0] { for y in 0..d[1] { for z in 0..d[2] { if g.is_solid(x as i32, y as i32, z as i32) { n += 1; } } } } n } fn casa(tipo: CasaTipo, seed: u32) -> VoxelGrid { let mut g = VoxelGrid::new([24, 24, 24]); llimphi_voxel::stamp_casa(&mut g, tipo, 12, 0, 12, seed); g } fn main() { // --- Una casa sola: el `.vox` clásico de un modelo. let cabana = casa(CasaTipo::Cabana, 7); save_grid("/tmp/tawasuyu_casa.vox", &cabana).expect("escribir la casa"); let leida = llimphi_voxel::load_grid("/tmp/tawasuyu_casa.vox").expect("releer la casa"); println!( "casa sola : {} voxels → /tmp/tawasuyu_casa.vox → releída {} voxels {}", solidos(&cabana), solidos(&leida), if solidos(&cabana) == solidos(&leida) { "✓" } else { "✗" } ); // --- Dos casas como ESCENA: cada una es un modelo con su lugar (y una girada). let moderna = casa(CasaTipo::Moderna, 3); let hobbit = casa(CasaTipo::Hobbit, 11); let modelos = vec![ grid_to_model(&moderna).expect("exportar moderna"), grid_to_model(&hobbit).expect("exportar hobbit"), ]; let colocaciones = vec![ Placement { model: 0, translation: [0, 0, 0], rotation: Rot::IDENTITY }, // La segunda, corrida 30 voxels y girada un cuarto de vuelta. Placement { model: 1, translation: [30, 0, 0], rotation: Rot::from_byte(17) }, ]; let bytes = foreign_vox::write_scene(&modelos, &colocaciones); std::fs::write("/tmp/tawasuyu_barrio.vox", &bytes).expect("escribir el barrio"); println!("barrio : {} bytes → /tmp/tawasuyu_barrio.vox", bytes.len()); // --- Y se relee: los dos modelos, sus lugares y su rotación. let escena = foreign_vox::parse_scene(&bytes).expect("releer el barrio"); println!( " : {} modelos, {} colocaciones, rotación de la 2ª = {}", escena.models.len(), escena.placements.len(), escena.placements.iter().find(|p| p.model == 1).map(|p| p.rotation.to_byte()).unwrap_or(0) ); let compuesto = scene_to_grid(&escena); let esperado = solidos(&moderna) + solidos(&hobbit); println!( "compuesto : {:?} = {} voxels (las dos casas juntas: {}) {}", compuesto.dim(), solidos(&compuesto), esperado, if solidos(&compuesto) == esperado { "✓" } else { "✗ se pisan o se pierden" } ); }