High-res textures for all rooms, special floors, walls, bridges, outdoors and objects; reinforced wall as castle masonry in both styles
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
da40b0875e
commit
2e905fe374
279 files changed
+307
-35
No files matched your search
+123
-33
@@ -357,11 +357,66 @@ const HD_TILES: [(u32, u32, &[u8], &[u8]); 2] = [
|
||||
// 128x128 ones, weights)
|
||||
pub const T_HDSET: u32 = 224;
|
||||
|
||||
// the floor decals (wear and tear laid over plain floors) in the high-res style: transparent
|
||||
// pictures for their cells (cell, 64x64, 128x128)
|
||||
const HD_DECALS: [(u32, &[u8], &[u8]); 2] = [
|
||||
// the decals (wear and tear laid over plain floors) and the upright objects (treasury heaps,
|
||||
// mushrooms, the core shard) in the high-res style: transparent pictures for their cells
|
||||
// (cell, 64x64, 128x128)
|
||||
macro_rules! hd_obj {
|
||||
($id:expr, $name:literal) => {
|
||||
($id, include_bytes!(concat!("../assets/textures/hd/obj-", $name, "-64.png")), include_bytes!(concat!("../assets/textures/hd/obj-", $name, "-128.png")))
|
||||
};
|
||||
}
|
||||
const HD_DECALS: [(u32, &[u8], &[u8]); 8] = [
|
||||
(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")),
|
||||
hd_obj!(D_COINS, "coins"),
|
||||
hd_obj!(D_SILVER, "silver"),
|
||||
hd_obj!(D_RUBY, "ruby"),
|
||||
hd_obj!(D_DIAMOND, "diamond"),
|
||||
hd_obj!(D_MUSHROOM, "mushroom"),
|
||||
hd_obj!(D_SHARD, "shard"),
|
||||
];
|
||||
|
||||
// Everything else in the world (see art/generated/textures/all/): a kind's own cells get as many
|
||||
// variants as it has cells, tiles that fit together in any order (one seamless border, different
|
||||
// middles), and a tile picks one by its position. (first cell, cells, 64x64 tiles side by side,
|
||||
// 128x128 ones)
|
||||
macro_rules! hd_var {
|
||||
($id:expr, $n:expr, $name:literal) => {
|
||||
($id, $n, include_bytes!(concat!("../assets/textures/hd/", $name, "-v64.png")), include_bytes!(concat!("../assets/textures/hd/", $name, "-v128.png")))
|
||||
};
|
||||
}
|
||||
const HD_VARS: [(u32, u32, &[u8], &[u8]); 31] = [
|
||||
hd_var!(T_FORTWALL, 4, "fortwall"),
|
||||
hd_var!(T_STEEL, 4, "steel"),
|
||||
hd_var!(T_OBSIDIAN, 4, "obsidian"),
|
||||
hd_var!(T_FACE_EARTH, 1, "face"),
|
||||
hd_var!(T_TREASURY, 4, "treasury"),
|
||||
hd_var!(T_LAIR, 4, "lair"),
|
||||
hd_var!(T_FARM, 4, "farm"),
|
||||
hd_var!(T_TRAINING, 4, "training"),
|
||||
hd_var!(T_LIBRARY, 4, "library"),
|
||||
hd_var!(T_TORTURE, 4, "torture"),
|
||||
hd_var!(T_TEMPLE, 4, "temple"),
|
||||
hd_var!(T_PRISON, 4, "prison"),
|
||||
hd_var!(T_GRAVEYARD, 4, "graveyard"),
|
||||
hd_var!(T_GUARDPOST, 4, "guardpost"),
|
||||
hd_var!(T_ARENA, 4, "arena"),
|
||||
hd_var!(T_ALTAR, 4, "altar"),
|
||||
hd_var!(T_FORGE, 4, "forge"),
|
||||
hd_var!(T_AERIE, 4, "aerie"),
|
||||
hd_var!(T_COREFLOOR, 4, "core"),
|
||||
hd_var!(T_PORTALFLOOR, 4, "portal"),
|
||||
hd_var!(T_GATEFLOOR, 4, "gate"),
|
||||
hd_var!(T_HEROFLOOR, 4, "hero"),
|
||||
hd_var!(T_BRIDGE, 2, "bridge"),
|
||||
hd_var!(T_STONEBRIDGE, 2, "stonebridge"),
|
||||
hd_var!(T_GRASS, 4, "grass"),
|
||||
hd_var!(T_SNOW, 4, "snow"),
|
||||
hd_var!(T_MOSS, 4, "moss"),
|
||||
hd_var!(T_LEAVES, 2, "leaves"),
|
||||
hd_var!(T_BARK, 1, "bark"),
|
||||
hd_var!(T_STEM, 1, "stem"),
|
||||
hd_var!(T_CAP, 1, "cap"),
|
||||
];
|
||||
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]),
|
||||
@@ -392,6 +447,11 @@ pub fn hd_tile(id: u32, x: i32, z: i32) -> u32 {
|
||||
r -= wk;
|
||||
}
|
||||
}
|
||||
if let Some(&(base, n, _, _)) = HD_VARS.iter().find(|&&(base, n, _, _)| (base..base + n).contains(&id)) {
|
||||
let h = (x as u32).wrapping_mul(2_654_435_761) ^ (z as u32).wrapping_mul(40_503);
|
||||
let h = (h ^ (h >> 15)).wrapping_mul(0x2c1b_3c6d);
|
||||
return base + (h >> 9) % n;
|
||||
}
|
||||
match HD_TILES.iter().find(|&&(base, n, _, _)| (base..base + n).contains(&id)) {
|
||||
Some(&(base, 4, _, _)) => base + (x & 1) as u32 + (z & 1) as u32 * 2,
|
||||
_ => id,
|
||||
@@ -434,6 +494,18 @@ fn gen_hd_atlas(tile: u32) -> Image {
|
||||
}
|
||||
}
|
||||
}
|
||||
for &(base, n, png, png2) in HD_VARS.iter() {
|
||||
let src = Image::from_file_with_format(if tile == HD_TILE2 { png2 } else { png }, Some(ImageFormat::Png)).expect("hd variants");
|
||||
for v in 0..n {
|
||||
let id = base + v;
|
||||
let (ox, oy) = ((id % ATLAS_COLS) * tile, (id / ATLAS_COLS) * tile);
|
||||
for y in 0..tile {
|
||||
for x in 0..tile {
|
||||
img.set_pixel(ox + x, oy + y, src.get_pixel(v * tile + x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for &(id, png, png2) in HD_DECALS.iter() {
|
||||
let src = Image::from_file_with_format(if tile == HD_TILE2 { png2 } else { png }, Some(ImageFormat::Png)).expect("hd decal");
|
||||
let (ox, oy) = ((id % ATLAS_COLS) * tile, (id / ATLAS_COLS) * tile);
|
||||
@@ -653,41 +725,47 @@ 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
|
||||
// reinforced wall: a castle wall of roughly squared grey blocks in regular courses (three
|
||||
// courses of 6, 5 and 5 pixels, every course cut into blocks of 5-9 pixels at its own places;
|
||||
// wrapped, so the cell is seamless), dark mortar with a crimson tint, the top of every
|
||||
// block lit, its bottom in shadow, now and then a chipped corner
|
||||
cv.cell(T_REINF + v, |x, y| {
|
||||
// (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 (row, ry, rh) = match y {
|
||||
0..=5 => (0, y, 6),
|
||||
6..=10 => (1, y - 6, 5),
|
||||
_ => (2, y - 11, 5),
|
||||
};
|
||||
// the course's cuts: from an offset on, blocks of 5-9 pixels around the cell
|
||||
let off = (hash(row, 1, v + 95) % 6) as i32;
|
||||
let mut cuts = vec![off];
|
||||
let mut c = off;
|
||||
let mut k = 0;
|
||||
loop {
|
||||
c += 5 + (hash(row, k, v + 96) % 5) as i32;
|
||||
k += 1;
|
||||
if c > off + 16 - 4 {
|
||||
break;
|
||||
}
|
||||
cuts.push(c);
|
||||
}
|
||||
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 xs = (x - off).rem_euclid(16) + off;
|
||||
let block = cuts.iter().filter(|&&q| q <= xs).count() as i32;
|
||||
let start = cuts[(block - 1).max(0) as usize];
|
||||
let end = cuts.get(block as usize).copied().unwrap_or(off + 16);
|
||||
let mortar = ry == rh - 1 || xs == end - 1;
|
||||
let chip = (xs == start || xs == end - 2) && (ry == 0 || ry == rh - 2) && hash(row * 7 + block, ry, v + 97) % 4 == 0;
|
||||
if mortar || chip {
|
||||
return Some(shade((46, 30, 34), (rnd(x, y, v + 98) * 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 }
|
||||
let tone = (hash(row * 11 + block, 3, v + 99) % 5) as i32 * 5 - 10;
|
||||
let face = if ry == 0 {
|
||||
12
|
||||
} else if ry == rh - 2 {
|
||||
-8
|
||||
} else {
|
||||
0
|
||||
};
|
||||
Some(shade((92, 90, 96), tone + rim + (rnd(x, y, v + 99) * 10.0) as i32 - 5))
|
||||
Some(shade((92, 90, 96), tone + face + (rnd(x, y, v + 100) * 10.0) as i32 - 5))
|
||||
});
|
||||
// torture chamber: dark stones with rusty iron grates
|
||||
cv.cell(T_TORTURE + v, |x, y| {
|
||||
@@ -2800,7 +2878,7 @@ mod hd_atlas_tests {
|
||||
(p.r, p.g, p.b, p.a)
|
||||
};
|
||||
// a cell without an own texture: the 16x16 one scaled up
|
||||
let (cx, cy) = ((T_TREASURY % ATLAS_COLS) * 16, (T_TREASURY / ATLAS_COLS) * 16);
|
||||
let (cx, cy) = ((T_PUMPKIN % ATLAS_COLS) * 16, (T_PUMPKIN / ATLAS_COLS) * 16);
|
||||
for (x, y) in [(0, 0), (5, 9), (15, 15)] {
|
||||
assert_eq!(px(&hd, (cx + x) * k + 2, (cy + y) * k + 1), px(&small, cx + x, cy + y));
|
||||
}
|
||||
@@ -2828,6 +2906,18 @@ mod hd_atlas_tests {
|
||||
}
|
||||
}
|
||||
}
|
||||
// the variants: as many tiles as the kind has cells, every cell filled
|
||||
for &(base, n, png, png2) in HD_VARS.iter() {
|
||||
for tile in [HD_TILE, HD_TILE2] {
|
||||
let src = Image::from_file_with_format(if tile == HD_TILE2 { png2 } else { png }, Some(ImageFormat::Png)).unwrap();
|
||||
assert_eq!((src.width as u32, src.height as u32), (n * tile, tile), "cell {base}");
|
||||
}
|
||||
for z in 0..8 {
|
||||
for x in 0..8 {
|
||||
assert!((base..base + n).contains(&hd_tile(base, x, z)));
|
||||
}
|
||||
}
|
||||
}
|
||||
// the decals: transparent around their pictures
|
||||
for &(id, _, _) in HD_DECALS.iter() {
|
||||
for tile in [HD_TILE, HD_TILE2] {
|
||||
@@ -2854,7 +2944,7 @@ mod hd_atlas_tests {
|
||||
// the liquids: four variants by position; others stay
|
||||
assert_eq!(hd_tile(T_WATER + 3, 0, 0), T_WATER);
|
||||
assert_eq!(hd_tile(T_LAVA, 1, 1), T_LAVA + 3);
|
||||
assert_eq!(hd_tile(T_TREASURY + 2, 1, 0), T_TREASURY + 2);
|
||||
assert_eq!(hd_tile(T_PUMPKIN + 2, 1, 0), T_PUMPKIN + 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user