gioser

tawasuyu/llimphi

Sovereign retained-mode GPU UI framework in Rust (wgpu+vello+taffy+parley), Elm loop, 40+ widgets.

Rust 614Markdown 274TOML 149RON 310606 Definitions

⎇ main llimphi-voxel/src/bicho.rs Rust · 1124 lines · 40.3 KB History Who touched what raw

chore: refresco desde el monorepo (pin tawasuyu.git v0.3.0) b575c63f1 · Sergio ·

1//! **Seres del bioma (fauna procedural)**: un catálogo de modelitos voxel de
2//! animales (vaca, oveja, ciervo, zorro, oso, caballo…) que **pueblan el mundo
3//! por semilla**, como la flora y las casas. A diferencia de un [`Mueble`](crate::Mueble)
4//! (prop de interior, colocado a mano), un [`Bicho`] lo **esparce el bioma**: el
5//! campo `fauna` del [`Bioma`](crate::Bioma) dice qué animales y con qué densidad,
6//! y [`generate_window`](crate::Bioma::generate_window) los siembra parados sobre
7//! el terreno, orientados al azar.
8//!
9//! Los animales usan **color RGB directo** (no [`Material`](crate::worldgen::Material)):
10//! el rosa del cerdo o el naranja del zorro no viven en la paleta de terreno. Son
11//! mates (sin brillo). Se orientan con `facing` (0=+Z, 1=+X, 2=−Z, 3=−X).
12
13use serde::{Deserialize, Serialize};
14
15use llimphi_3d::VoxelGrid;
16
17/// Catálogo de seres/animales que pueblan un bioma.
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
19pub enum Bicho {
20    /// Vaca: cuerpo blanco con manchas negras, cabeza y cuernos.
21    Vaca,
22    /// Oveja: cuerpo lanudo blanco, cara oscura.
23    Oveja,
24    /// Cerdo: cuerpo rosado, hocico y colita.
25    Cerdo,
26    /// Gallina: cuerpo blanco chico, cresta roja y pico.
27    Gallina,
28    /// Ciervo: cuerpo marrón, patas largas y astas.
29    Ciervo,
30    /// Conejo: cuerpo chico con orejas largas.
31    Conejo,
32    /// Zorro: cuerpo naranja, pecho blanco y cola tupida.
33    Zorro,
34    /// Lobo: cuerpo gris alargado, orejas y cola.
35    Lobo,
36    /// Oso: cuerpo marrón voluminoso, cabeza redonda.
37    Oso,
38    /// Caballo: cuerpo marrón alto, cuello, crin y cola.
39    Caballo,
40    /// Pájaro: cuerpo diminuto con alas y pico (posado).
41    Pajaro,
42    /// Pez: cuerpo con aleta caudal (para el agua/orilla).
43    Pez,
44    /// Tortuga: caparazón verde abovedado, cabeza y patas.
45    Tortuga,
46    /// Rana: cuerpo verde agazapado, ojos saltones.
47    Rana,
48    /// Serpiente: cuerpo largo y bajo en zigzag, con cabeza.
49    Serpiente,
50    /// Mariposa: cuerpecito con cuatro alas coloridas (revolotea bajo).
51    Mariposa,
52    // --- Granja / pradera ---
53    /// Pato: cuerpo blanco chico, pico naranja (orilla/pradera).
54    Pato,
55    /// Cabra: cuerpo claro con cuernitos (montaña/granja).
56    Cabra,
57    /// Burro: cuerpo gris con orejas largas (granja).
58    Burro,
59    // --- Bosque ---
60    /// Ardilla: cuerpito con cola tupida enroscada (bosque).
61    Ardilla,
62    /// Búho: cuerpo compacto con ojos grandes, posado (bosque).
63    Buho,
64    /// Erizo: lomo de púas oscuras, cara clara (bosque).
65    Erizo,
66    // --- Desierto ---
67    /// Camello: cuerpo arena con joroba y cuello (desierto).
68    Camello,
69    /// Escorpión: cuerpo bajo con pinzas y cola en alto (desierto).
70    Escorpion,
71    /// Lagarto: cuerpo verde alargado y bajo (desierto/selva).
72    Lagarto,
73    // --- Nieve / agua fría ---
74    /// Pingüino: cuerpo negro con panza blanca, pico naranja (nieve).
75    Pinguino,
76    /// Foca: cuerpo gris tendido con aletas (nieve/agua).
77    Foca,
78    // --- Selva / sabana ---
79    /// Mono: cuerpo marrón con cola larga (selva).
80    Mono,
81    /// Loro: cuerpo verde con pecho rojo y pico (selva).
82    Loro,
83    /// Tigre: cuerpo naranja con rayas negras (selva).
84    Tigre,
85    /// Elefante: cuerpo gris grande con trompa y orejas (sabana).
86    Elefante,
87    /// Cocodrilo: cuerpo verde largo y bajo con fauces (selva/agua).
88    Cocodrilo,
89    // --- El bestiario SDF (2026-09-06) -------------------------------------
90    // Variantes SIEMPRE al final: `BichoUso` viaja en postcard, que numera por
91    // posición — una al medio corre a todas las de abajo y un mundo guardado
92    // cambia de fauna sin decir nada.
93    //
94    // Estas nacieron para la segunda técnica de graficación (`bicho_sdf`), que
95    // las arma de primitivas analíticas. En VOXEL no tienen estampa propia:
96    // `silueta_voxel` las manda a la de un pariente, que es el LOD lejano.
97    /// Perro: compañía, orejas caídas y cola tupida.
98    Perro,
99    /// Gato: lomo arqueado, orejas en punta y cola larga.
100    Gato,
101    /// Toro: cuello macizo, morrillo y cuernos en lira.
102    Toro,
103    /// Alce: cruz alta, hocico largo y astas palmeadas.
104    Alce,
105    /// Mapache: antifaz oscuro y cola anillada.
106    Mapache,
107    /// Ratón: orejas redondas grandes y cola pelada.
108    Raton,
109    /// Panda: blanco y negro, cara chata, orejas redondas.
110    Panda,
111    /// Koala: orejas mullidas enormes, sin cola.
112    Koala,
113    /// Canguro: bípedo, cola gruesa de contrapeso.
114    Canguro,
115    /// Llama: cuello largo lanudo (andes).
116    Llama,
117    /// Jirafa: cuello altísimo y manchas.
118    Jirafa,
119    /// León: melena alrededor del cuello y cola con penacho.
120    Leon,
121    /// Cebra: caballo a rayas.
122    Cebra,
123    /// Jaguar: felino manchado de la selva.
124    Jaguar,
125    /// Hipopótamo: cuerpo bajo y bocaza.
126    Hipopotamo,
127    /// Rinoceronte: cuerno nasal y piel de placas.
128    Rinoceronte,
129    /// Capibara: roedor grande y tranquilo de ribera.
130    Capibara,
131    /// Perezoso: brazos largos, cara serena, sin cola.
132    Perezoso,
133    /// Gorrión: pajarito pardo de ciudad.
134    Gorrion,
135    /// Cardenal: rojo con copete.
136    Cardenal,
137    /// Cuervo: negro entero, pico recto.
138    Cuervo,
139    /// Colibrí: pico aguja y alas en batido.
140    Colibri,
141    /// Guacamayo: rojo/azul/amarillo con cola larguísima.
142    Guacamayo,
143    /// Tucán: pico enorme naranja.
144    Tucan,
145    /// Quetzal: verde metálico con cola de dos plumas largas.
146    Quetzal,
147    /// Flamenco: zancudo rosado de cuello en S.
148    Flamenco,
149    /// Garza: zancuda blanca de pico largo.
150    Garza,
151    /// Cisne: cuello en S y pico naranja.
152    Cisne,
153    /// Ganso: cuello mediano, pico pala.
154    Ganso,
155    /// Pelícano: pico con bolsa.
156    Pelicano,
157    /// Águila: pico ganchudo y alas abiertas.
158    Aguila,
159    /// Cóndor: planeador enorme de collar blanco.
160    Condor,
161    /// Pavo real: rueda de ocelos y copete.
162    PavoReal,
163    /// Avestruz: patas largas, cuello pelado.
164    Avestruz,
165    /// Martín pescador: azul con pico largo y copete.
166    Martin,
167    /// Gallo: cresta roja y cola en abanico.
168    Gallo,
169    /// Boa: serpiente gruesa con rombos.
170    Boa,
171    /// Cobra: capucha desplegada y tercio delantero alzado.
172    Cobra,
173    /// Iguana: cresta dorsal de púas.
174    Iguana,
175    /// Camaleón: cuerpo alto y comprimido, ojos saltones.
176    Camaleon,
177    /// Salamandra: negra con manchas amarillas.
178    Salamandra,
179    /// Delfín: hocico y cola horizontal.
180    Delfin,
181    /// Ballena: cuerpo enorme y cola horizontal.
182    Ballena,
183    /// Tiburón: aleta dorsal alta y boca abajo.
184    Tiburon,
185    /// Pulpo: manto y ocho tentáculos.
186    Pulpo,
187    /// Abeja: rayas y alas de membrana.
188    Abeja,
189    /// Libélula: abdomen largo y cuatro alas.
190    Libelula,
191    /// Escarabajo: élitros duros con lunares.
192    Escarabajo,
193    /// Hormiga: tres segmentos y seis patas.
194    Hormiga,
195    /// Araña: ocho patas arqueadas.
196    Arana,
197    /// Cangrejo: caparazón plano, pinzas y ojos en pedúnculo.
198    Cangrejo,
199    /// Caracol: concha en espiral y cuernitos.
200    Caracol,
201    /// Luciérnaga: élitros oscuros y abdomen luminoso.
202    Luciernaga,
203}
204
205impl Bicho {
206    pub const ALL: [Bicho; 85] = [
207        Bicho::Vaca,
208        Bicho::Oveja,
209        Bicho::Cerdo,
210        Bicho::Gallina,
211        Bicho::Ciervo,
212        Bicho::Conejo,
213        Bicho::Zorro,
214        Bicho::Lobo,
215        Bicho::Oso,
216        Bicho::Caballo,
217        Bicho::Pajaro,
218        Bicho::Pez,
219        Bicho::Tortuga,
220        Bicho::Rana,
221        Bicho::Serpiente,
222        Bicho::Mariposa,
223        Bicho::Pato,
224        Bicho::Cabra,
225        Bicho::Burro,
226        Bicho::Ardilla,
227        Bicho::Buho,
228        Bicho::Erizo,
229        Bicho::Camello,
230        Bicho::Escorpion,
231        Bicho::Lagarto,
232        Bicho::Pinguino,
233        Bicho::Foca,
234        Bicho::Mono,
235        Bicho::Loro,
236        Bicho::Tigre,
237        Bicho::Elefante,
238        Bicho::Cocodrilo,
239        Bicho::Perro,
240        Bicho::Gato,
241        Bicho::Toro,
242        Bicho::Alce,
243        Bicho::Mapache,
244        Bicho::Raton,
245        Bicho::Panda,
246        Bicho::Koala,
247        Bicho::Canguro,
248        Bicho::Llama,
249        Bicho::Jirafa,
250        Bicho::Leon,
251        Bicho::Cebra,
252        Bicho::Jaguar,
253        Bicho::Hipopotamo,
254        Bicho::Rinoceronte,
255        Bicho::Capibara,
256        Bicho::Perezoso,
257        Bicho::Gorrion,
258        Bicho::Cardenal,
259        Bicho::Cuervo,
260        Bicho::Colibri,
261        Bicho::Guacamayo,
262        Bicho::Tucan,
263        Bicho::Quetzal,
264        Bicho::Flamenco,
265        Bicho::Garza,
266        Bicho::Cisne,
267        Bicho::Ganso,
268        Bicho::Pelicano,
269        Bicho::Aguila,
270        Bicho::Condor,
271        Bicho::PavoReal,
272        Bicho::Avestruz,
273        Bicho::Martin,
274        Bicho::Gallo,
275        Bicho::Boa,
276        Bicho::Cobra,
277        Bicho::Iguana,
278        Bicho::Camaleon,
279        Bicho::Salamandra,
280        Bicho::Delfin,
281        Bicho::Ballena,
282        Bicho::Tiburon,
283        Bicho::Pulpo,
284        Bicho::Abeja,
285        Bicho::Libelula,
286        Bicho::Escarabajo,
287        Bicho::Hormiga,
288        Bicho::Arana,
289        Bicho::Cangrejo,
290        Bicho::Caracol,
291        Bicho::Luciernaga,
292    ];
293
294    pub fn label(self) -> &'static str {
295        match self {
296            Bicho::Vaca => "vaca",
297            Bicho::Oveja => "oveja",
298            Bicho::Cerdo => "cerdo",
299            Bicho::Gallina => "gallina",
300            Bicho::Ciervo => "ciervo",
301            Bicho::Conejo => "conejo",
302            Bicho::Zorro => "zorro",
303            Bicho::Lobo => "lobo",
304            Bicho::Oso => "oso",
305            Bicho::Caballo => "caballo",
306            Bicho::Pajaro => "pájaro",
307            Bicho::Pez => "pez",
308            Bicho::Tortuga => "tortuga",
309            Bicho::Rana => "rana",
310            Bicho::Serpiente => "serpiente",
311            Bicho::Mariposa => "mariposa",
312            Bicho::Pato => "pato",
313            Bicho::Cabra => "cabra",
314            Bicho::Burro => "burro",
315            Bicho::Ardilla => "ardilla",
316            Bicho::Buho => "búho",
317            Bicho::Erizo => "erizo",
318            Bicho::Camello => "camello",
319            Bicho::Escorpion => "escorpión",
320            Bicho::Lagarto => "lagarto",
321            Bicho::Pinguino => "pingüino",
322            Bicho::Foca => "foca",
323            Bicho::Mono => "mono",
324            Bicho::Loro => "loro",
325            Bicho::Tigre => "tigre",
326            Bicho::Elefante => "elefante",
327            Bicho::Cocodrilo => "cocodrilo",
328            Bicho::Perro => "perro",
329            Bicho::Gato => "gato",
330            Bicho::Toro => "toro",
331            Bicho::Alce => "alce",
332            Bicho::Mapache => "mapache",
333            Bicho::Raton => "ratón",
334            Bicho::Panda => "panda",
335            Bicho::Koala => "koala",
336            Bicho::Canguro => "canguro",
337            Bicho::Llama => "llama",
338            Bicho::Jirafa => "jirafa",
339            Bicho::Leon => "león",
340            Bicho::Cebra => "cebra",
341            Bicho::Jaguar => "jaguar",
342            Bicho::Hipopotamo => "hipopótamo",
343            Bicho::Rinoceronte => "rinoceronte",
344            Bicho::Capibara => "capibara",
345            Bicho::Perezoso => "perezoso",
346            Bicho::Gorrion => "gorrión",
347            Bicho::Cardenal => "cardenal",
348            Bicho::Cuervo => "cuervo",
349            Bicho::Colibri => "colibrí",
350            Bicho::Guacamayo => "guacamayo",
351            Bicho::Tucan => "tucán",
352            Bicho::Quetzal => "quetzal",
353            Bicho::Flamenco => "flamenco",
354            Bicho::Garza => "garza",
355            Bicho::Cisne => "cisne",
356            Bicho::Ganso => "ganso",
357            Bicho::Pelicano => "pelícano",
358            Bicho::Aguila => "águila",
359            Bicho::Condor => "cóndor",
360            Bicho::PavoReal => "pavo real",
361            Bicho::Avestruz => "avestruz",
362            Bicho::Martin => "martín pescador",
363            Bicho::Gallo => "gallo",
364            Bicho::Boa => "boa",
365            Bicho::Cobra => "cobra",
366            Bicho::Iguana => "iguana",
367            Bicho::Camaleon => "camaleón",
368            Bicho::Salamandra => "salamandra",
369            Bicho::Delfin => "delfín",
370            Bicho::Ballena => "ballena",
371            Bicho::Tiburon => "tiburón",
372            Bicho::Pulpo => "pulpo",
373            Bicho::Abeja => "abeja",
374            Bicho::Libelula => "libélula",
375            Bicho::Escarabajo => "escarabajo",
376            Bicho::Hormiga => "hormiga",
377            Bicho::Arana => "araña",
378            Bicho::Cangrejo => "cangrejo",
379            Bicho::Caracol => "caracol",
380            Bicho::Luciernaga => "luciérnaga",
381        }
382    }
383
384    /// **La estampa VOXEL que le toca** a este bicho. Las 32 primeras tienen la
385    /// suya; las del bestiario SDF (2026-09-06) reusan la de un pariente de silueta
386    /// parecida — a la distancia en que se usa el voxel (LOD lejano, fauna esparcida
387    /// por el bioma) un jaguar y un tigre son el mismo puñado de voxels, y una
388    /// estampa a medias sería peor que la del pariente.
389    pub fn silueta_voxel(self) -> Bicho {
390        match self {
391            Bicho::Perro => Bicho::Zorro,
392            Bicho::Gato => Bicho::Zorro,
393            Bicho::Toro => Bicho::Vaca,
394            Bicho::Alce => Bicho::Ciervo,
395            Bicho::Mapache => Bicho::Zorro,
396            Bicho::Raton => Bicho::Conejo,
397            Bicho::Panda => Bicho::Oso,
398            Bicho::Koala => Bicho::Oso,
399            Bicho::Canguro => Bicho::Ciervo,
400            Bicho::Llama => Bicho::Oveja,
401            Bicho::Jirafa => Bicho::Caballo,
402            Bicho::Leon => Bicho::Oso,
403            Bicho::Cebra => Bicho::Caballo,
404            Bicho::Jaguar => Bicho::Tigre,
405            Bicho::Hipopotamo => Bicho::Oso,
406            Bicho::Rinoceronte => Bicho::Oso,
407            Bicho::Capibara => Bicho::Cerdo,
408            Bicho::Perezoso => Bicho::Mono,
409            Bicho::Gorrion => Bicho::Pajaro,
410            Bicho::Cardenal => Bicho::Pajaro,
411            Bicho::Cuervo => Bicho::Pajaro,
412            Bicho::Colibri => Bicho::Pajaro,
413            Bicho::Guacamayo => Bicho::Loro,
414            Bicho::Tucan => Bicho::Loro,
415            Bicho::Quetzal => Bicho::Loro,
416            Bicho::Flamenco => Bicho::Pato,
417            Bicho::Garza => Bicho::Pato,
418            Bicho::Cisne => Bicho::Pato,
419            Bicho::Ganso => Bicho::Pato,
420            Bicho::Pelicano => Bicho::Pato,
421            Bicho::Aguila => Bicho::Buho,
422            Bicho::Condor => Bicho::Buho,
423            Bicho::PavoReal => Bicho::Gallina,
424            Bicho::Avestruz => Bicho::Gallina,
425            Bicho::Martin => Bicho::Pajaro,
426            Bicho::Gallo => Bicho::Gallina,
427            Bicho::Boa => Bicho::Serpiente,
428            Bicho::Cobra => Bicho::Serpiente,
429            Bicho::Iguana => Bicho::Lagarto,
430            Bicho::Camaleon => Bicho::Lagarto,
431            Bicho::Salamandra => Bicho::Lagarto,
432            Bicho::Delfin => Bicho::Pez,
433            Bicho::Ballena => Bicho::Pez,
434            Bicho::Tiburon => Bicho::Pez,
435            Bicho::Pulpo => Bicho::Pez,
436            Bicho::Abeja => Bicho::Mariposa,
437            Bicho::Libelula => Bicho::Mariposa,
438            Bicho::Escarabajo => Bicho::Escorpion,
439            Bicho::Hormiga => Bicho::Escorpion,
440            Bicho::Arana => Bicho::Escorpion,
441            Bicho::Cangrejo => Bicho::Escorpion,
442            Bicho::Caracol => Bicho::Escorpion,
443            Bicho::Luciernaga => Bicho::Mariposa,
444            otro => otro,
445        }
446    }
447
448    pub fn next(self) -> Bicho {
449        let i = Bicho::ALL.iter().position(|&b| b == self).unwrap_or(0);
450        Bicho::ALL[(i + 1) % Bicho::ALL.len()]
451    }
452}
453
454/// **Uso de un ser en un bioma**: qué animal y con qué densidad `[0,1]` aparece
455/// (una candidata por parcela de la grilla de fauna; el bioma lo esparce por
456/// semilla → una fauna procedural, como la flora y las casas).
457#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
458pub struct BichoUso {
459    pub bicho: Bicho,
460    pub densidad: f32,
461}
462
463// Paleta cruda de fauna (colores que la paleta de terreno no tiene).
464const MARRON: [u8; 3] = [120, 84, 50];
465const MARRON_OSC: [u8; 3] = [86, 58, 34];
466const BLANCO: [u8; 3] = [230, 228, 222];
467const NEGRO: [u8; 3] = [42, 42, 46];
468const ROSA: [u8; 3] = [224, 152, 152];
469const NARANJA: [u8; 3] = [206, 108, 46];
470const GRIS: [u8; 3] = [132, 132, 138];
471const VERDE: [u8; 3] = [96, 156, 74];
472const VERDE_OSC: [u8; 3] = [64, 116, 56];
473const ROJO: [u8; 3] = [206, 72, 60];
474const AMARILLO: [u8; 3] = [224, 192, 92];
475const AZUL: [u8; 3] = [72, 116, 186];
476const TAN: [u8; 3] = [204, 172, 120];
477const MARRON_CLR: [u8; 3] = [158, 118, 76];
478const GRIS_OSC: [u8; 3] = [92, 94, 100];
479
480/// Hash barato de la posición → variedad de morfo (color/patrón) por dónde cae el
481/// animal, sin usar la semilla del mundo. Igual que la carrocería de un vehículo o
482/// el tinte del follaje: un rebaño estampado sale VARIADO, determinista por posición.
483#[inline]
484fn morph(x: u32, z: u32) -> u32 {
485    let mut h = x.wrapping_mul(0x9E37_79B9).wrapping_add(z.wrapping_mul(0x85EB_CA77));
486    h ^= h >> 15;
487    h = h.wrapping_mul(0x2C1B_3C6D);
488    (h ^ (h >> 13)) & 0xFFFF
489}
490
491/// Rota un desplazamiento `(dx, dz)` según `facing` (giros de 90°).
492#[inline]
493fn rot(dx: i32, dz: i32, facing: u8) -> (i32, i32) {
494    match facing & 3 {
495        0 => (dx, dz),
496        1 => (-dz, dx),
497        2 => (-dx, -dz),
498        _ => (dz, -dx),
499    }
500}
501
502/// **Detalle sub-voxel de un ser vivo** `(rugosidad, bisel)` — la gramática
503/// cuantizada que rompe la caja rectangular de los animales voxel. Rugosidad suave
504/// (grano de piel/pelaje, escala `VoxelGrid::DETALLE_RUG_MAX`) + bisel alto (redondeo
505/// orgánico de la silueta de sombreado): un ser vivo no es un ladrillo. Es la MISMA
506/// gramática de bisel/campo que el terreno (no una fidelidad distinta → sin valle),
507/// sólo con más redondeo por ser un cuerpo. `generate_window` lo aplica como pincel
508/// de detalle alrededor de cada `stamp_bicho`. El bisel sólo luce si el bisel GLOBAL
509/// de la escena está prendido (activa la isosuperficie); la rugosidad luce siempre.
510pub const DETALLE_SER_VIVO: (f32, f32) = (0.4, 0.85);
511
512/// **Estampa un ser** del `bicho` parado con las patas en `(x, y, z)` (base local
513/// `dy=0` = a ras del suelo), orientado por `facing`. `dz` crece hacia el frente
514/// (hocico), `dx` a lo ancho, `dy` hacia arriba.
515pub fn stamp_bicho(g: &mut VoxelGrid, bicho: Bicho, x: u32, y: u32, z: u32, facing: u8) {
516    // Las especies del bestiario SDF caen en la estampa de su pariente voxel.
517    let bicho = bicho.silueta_voxel();
518    let (bx, by, bz) = (x as i32, y as i32, z as i32);
519    let dim = g.dim();
520    let vh = morph(x, z); // morfo de color/patrón por posición (variedad de rebaño)
521    let mut put = |dx: i32, dy: i32, dz: i32, c: [u8; 3]| {
522        let (rx, rz) = rot(dx, dz, facing);
523        let (px, py, pz) = (bx + rx, by + dy, bz + rz);
524        if px >= 0 && py >= 0 && pz >= 0 && (px as u32) < dim[0] && (py as u32) < dim[1] && (pz as u32) < dim[2] {
525            g.set(px as u32, py as u32, pz as u32, c);
526        }
527    };
528
529    match bicho {
530        Bicho::Vaca => {
531            // Morfo de pelaje: holstein / marrón-blanca / negra.
532            let (base, mancha_c) = match vh % 3 {
533                0 => (BLANCO, NEGRO),
534                1 => (BLANCO, MARRON_CLR),
535                _ => (MARRON_CLR, NEGRO),
536            };
537            // Cuerpo (2 de ancho × 3 de largo × 2 de alto) sobre 4 patas.
538            for dx in -1i32..=0 {
539                for dz in -1i32..=1 {
540                    for dy in 2..=3 {
541                        // Manchas en algunas celdas, base en el resto.
542                        let mancha = (dx + dz).rem_euclid(2) == 0 && dz != 1;
543                        put(dx, dy, dz, if mancha { mancha_c } else { base });
544                    }
545                }
546            }
547            for &(lx, lz) in &[(-1, -1), (0, -1), (-1, 1), (0, 1)] {
548                put(lx, 0, lz, MARRON_OSC);
549                put(lx, 1, lz, MARRON_OSC);
550            }
551            // Cabeza al frente + cuernos.
552            put(0, 3, 2, ROSA);
553            put(-1, 3, 2, ROSA);
554            put(0, 4, 2, base);
555            put(-1, 4, 2, base);
556            put(1, 4, 2, [232, 228, 214]); // cuerno
557            put(-2, 4, 2, [232, 228, 214]); // cuerno
558        }
559        Bicho::Oveja => {
560            // Morfo de lana: blanca / beige / gris.
561            let lana = match vh % 3 {
562                0 => BLANCO,
563                1 => [214, 202, 176],
564                _ => [186, 186, 190],
565            };
566            // Cuerpo lanudo y mullido sobre patas oscuras.
567            for dx in -1..=0 {
568                for dz in -1..=1 {
569                    for dy in 2..=3 {
570                        put(dx, dy, dz, lana);
571                    }
572                }
573            }
574            put(0, 4, 0, lana);
575            put(-1, 4, 0, lana);
576            for &(lx, lz) in &[(-1, -1), (0, -1), (-1, 1), (0, 1)] {
577                put(lx, 0, lz, NEGRO);
578                put(lx, 1, lz, NEGRO);
579            }
580            // Cara oscura al frente.
581            put(0, 2, 2, NEGRO);
582            put(-1, 2, 2, NEGRO);
583            put(0, 3, 2, lana);
584        }
585        Bicho::Cerdo => {
586            // Cuerpo rosado rechoncho, patas cortas, hocico y colita.
587            for dx in -1..=0 {
588                for dz in -1..=1 {
589                    put(dx, 1, dz, ROSA);
590                    put(dx, 2, dz, ROSA);
591                }
592            }
593            for &(lx, lz) in &[(-1, -1), (0, -1), (-1, 1), (0, 1)] {
594                put(lx, 0, lz, ROSA);
595            }
596            put(0, 1, 2, ROSA); // hocico
597            put(-1, 1, 2, ROSA);
598            put(0, 2, 2, ROSA);
599            put(-1, 2, 2, ROSA);
600            put(0, 2, 3, [232, 170, 170]); // trompa
601            put(-1, 1, -2, ROSA); // colita
602        }
603        Bicho::Gallina => {
604            // Morfo de plumaje: blanca / marrón / negra (con gallo rojizo).
605            let plum = match vh % 3 {
606                0 => BLANCO,
607                1 => MARRON_CLR,
608                _ => [70, 68, 74],
609            };
610            put(0, 1, 0, plum);
611            put(0, 1, -1, plum);
612            put(0, 2, 0, plum);
613            put(0, 2, 1, plum); // pecho/cabeza
614            put(0, 3, 1, ROJO); // cresta
615            put(0, 2, 2, AMARILLO); // pico
616            put(0, 0, 0, AMARILLO); // patas
617            put(0, 0, -1, AMARILLO);
618            put(0, 1, -2, plum); // cola
619        }
620        Bicho::Ciervo => {
621            // Patas largas, cuerpo marrón, cuello y cabeza al frente, astas.
622            for &(lx, lz) in &[(-1, -1), (0, -1), (-1, 1), (0, 1)] {
623                put(lx, 0, lz, MARRON_OSC);
624                put(lx, 1, lz, MARRON_OSC);
625            }
626            for dx in -1..=0 {
627                for dz in -1..=1 {
628                    put(dx, 2, dz, MARRON);
629                    put(dx, 3, dz, MARRON);
630                }
631            }
632            // Cuello + cabeza.
633            put(0, 3, 2, MARRON);
634            put(0, 4, 2, MARRON);
635            put(0, 5, 2, MARRON);
636            put(0, 5, 3, MARRON); // hocico
637            // Astas.
638            put(0, 6, 2, MARRON_OSC);
639            put(1, 6, 2, MARRON_OSC);
640            put(-1, 6, 2, MARRON_OSC);
641            put(0, 6, 3, MARRON_OSC);
642        }
643        Bicho::Conejo => {
644            // Morfo de pelaje: blanco / marrón / gris.
645            let pelo = match vh % 3 {
646                0 => BLANCO,
647                1 => MARRON_CLR,
648                _ => GRIS,
649            };
650            // Cuerpo chico, orejas largas, cola de algodón.
651            put(0, 1, 0, pelo);
652            put(0, 1, -1, pelo);
653            put(0, 2, 0, pelo);
654            put(0, 2, 1, pelo); // cabeza al frente
655            put(0, 3, 1, pelo); // oreja
656            put(0, 4, 1, pelo);
657            put(0, 3, 0, pelo); // oreja 2
658            put(0, 4, 0, pelo);
659            put(0, 0, 0, pelo);
660            put(0, 0, -1, pelo);
661            put(0, 2, -1, [240, 240, 236]); // colita
662        }
663        Bicho::Zorro => {
664            // Cuerpo naranja, pecho/cola blancos, orejas puntiagudas.
665            for dz in -1..=1 {
666                put(0, 1, dz, NARANJA);
667                put(0, 2, dz, NARANJA);
668            }
669            put(0, 0, -1, MARRON_OSC); // patas
670            put(0, 0, 1, MARRON_OSC);
671            put(0, 2, 2, NARANJA); // cabeza
672            put(0, 3, 2, NARANJA); // oreja
673            put(0, 2, 3, BLANCO); // hocico
674            put(0, 1, 2, BLANCO); // pecho
675            put(0, 2, -2, BLANCO); // cola
676            put(0, 1, -2, NARANJA);
677        }
678        Bicho::Lobo => {
679            // Como el zorro pero gris y más largo/robusto.
680            for dz in -2..=1 {
681                put(0, 1, dz, GRIS);
682                put(0, 2, dz, GRIS);
683            }
684            for &lz in &[-1, 1] {
685                put(0, 0, lz, [96, 96, 102]);
686            }
687            put(0, 2, 2, GRIS); // cabeza
688            put(0, 3, 2, GRIS); // oreja
689            put(0, 2, 3, [110, 110, 116]); // hocico
690            put(0, 2, -3, GRIS); // cola
691            put(0, 3, -3, GRIS);
692        }
693        Bicho::Oso => {
694            // Cuerpo voluminoso (2×3), cabeza redonda con orejas.
695            for dx in -1..=0 {
696                for dz in -1..=1 {
697                    for dy in 1..=3 {
698                        put(dx, dy, dz, MARRON_OSC);
699                    }
700                }
701            }
702            for &(lx, lz) in &[(-1, -1), (0, -1), (-1, 1), (0, 1)] {
703                put(lx, 0, lz, MARRON_OSC);
704            }
705            put(0, 3, 2, MARRON); // cabeza
706            put(-1, 3, 2, MARRON);
707            put(0, 4, 2, MARRON);
708            put(-1, 4, 2, MARRON);
709            put(1, 4, 2, MARRON_OSC); // orejas
710            put(-2, 4, 2, MARRON_OSC);
711        }
712        Bicho::Caballo => {
713            // Morfo de capa: alazán / negro / bayo, con crin de contraste.
714            let (capa, crin) = match vh % 3 {
715                0 => (MARRON, MARRON_OSC),
716                1 => ([58, 54, 56], NEGRO),
717                _ => (TAN, MARRON_OSC),
718            };
719            // Alto: patas largas, lomo, cuello erguido, crin y cola.
720            for &(lx, lz) in &[(-1, -1), (0, -1), (-1, 1), (0, 1)] {
721                put(lx, 0, lz, crin);
722                put(lx, 1, lz, capa);
723                put(lx, 2, lz, capa);
724            }
725            for dx in -1..=0 {
726                for dz in -1..=1 {
727                    put(dx, 3, dz, capa);
728                }
729            }
730            // Cuello + cabeza.
731            put(0, 4, 1, capa);
732            put(0, 5, 1, capa);
733            put(0, 5, 2, capa); // testa
734            put(0, 4, 2, capa);
735            put(0, 6, 1, crin); // crin
736            put(0, 5, 0, crin);
737            put(-1, 4, -1, crin); // cola
738            put(-1, 3, -2, crin);
739        }
740        Bicho::Pajaro => {
741            // Diminuto: cuerpo azul, alas, pico, patitas.
742            put(0, 1, 0, AZUL);
743            put(0, 2, 0, AZUL); // cabeza
744            put(0, 2, 1, AMARILLO); // pico
745            put(1, 1, 0, [96, 140, 210]); // ala
746            put(-1, 1, 0, [96, 140, 210]);
747            put(0, 1, -1, AZUL); // cola
748            put(0, 0, 0, AMARILLO); // pata
749        }
750        Bicho::Pez => {
751            // Cuerpo lateral + aleta caudal (se coloca en/junto al agua).
752            put(0, 1, 0, AZUL);
753            put(0, 1, 1, AZUL);
754            put(0, 2, 0, [110, 150, 210]);
755            put(0, 1, 2, [110, 150, 210]); // morro
756            put(0, 1, -1, [150, 180, 220]); // cola
757            put(0, 2, -1, [150, 180, 220]);
758            put(0, 0, -1, [150, 180, 220]);
759        }
760        Bicho::Tortuga => {
761            // Caparazón verde abovedado + cabeza + 4 patas.
762            for dx in -1..=1 {
763                for dz in -1..=1 {
764                    put(dx, 1, dz, VERDE_OSC);
765                }
766            }
767            put(0, 2, 0, VERDE); // cúpula del caparazón
768            put(0, 1, 2, [180, 200, 120]); // cabeza
769            for &(lx, lz) in &[(-1, -1), (1, -1), (-1, 1), (1, 1)] {
770                put(lx, 0, lz, [180, 200, 120]); // patas
771            }
772        }
773        Bicho::Rana => {
774            // Cuerpo verde agazapado, ojos saltones, patas dobladas.
775            put(0, 1, 0, VERDE);
776            put(-1, 1, 0, VERDE);
777            put(0, 1, 1, VERDE); // frente
778            put(-1, 1, 1, VERDE);
779            put(0, 2, 1, VERDE_OSC); // ojo
780            put(-1, 2, 1, VERDE_OSC);
781            put(0, 0, -1, VERDE); // pata trasera
782            put(-1, 0, -1, VERDE);
783            put(0, 0, 2, [200, 210, 140]); // pata delantera
784        }
785        Bicho::Serpiente => {
786            // Cuerpo largo y bajo en zigzag + cabeza.
787            let cuerpo = [(0, 0), (0, -1), (-1, -1), (-1, -2), (-2, -2), (-2, -3)];
788            for &(sx, sz) in &cuerpo {
789                put(sx, 1, sz, VERDE_OSC);
790            }
791            put(0, 1, 1, VERDE); // cabeza
792            put(0, 1, 2, VERDE);
793            put(0, 2, 1, ROJO); // lengua/ojo
794        }
795        Bicho::Mariposa => {
796            // Morfo de alas: naranja monarca / azul / amarilla.
797            let (ala1, ala2) = match vh % 3 {
798                0 => (AMARILLO, NARANJA),
799                1 => (AZUL, [140, 180, 230]),
800                _ => (AMARILLO, [230, 170, 60]),
801            };
802            put(0, 3, 0, NEGRO); // cuerpo
803            put(0, 2, 0, NEGRO);
804            put(1, 3, 0, ala1); // alas
805            put(1, 3, 1, ala2);
806            put(-1, 3, 0, ala1);
807            put(-1, 3, 1, ala2);
808            put(1, 2, 0, ala2);
809            put(-1, 2, 0, ala2);
810        }
811
812        // ---- Granja / pradera ----
813        Bicho::Pato => {
814            // Cuerpo blanco chico, cuello, pico naranja, cola.
815            put(0, 1, 0, BLANCO);
816            put(0, 1, -1, BLANCO);
817            put(-1, 1, 0, BLANCO);
818            put(0, 2, 1, BLANCO); // cuello/cabeza
819            put(0, 3, 1, BLANCO);
820            put(0, 3, 2, NARANJA); // pico
821            put(0, 2, -1, BLANCO); // cola
822            put(0, 0, 0, NARANJA); // patas
823        }
824        Bicho::Cabra => {
825            // Morfo: blanca / parda. Cuerpo, patas, cabeza barbada y cuernos.
826            let capa = if vh % 2 == 0 { [222, 216, 202] } else { MARRON_CLR };
827            for &(lx, lz) in &[(-1, -1), (0, -1), (-1, 1), (0, 1)] {
828                put(lx, 0, lz, MARRON_OSC);
829                put(lx, 1, lz, capa);
830            }
831            for dx in -1..=0 {
832                for dz in -1..=1 {
833                    put(dx, 2, dz, capa);
834                }
835            }
836            put(0, 2, 2, capa); // cabeza
837            put(0, 3, 2, capa);
838            put(0, 2, 3, capa); // hocico
839            put(0, 4, 2, [232, 228, 214]); // cuerno
840            put(0, 1, 2, [220, 214, 200]); // barbita
841            put(-1, 2, -2, capa); // cola corta
842        }
843        Bicho::Burro => {
844            // Gris, patas, lomo, cuello y orejas largas.
845            for &(lx, lz) in &[(-1, -1), (0, -1), (-1, 1), (0, 1)] {
846                put(lx, 0, lz, GRIS_OSC);
847                put(lx, 1, lz, GRIS);
848            }
849            for dx in -1..=0 {
850                for dz in -1..=1 {
851                    put(dx, 2, dz, GRIS);
852                }
853            }
854            put(0, 3, 1, GRIS); // cuello
855            put(0, 3, 2, GRIS); // cabeza
856            put(0, 4, 2, GRIS); // oreja larga
857            put(0, 5, 2, GRIS_OSC);
858            put(-1, 2, -2, GRIS_OSC); // cola
859        }
860
861        // ---- Bosque ----
862        Bicho::Ardilla => {
863            // Cuerpito naranja con cola tupida enroscada hacia arriba.
864            put(0, 1, 0, NARANJA);
865            put(0, 2, 0, NARANJA);
866            put(0, 2, 1, NARANJA); // cabeza
867            put(0, 3, 1, [222, 150, 90]); // oreja
868            put(0, 1, 1, [232, 190, 150]); // pecho claro
869            put(0, 0, 0, MARRON_OSC); // pata
870            put(0, 2, -1, NARANJA); // cola
871            put(0, 3, -1, [222, 150, 90]);
872            put(0, 4, -1, NARANJA);
873            put(0, 4, 0, [222, 150, 90]);
874        }
875        Bicho::Buho => {
876            // Compacto, posado, con ojos grandes y penachos.
877            for dy in 1..=3 {
878                put(0, dy, 0, MARRON);
879                put(-1, dy, 0, MARRON);
880            }
881            put(0, 3, 1, AMARILLO); // ojo
882            put(-1, 3, 1, AMARILLO);
883            put(0, 4, 0, MARRON_OSC); // penacho
884            put(-1, 4, 0, MARRON_OSC);
885            put(0, 2, 1, [206, 180, 140]); // pecho
886            put(-1, 2, 1, [206, 180, 140]);
887            put(0, 0, 0, AMARILLO); // garras
888            put(-1, 0, 0, AMARILLO);
889        }
890        Bicho::Erizo => {
891            // Cuerpo bajo con lomo de púas oscuras y carita clara.
892            for dx in -1..=0 {
893                for dz in -1..=1 {
894                    put(dx, 1, dz, MARRON_OSC);
895                    put(dx, 2, dz, [64, 52, 40]); // púas
896                }
897            }
898            put(0, 2, 2, [222, 198, 160]); // carita
899            put(-1, 2, 2, [222, 198, 160]);
900            put(0, 1, 3, NEGRO); // hocico
901            for &(lx, lz) in &[(-1, -1), (0, 1)] {
902                put(lx, 0, lz, [120, 96, 72]);
903            }
904        }
905
906        // ---- Desierto ----
907        Bicho::Camello => {
908            // Color arena, patas largas, joroba, cuello y cabeza.
909            for &(lx, lz) in &[(-1, -1), (0, -1), (-1, 1), (0, 1)] {
910                put(lx, 0, lz, [176, 148, 104]);
911                put(lx, 1, lz, TAN);
912                put(lx, 2, lz, TAN);
913            }
914            for dx in -1..=0 {
915                for dz in -1..=1 {
916                    put(dx, 3, dz, TAN);
917                }
918            }
919            put(0, 4, 0, TAN); // joroba
920            put(-1, 4, 0, TAN);
921            put(0, 4, 1, TAN); // cuello
922            put(0, 5, 2, TAN); // cabeza
923            put(0, 5, 3, [176, 148, 104]); // hocico
924            put(-1, 3, -2, TAN); // cola
925        }
926        Bicho::Escorpion => {
927            // Cuerpo bajo oscuro, pinzas al frente, cola curva con aguijón.
928            put(0, 1, 0, [70, 58, 40]);
929            put(0, 1, 1, [70, 58, 40]);
930            put(0, 1, 2, [86, 70, 48]); // pinzas
931            put(1, 1, 2, [86, 70, 48]);
932            put(-1, 1, 2, [86, 70, 48]);
933            put(0, 1, -1, [70, 58, 40]); // cola
934            put(0, 2, -1, [70, 58, 40]);
935            put(0, 2, 0, [70, 58, 40]);
936            put(0, 3, 0, ROJO); // aguijón
937        }
938        Bicho::Lagarto => {
939            // Cuerpo verde alargado y bajo, patitas, cabeza, cola larga.
940            for dz in -2..=1 {
941                put(0, 1, dz, VERDE_OSC);
942            }
943            put(0, 1, 2, VERDE); // cabeza
944            put(0, 1, -3, VERDE_OSC); // cola
945            put(0, 1, -4, [80, 130, 66]);
946            put(1, 0, 0, VERDE_OSC); // patas
947            put(-1, 0, 0, VERDE_OSC);
948            put(1, 0, -1, VERDE_OSC);
949            put(-1, 0, -1, VERDE_OSC);
950        }
951
952        // ---- Nieve / agua fría ----
953        Bicho::Pinguino => {
954            // De pie: espalda negra, panza blanca, pico y patas naranjas.
955            for dy in 1..=3 {
956                put(0, dy, 0, NEGRO); // espalda
957            }
958            put(0, 1, 1, BLANCO); // panza
959            put(0, 2, 1, BLANCO);
960            put(0, 4, 0, NEGRO); // cabeza
961            put(0, 4, 1, NARANJA); // pico
962            put(1, 2, 0, NEGRO); // aleta
963            put(-1, 2, 0, NEGRO);
964            put(0, 0, 1, NARANJA); // patas
965        }
966        Bicho::Foca => {
967            // Cuerpo gris tendido, cabeza levantada, aletas.
968            for dz in -2..=1 {
969                put(0, 1, dz, GRIS);
970                put(-1, 1, dz, GRIS);
971            }
972            put(0, 2, 1, GRIS); // cabeza
973            put(-1, 2, 1, GRIS);
974            put(0, 2, 2, [110, 112, 118]); // hocico
975            put(0, 1, -3, [110, 112, 118]); // cola/aleta
976            put(-1, 1, -3, [110, 112, 118]);
977            put(1, 1, 0, [150, 150, 156]); // aleta lateral
978        }
979
980        // ---- Selva / sabana ----
981        Bicho::Mono => {
982            // Cuerpo marrón sentado, cabeza clara, cola larga curva.
983            put(0, 1, 0, MARRON);
984            put(0, 2, 0, MARRON);
985            put(0, 2, 1, [176, 140, 100]); // cara clara
986            put(0, 3, 1, MARRON); // frente
987            put(0, 1, 1, MARRON); // rodillas
988            put(1, 2, 0, MARRON); // brazo
989            put(-1, 2, 0, MARRON);
990            put(0, 1, -1, MARRON); // cola
991            put(0, 2, -1, MARRON);
992            put(0, 2, -2, MARRON);
993        }
994        Bicho::Loro => {
995            // Cuerpo verde vivo, pecho rojo, pico y cola larga.
996            put(0, 1, 0, [70, 168, 72]);
997            put(0, 2, 0, [70, 168, 72]);
998            put(0, 3, 0, [70, 168, 72]); // cabeza
999            put(0, 3, 1, ROJO); // pico
1000            put(0, 1, 1, ROJO); // pecho
1001            put(1, 2, 0, [90, 190, 90]); // ala
1002            put(0, 1, -1, [220, 200, 60]); // cola
1003            put(0, 1, -2, [70, 168, 72]);
1004            put(0, 0, 0, [120, 96, 72]); // pata
1005        }
1006        Bicho::Tigre => {
1007            // Cuerpo naranja con rayas negras, patas, cabeza, cola.
1008            for &(lx, lz) in &[(-1, -1), (0, -1), (-1, 1), (0, 1)] {
1009                put(lx, 0, lz, NARANJA);
1010            }
1011            for dx in -1i32..=0 {
1012                for dz in -1i32..=1 {
1013                    // Rayas: bandas negras alternas a lo largo.
1014                    let raya = dz.rem_euclid(2) == 0;
1015                    put(dx, 1, dz, if raya { NEGRO } else { NARANJA });
1016                }
1017            }
1018            put(0, 2, 2, NARANJA); // cabeza
1019            put(-1, 2, 2, NARANJA);
1020            put(0, 1, 2, [232, 200, 150]); // hocico
1021            put(0, 2, -2, NARANJA); // cola
1022            put(0, 2, -3, NEGRO);
1023        }
1024        Bicho::Elefante => {
1025            // Grande: cuerpo gris (2×3×2), patas, trompa, orejas, colmillos.
1026            for dx in -1i32..=0 {
1027                for dz in -1..=1 {
1028                    for dy in 2..=3 {
1029                        put(dx, dy, dz, GRIS);
1030                    }
1031                }
1032            }
1033            for &(lx, lz) in &[(-1, -1), (0, -1), (-1, 1), (0, 1)] {
1034                put(lx, 0, lz, [110, 112, 118]);
1035                put(lx, 1, lz, GRIS);
1036            }
1037            put(0, 3, 2, GRIS); // cabeza
1038            put(-1, 3, 2, GRIS);
1039            put(0, 2, 2, GRIS);
1040            put(0, 1, 3, GRIS); // trompa
1041            put(0, 0, 3, [110, 112, 118]);
1042            put(1, 3, 1, [150, 150, 156]); // oreja
1043            put(-2, 3, 1, [150, 150, 156]);
1044            put(0, 1, 2, [232, 228, 214]); // colmillo
1045        }
1046        Bicho::Cocodrilo => {
1047            // Cuerpo verde largo y bajo, dorso escamado, fauces, cola.
1048            for dz in -3..=2 {
1049                put(0, 1, dz, VERDE_OSC);
1050                put(-1, 1, dz, VERDE_OSC);
1051            }
1052            // Dorso escamado (crestas alternas).
1053            for dz in -3i32..=1 {
1054                if dz.rem_euclid(2) == 0 {
1055                    put(0, 2, dz, [72, 128, 60]);
1056                }
1057            }
1058            put(0, 1, 3, VERDE); // hocico
1059            put(-1, 1, 3, VERDE);
1060            put(0, 2, 3, NEGRO); // ojo/fauces
1061            put(0, 1, -4, VERDE_OSC); // cola
1062            put(0, 1, -5, [80, 130, 66]);
1063            put(1, 0, 0, VERDE_OSC); // patas
1064            put(-2, 0, 0, VERDE_OSC);
1065        }
1066        // Inalcanzable por construcción: `silueta_voxel` (arriba, primera línea de
1067        // esta función) manda toda especie del bestiario SDF a la estampa de un
1068        // pariente, y las 32 originales tienen la suya. Lo fija el test
1069        // `cada_bicho_estampa_voxels`, que recorre `Bicho::ALL` y exige voxels: una
1070        // especie nueva sin remapeo cae acá, no estampa nada, y el test se pone
1071        // rojo — que es mejor que un `unreachable!` reventando un mundo entero.
1072        _ => {}
1073    }
1074}
1075
1076#[cfg(test)]
1077mod tests {
1078    use super::*;
1079
1080    fn solids(g: &VoxelGrid, dim: [u32; 3]) -> usize {
1081        let mut n = 0;
1082        for x in 0..dim[0] {
1083            for y in 0..dim[1] {
1084                for z in 0..dim[2] {
1085                    if g.is_solid(x as i32, y as i32, z as i32) {
1086                        n += 1;
1087                    }
1088                }
1089            }
1090        }
1091        n
1092    }
1093
1094    #[test]
1095    fn cada_bicho_estampa_voxels() {
1096        let dim = [20u32, 16, 20];
1097        for bicho in Bicho::ALL {
1098            let mut g = VoxelGrid::new(dim);
1099            stamp_bicho(&mut g, bicho, 10, 1, 10, 0);
1100            assert!(solids(&g, dim) >= 5, "{} estampó muy poco", bicho.label());
1101        }
1102    }
1103
1104    #[test]
1105    fn facing_rota_la_silueta() {
1106        let dim = [24u32, 16, 24];
1107        let mut a = VoxelGrid::new(dim);
1108        let mut b = VoxelGrid::new(dim);
1109        stamp_bicho(&mut a, Bicho::Ciervo, 12, 1, 12, 0);
1110        stamp_bicho(&mut b, Bicho::Ciervo, 12, 1, 12, 1);
1111        // Al rotar, la ocupación cambia (el hocico apunta a otro eje).
1112        let mut diff = 0;
1113        for x in 0..dim[0] {
1114            for y in 0..dim[1] {
1115                for z in 0..dim[2] {
1116                    if a.is_solid(x as i32, y as i32, z as i32) != b.is_solid(x as i32, y as i32, z as i32) {
1117                        diff += 1;
1118                    }
1119                }
1120            }
1121        }
1122        assert!(diff > 0, "facing no rotó la silueta");
1123    }
1124}