Reinforced wall as roughly hewn stone in both styles (high-res with five variants)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No files matched your search
@@ -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`
|
`<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).
|
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).
|
||||||
|
After Width: | Height: | Size: 1.6 MiB |
|
After Width: | Height: | Size: 324 KiB |
|
After Width: | Height: | Size: 94 KiB |
|
After Width: | Height: | Size: 86 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 94 KiB |
|
After Width: | Height: | Size: 26 KiB |
@@ -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_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")),
|
(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_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_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]),
|
(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_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_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_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
|
// 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
|
// reinforced walls: masonry in dark stone with the player's red mortar
|
||||||
for v in 0..4u32 {
|
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| {
|
cv.cell(T_REINF + v, |x, y| {
|
||||||
let row = y / 4;
|
// (distance to the nearest centre, to the second nearest, the nearest stone, its centre's y)
|
||||||
let off = if row % 2 == 1 { 4 } else { 0 };
|
let mut best = (99.0f32, 99.0f32, 0i32, 0.0f32);
|
||||||
if y % 4 == 3 || (x + off) % 8 == 7 {
|
for gy in 0..3 {
|
||||||
return Some(shade((70, 26, 30), (rnd(x, y, v + 90) * 8.0) as i32));
|
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
|
// torture chamber: dark stones with rusty iron grates
|
||||||
cv.cell(T_TORTURE + v, |x, y| {
|
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)]
|
#[cfg(test)]
|
||||||
mod sprite_tests {
|
mod sprite_tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||