diff --git a/art/generated/gear/PROMPTS.md b/art/generated/gear/PROMPTS.md new file mode 100644 index 0000000..ec2e060 --- /dev/null +++ b/art/generated/gear/PROMPTS.md @@ -0,0 +1,12 @@ +# Gear parts (high-res) + +The parts laid over the detailed sprites as their gear (helmet, shoulder piece, crown, cape, +horn, plume; `GEAR_*` and `gen_gear` in `src/gfx.rs`). Generated on 2026-11-08 with +`fal-ai/nano-banana-pro` (`aspect_ratio: 3:2`, `resolution: 2K`, one image), the prompt in +`batch.py`: six pieces in light neutral grey on magenta, so the game tints them (bronze, steel, +gold; the cape red for creatures, blue for heroes). + +Processing (inline python, see the session): magenta keyed out, every piece cropped to its +picture, the horn mirrored, turned into light grey (luminance x 1.25), scaled to its place in the +gear texture (the old rects times four: helmet 96x48, shoulder 48x36, crown 80x40, cape 112x160, +horn 28x40, plume 28x48) with hard alpha; copied to `assets/textures/gear/.png`. diff --git a/art/generated/gear/batch.py b/art/generated/gear/batch.py new file mode 100644 index 0000000..1f1299c --- /dev/null +++ b/art/generated/gear/batch.py @@ -0,0 +1,12 @@ +# The gear parts laid over the detailed sprites (src/gfx.rs GEAR_*), 2026-11-08: one sheet, +# light neutral grey so the game tints them (bronze, steel, gold; the cape red or blue). +PROMPT = ("A sheet of six separate equipment pieces for a dark-fantasy pixel-art game, arranged in a grid of 3 columns and 2 rows, each piece centred " + "in its own cell and filling most of it, all in the same style: hand-painted pixel art, crisp edges, a dark near-black outline, shading lit " + "from the upper left, and every piece in LIGHT NEUTRAL GREY tones only (no other colours), so it can be tinted later. The background is a " + "completely flat pure magenta (#FF00FF) everywhere - no frames, no grid lines, no text. The pieces, in reading order: " + "1. a round metal helmet seen from the front, a dome with a riveted rim, no face, no visor; " + "2. a single rounded shoulder plate (pauldron) seen from the front, with two rivets; " + "3. a crown with three pointed spikes and small round gems; " + "4. a long cape seen from behind, hanging down, wider at the hem, with folds; " + "5. a single curved horn pointing up, slightly bent to the right; " + "6. a feather plume, a tall bushy crest.") diff --git a/art/generated/gear/cape.png b/art/generated/gear/cape.png new file mode 100644 index 0000000..fe5a556 Binary files /dev/null and b/art/generated/gear/cape.png differ diff --git a/art/generated/gear/crown.png b/art/generated/gear/crown.png new file mode 100644 index 0000000..ff0e3f6 Binary files /dev/null and b/art/generated/gear/crown.png differ diff --git a/art/generated/gear/helmet.png b/art/generated/gear/helmet.png new file mode 100644 index 0000000..674b198 Binary files /dev/null and b/art/generated/gear/helmet.png differ diff --git a/art/generated/gear/horn.png b/art/generated/gear/horn.png new file mode 100644 index 0000000..955c4d5 Binary files /dev/null and b/art/generated/gear/horn.png differ diff --git a/art/generated/gear/parts-raw.png b/art/generated/gear/parts-raw.png new file mode 100644 index 0000000..9916283 Binary files /dev/null and b/art/generated/gear/parts-raw.png differ diff --git a/art/generated/gear/pauldron.png b/art/generated/gear/pauldron.png new file mode 100644 index 0000000..20eab0e Binary files /dev/null and b/art/generated/gear/pauldron.png differ diff --git a/art/generated/gear/plume.png b/art/generated/gear/plume.png new file mode 100644 index 0000000..015c2af Binary files /dev/null and b/art/generated/gear/plume.png differ diff --git a/assets/textures/gear/cape.png b/assets/textures/gear/cape.png new file mode 100644 index 0000000..fe5a556 Binary files /dev/null and b/assets/textures/gear/cape.png differ diff --git a/assets/textures/gear/crown.png b/assets/textures/gear/crown.png new file mode 100644 index 0000000..ff0e3f6 Binary files /dev/null and b/assets/textures/gear/crown.png differ diff --git a/assets/textures/gear/helmet.png b/assets/textures/gear/helmet.png new file mode 100644 index 0000000..674b198 Binary files /dev/null and b/assets/textures/gear/helmet.png differ diff --git a/assets/textures/gear/horn.png b/assets/textures/gear/horn.png new file mode 100644 index 0000000..955c4d5 Binary files /dev/null and b/assets/textures/gear/horn.png differ diff --git a/assets/textures/gear/pauldron.png b/assets/textures/gear/pauldron.png new file mode 100644 index 0000000..20eab0e Binary files /dev/null and b/assets/textures/gear/pauldron.png differ diff --git a/assets/textures/gear/plume.png b/assets/textures/gear/plume.png new file mode 100644 index 0000000..015c2af Binary files /dev/null and b/assets/textures/gear/plume.png differ diff --git a/src/gfx.rs b/src/gfx.rs index 108e9ef..6a42bc3 100644 --- a/src/gfx.rs +++ b/src/gfx.rs @@ -1934,18 +1934,19 @@ fn gear_anchor(g: &Cell) -> GearAnchor { } // the gear's parts in their texture (grey, tinted by the metal or cloth colour at draw time): -// (x, y, w, h) in texels of GEAR_TEX -pub const GEAR_TEX: u32 = 96; -pub const GEAR_HELMET: (u32, u32, u32, u32) = (0, 0, 24, 12); -pub const GEAR_PAULDRON: (u32, u32, u32, u32) = (24, 0, 12, 9); -pub const GEAR_CROWN: (u32, u32, u32, u32) = (36, 0, 20, 10); -pub const GEAR_CAPE: (u32, u32, u32, u32) = (0, 14, 28, 40); -pub const GEAR_HORN: (u32, u32, u32, u32) = (28, 14, 7, 10); -pub const GEAR_PLUME: (u32, u32, u32, u32) = (36, 14, 7, 12); +// (x, y, w, h) in texels of GEAR_TEX; helmet, shoulder piece, crown, cape, horn and plume are +// generated pictures (art/generated/gear/), drawn over the simple shapes of gen_gear +pub const GEAR_TEX: u32 = 384; +pub const GEAR_HELMET: (u32, u32, u32, u32) = (0, 0, 96, 48); +pub const GEAR_PAULDRON: (u32, u32, u32, u32) = (96, 0, 48, 36); +pub const GEAR_CROWN: (u32, u32, u32, u32) = (144, 0, 80, 40); +pub const GEAR_CAPE: (u32, u32, u32, u32) = (0, 56, 112, 160); +pub const GEAR_HORN: (u32, u32, u32, u32) = (112, 56, 28, 40); +pub const GEAR_PLUME: (u32, u32, u32, u32) = (144, 56, 28, 48); // the holidays' headwear (in its own colours, not tinted): a Christmas hat, a carved pumpkin, bunny ears -pub const GEAR_SANTA: (u32, u32, u32, u32) = (44, 14, 20, 20); -pub const GEAR_PUMPKIN: (u32, u32, u32, u32) = (66, 14, 22, 20); -pub const GEAR_EARS: (u32, u32, u32, u32) = (44, 36, 18, 18); +pub const GEAR_SANTA: (u32, u32, u32, u32) = (176, 56, 80, 80); +pub const GEAR_PUMPKIN: (u32, u32, u32, u32) = (264, 56, 88, 80); +pub const GEAR_EARS: (u32, u32, u32, u32) = (176, 144, 72, 72); // where the gear of a 10x10 sprite goes (its cell, standing; per kind and view), for the // holidays' headwear in the pixel-art style @@ -2868,6 +2869,23 @@ fn gen_gear() -> Image { shape(GEAR_HORN, &|x, y| (x - (1.0 - y) * 0.4 - 0.3).abs() < 0.16 + 0.3 * y, &|x, y| 0.95 - y * 0.25 - x * 0.1); // plume: a feather bush shape(GEAR_PLUME, &|x, y| (x - 0.5).powi(2) * 3.2 + (y - 0.5).powi(2) * 1.1 <= 0.26 + 0.04 * (y * 14.0).sin(), &|_x, y| 0.95 - y * 0.3); + // the generated parts (grey, sized to their places) + for (rect, png) in [ + (GEAR_HELMET, include_bytes!("../assets/textures/gear/helmet.png") as &[u8]), + (GEAR_PAULDRON, include_bytes!("../assets/textures/gear/pauldron.png")), + (GEAR_CROWN, include_bytes!("../assets/textures/gear/crown.png")), + (GEAR_CAPE, include_bytes!("../assets/textures/gear/cape.png")), + (GEAR_HORN, include_bytes!("../assets/textures/gear/horn.png")), + (GEAR_PLUME, include_bytes!("../assets/textures/gear/plume.png")), + ] { + let src = Image::from_file_with_format(png, Some(ImageFormat::Png)).expect("gear part"); + for y in 0..rect.3 { + for x in 0..rect.2 { + let p = if x < src.width as u32 && y < src.height as u32 { src.get_pixel(x, y) } else { Color::new(0.0, 0.0, 0.0, 0.0) }; + img.set_pixel(rect.0 + x, rect.1 + y, p); + } + } + } // the holidays' headwear, coloured: a shape, outlined, its colour per texel let mut cshape = |(ox, oy, w, h): (u32, u32, u32, u32), inside: &dyn Fn(f32, f32) -> bool, paint: &dyn Fn(f32, f32) -> Color| { for y in 0..h { @@ -3660,12 +3678,12 @@ mod sprite_tests { } out.export_png("/tmp/imp-cells.png"); let gear = gen_gear(); - let mut g = Image::gen_image_color((GEAR_TEX * 4) as u16, (GEAR_TEX * 4) as u16, Color::new(0.35, 0.33, 0.38, 1.0)); - for y in 0..GEAR_TEX * 4 { - for x in 0..GEAR_TEX * 4 { - let p = gear.get_pixel(x / 4, y / 4); + let mut g = Image::gen_image_color(GEAR_TEX as u16, GEAR_TEX as u16, Color::new(0.35, 0.33, 0.38, 1.0)); + for y in 0..GEAR_TEX { + for x in 0..GEAR_TEX { + let p = gear.get_pixel(x, y); if p.a > 0.5 { - g.set_pixel(x, GEAR_TEX * 4 - 1 - y, p); + g.set_pixel(x, GEAR_TEX - 1 - y, p); } } }