Reinforced wall as roughly hewn stone in both styles (high-res with five variants)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard ZinkandClaude Opus 5.5 committed 2026-11-07 22:15:36 +01:00
1 parent ca8494aea0
commit da40b0875e
9 files changed
+82 -7

No files matched your search

+21
View File
@@ -101,3 +101,24 @@ python3 tools/make_tile.py <name>-raw.png <name> --size 128 --colors 32 --band 1
`<name>-v64.png` / `<name>-v128.png` are copied to `assets/textures/`; `<name>-v128-preview.png`
shows a floor laid out at random. Water and lava keep their 2x2 blocks (they flow).
## Reinforced wall (2026-11-07)
Roughly hewn stone instead of bricks. `fal-ai/flux-2-pro` (`square_hd`, `seed: 4244`), the
sentence followed by the shared style text:
```text
A uniform all-over pattern of a fortified dungeon wall seen straight on: roughly hewn, irregular grey stone blocks of clearly different sizes and shapes, chiselled rough faces with tool marks and chipped edges, fitted tightly with thin dark mortar that has a faint dark-crimson tint, very solid and heavy - not bricks, not a regular brick pattern, no frame, evenly spread from edge to edge.
```
The stones came out small, so the middle of the picture (pixels 100-500) is used:
```bash
python3 -I -c "from PIL import Image; Image.open('reinforced-raw.png').crop((100,100,500,500)).save('/tmp/reinf-zoom.png')"
python3 tools/make_tile.py /tmp/reinf-zoom.png reinforced --size 256 --colors 32 --band 28 --variants 5 --bright 1.25
python3 tools/make_tile.py /tmp/reinf-zoom.png reinforced --size 128 --colors 24 --band 14 --variants 5 --bright 1.25
```
The pixel-art atlas (16x16) does not use the picture (scaled that small it turns to mush): its
reinforced wall is drawn in code in the same spirit (`T_REINF` in `gen_atlas`: rubble stones
around a jittered grid, crimson-tinted mortar).
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

+61 -7
View File
@@ -363,7 +363,7 @@ const HD_DECALS: [(u32, &[u8], &[u8]); 2] = [
(D_RUBBLE, include_bytes!("../assets/textures/decal-rubble.png"), include_bytes!("../assets/textures/decal-rubble-128.png")),
(D_CRACK, include_bytes!("../assets/textures/decal-crack.png"), include_bytes!("../assets/textures/decal-crack-128.png")),
];
const HD_SETS: [(u32, u32, u32, &[u8], &[u8], [u32; 5]); 11] = [
const HD_SETS: [(u32, u32, u32, &[u8], &[u8], [u32; 5]); 12] = [
(T_CLAIM, 4, T_HDSET, include_bytes!("../assets/textures/floor-player.png"), include_bytes!("../assets/textures/floor-player-128.png"), [1; 5]),
(T_RIVAL1, 4, T_HDSET + 5, include_bytes!("../assets/textures/floor-mossgrim.png"), include_bytes!("../assets/textures/floor-mossgrim-128.png"), [1; 5]),
(T_RIVAL2, 4, T_HDSET + 10, include_bytes!("../assets/textures/floor-nightwell.png"), include_bytes!("../assets/textures/floor-nightwell-128.png"), [1; 5]),
@@ -375,6 +375,7 @@ const HD_SETS: [(u32, u32, u32, &[u8], &[u8], [u32; 5]); 11] = [
(T_SILVER, 2, T_HDSET + 40, include_bytes!("../assets/textures/silver-v64.png"), include_bytes!("../assets/textures/silver-v128.png"), [1; 5]),
(T_RUBY, 2, T_HDSET + 45, include_bytes!("../assets/textures/ruby-v64.png"), include_bytes!("../assets/textures/ruby-v128.png"), [1; 5]),
(T_DIAMOND, 2, T_HDSET + 50, include_bytes!("../assets/textures/diamond-v64.png"), include_bytes!("../assets/textures/diamond-v128.png"), [1; 5]),
(T_REINF, 4, T_HDSET + 55, include_bytes!("../assets/textures/reinforced-v64.png"), include_bytes!("../assets/textures/reinforced-v128.png"), [1; 5]),
];
// the cell a tile at (x, z) shows in the high-res style: the kinds with a set pick one of its
@@ -652,14 +653,41 @@ fn gen_atlas() -> Image {
});
// reinforced walls: masonry in dark stone with the player's red mortar
for v in 0..4u32 {
// reinforced wall: roughly hewn grey stones of different sizes (a jittered grid of
// stone centres, their borders the mortar; wrapped, so the cell is seamless), dark mortar
// with a crimson tint, the upper rim of every stone lit, the lower rim in shadow
cv.cell(T_REINF + v, |x, y| {
let row = y / 4;
let off = if row % 2 == 1 { 4 } else { 0 };
if y % 4 == 3 || (x + off) % 8 == 7 {
return Some(shade((70, 26, 30), (rnd(x, y, v + 90) * 8.0) as i32));
// (distance to the nearest centre, to the second nearest, the nearest stone, its centre's y)
let mut best = (99.0f32, 99.0f32, 0i32, 0.0f32);
for gy in 0..3 {
for gx in 0..3 {
let cx = gx as f32 * 5.33 + 1.0 + (hash(gx, gy, v + 95) % 4) as f32;
let cy = gy as f32 * 5.33 + 1.0 + (hash(gy, gx, v + 96) % 4) as f32;
for wx in [-16.0f32, 0.0, 16.0] {
for wy in [-16.0f32, 0.0, 16.0] {
// stones a little wider than high, like coursed rubble
let (dx, dy) = ((x as f32 + 0.5 - cx - wx) * 0.8, y as f32 + 0.5 - cy - wy);
let d = (dx * dx + dy * dy).sqrt();
if d < best.0 {
best = (d, best.0, gy * 3 + gx, cy + wy);
} else if d < best.1 {
best.1 = d;
}
}
}
}
}
let brick = hash((x + off) / 8, row, v + 91) % 4;
Some(shade((84, 76, 74), (rnd(x, y, v + 92) * 14.0) as i32 - 7 + brick as i32 * 5 - 6 + if y % 4 == 0 { 10 } else { 0 }))
let (d1, d2, id, cy) = best;
if d2 - d1 < 0.9 {
return Some(shade((44, 30, 34), (rnd(x, y, v + 97) * 8.0) as i32));
}
let tone = (hash(id, 7, v + 98) % 5) as i32 * 5 - 10;
let rim = if d2 - d1 < 2.0 {
if (y as f32 + 0.5) < cy { 14 } else { -14 }
} else {
0
};
Some(shade((92, 90, 96), tone + rim + (rnd(x, y, v + 99) * 10.0) as i32 - 5))
});
// torture chamber: dark stones with rusty iron grates
cv.cell(T_TORTURE + v, |x, y| {
@@ -2830,6 +2858,32 @@ mod hd_atlas_tests {
}
}
#[cfg(test)]
mod atlas_dump {
use super::*;
// `cargo test --bins dump_atlas_cell -- --ignored` writes a 16x16 cell kind (env DUMP_CELL,
// default T_REINF: its four variants at random, 6x4 tiles) scaled up 8x to /tmp/atlas-cell.png
#[test]
#[ignore]
fn dump_atlas_cell() {
let base: u32 = std::env::var("DUMP_CELL").ok().and_then(|v| v.parse().ok()).unwrap_or(T_REINF);
let atlas = gen_atlas();
let (w, h) = (6 * 16 * 8, 4 * 16 * 8);
let mut out = Image::gen_image_color(w as u16, h as u16, BLACK);
for t in 0..24u32 {
let id = base + hash(t as i32, 3, 5) % 4;
let (ox, oy) = ((id % ATLAS_COLS) * 16, (id / ATLAS_COLS) * 16);
for y in 0..128 {
for x in 0..128 {
out.set_pixel((t % 6) * 128 + x, h - 1 - ((t / 6) * 128 + y), atlas.get_pixel(ox + x / 8, oy + y / 8));
}
}
}
out.export_png("/tmp/atlas-cell.png");
}
}
#[cfg(test)]
mod sprite_tests {
use super::*;