feat: procedural bushy vegetation autotiles
This commit is contained in:
@@ -0,0 +1,214 @@
|
||||
import random
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
|
||||
# 0: Floor
|
||||
# 1: Highlight
|
||||
# 2: Midtone
|
||||
# 3: Shadow
|
||||
|
||||
random.seed(1234) # deterministic
|
||||
|
||||
# Base seamless vegetation pattern (8x8)
|
||||
base_veg = [
|
||||
[2, 1, 2, 2, 3, 2, 2, 1],
|
||||
[1, 2, 2, 1, 2, 2, 3, 2],
|
||||
[2, 2, 3, 2, 2, 1, 2, 2],
|
||||
[3, 2, 2, 1, 2, 2, 2, 3],
|
||||
[2, 1, 2, 2, 3, 2, 2, 2],
|
||||
[2, 2, 2, 3, 2, 1, 2, 2],
|
||||
[2, 3, 2, 2, 2, 2, 1, 2],
|
||||
[1, 2, 2, 1, 2, 3, 2, 2]
|
||||
]
|
||||
base_veg = np.array(base_veg, dtype=np.uint8)
|
||||
|
||||
# To avoid repeating exactly the same pattern, we can roll it slightly per mask
|
||||
# Or we just use it.
|
||||
walls = []
|
||||
|
||||
def make_bush(n, e, s, w, mask_idx):
|
||||
# Start with base vegetation
|
||||
t = np.roll(np.roll(base_veg, mask_idx % 8, axis=0), (mask_idx // 2) % 8, axis=1).copy()
|
||||
|
||||
# Carve N
|
||||
if not n:
|
||||
# Jagged top edge:
|
||||
# col 0..7 randomly floor or highlight
|
||||
for c in range(8):
|
||||
depth = random.choice([0, 1])
|
||||
for r in range(depth):
|
||||
t[r, c] = 0
|
||||
t[depth, c] = 1 # highlight on the leaf tip
|
||||
t[depth+1, c] = 1 # more highlight
|
||||
|
||||
# Carve S
|
||||
if not s:
|
||||
for c in range(8):
|
||||
depth = random.choice([0, 1])
|
||||
for r in range(8 - depth, 8):
|
||||
t[r, c] = 0
|
||||
t[7 - depth, c] = 3 # shadow on the bottom leaf
|
||||
t[6 - depth, c] = 3
|
||||
|
||||
# Carve W
|
||||
if not w:
|
||||
for r in range(8):
|
||||
depth = random.choice([0, 1])
|
||||
for c in range(depth):
|
||||
t[r, c] = 0
|
||||
# Ensure the edge isn't floor, make it a midtone/shadow
|
||||
if t[r, depth] == 0: t[r, depth] = 2
|
||||
|
||||
# Carve E
|
||||
if not e:
|
||||
for r in range(8):
|
||||
depth = random.choice([0, 1])
|
||||
for c in range(8 - depth, 8):
|
||||
t[r, c] = 0
|
||||
if t[r, 7 - depth] == 0: t[r, 7 - depth] = 2
|
||||
|
||||
# Fix Corners if isolated
|
||||
if not n and not w:
|
||||
t[0, 0] = t[0, 1] = t[1, 0] = 0
|
||||
t[1, 1] = 1
|
||||
if not n and not e:
|
||||
t[0, 7] = t[0, 6] = t[1, 7] = 0
|
||||
t[1, 6] = 1
|
||||
if not s and not w:
|
||||
t[7, 0] = t[7, 1] = t[6, 0] = 0
|
||||
t[6, 1] = 3
|
||||
if not s and not e:
|
||||
t[7, 7] = t[7, 6] = t[6, 7] = 0
|
||||
t[6, 6] = 3
|
||||
|
||||
return t
|
||||
|
||||
for mask in range(16):
|
||||
n = (mask & 8) != 0
|
||||
e = (mask & 4) != 0
|
||||
s = (mask & 2) != 0
|
||||
w = (mask & 1) != 0
|
||||
walls.append(make_bush(n, e, s, w, mask))
|
||||
|
||||
floors = [
|
||||
# 0: Clean floor
|
||||
np.array([
|
||||
[0,0,0,0,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,0]
|
||||
], dtype=np.uint8),
|
||||
# 1: Tiny pebble/crack
|
||||
np.array([
|
||||
[0,0,0,0,0,0,0,0],
|
||||
[0,0,1,0,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,1],
|
||||
[0,0,0,0,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,0]
|
||||
], dtype=np.uint8),
|
||||
# 2: Subtle horizontal vein
|
||||
np.array([
|
||||
[0,0,0,0,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,0],
|
||||
[0,1,1,0,0,0,0,0],
|
||||
[0,0,0,1,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,0]
|
||||
], dtype=np.uint8),
|
||||
# 3: Diagonal crack
|
||||
np.array([
|
||||
[0,0,0,0,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,0],
|
||||
[0,0,0,0,0,0,1,0],
|
||||
[0,0,0,0,0,1,0,0],
|
||||
[0,0,0,0,1,0,0,0],
|
||||
[0,0,0,0,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,0]
|
||||
], dtype=np.uint8),
|
||||
# 4: Forked crack
|
||||
np.array([
|
||||
[0,0,0,0,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,0],
|
||||
[0,0,1,0,0,0,0,0],
|
||||
[0,0,0,1,1,0,0,0],
|
||||
[0,0,0,0,0,1,0,0],
|
||||
[0,0,0,0,0,0,0,0]
|
||||
], dtype=np.uint8),
|
||||
# 5: Dots / dust
|
||||
np.array([
|
||||
[0,0,0,0,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,0],
|
||||
[0,0,0,1,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,0],
|
||||
[0,0,0,0,1,0,0,0],
|
||||
[0,0,0,0,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,0]
|
||||
], dtype=np.uint8)
|
||||
]
|
||||
|
||||
def to_gb_format(tile_np):
|
||||
bytes_arr = []
|
||||
for r in range(8):
|
||||
lo = hi = 0
|
||||
for c in range(8):
|
||||
val = int(tile_np[r, c])
|
||||
if val & 1: lo |= (1 << (7 - c))
|
||||
if val & 2: hi |= (1 << (7 - c))
|
||||
bytes_arr.append(lo)
|
||||
bytes_arr.append(hi)
|
||||
return bytes_arr
|
||||
|
||||
with open('src/tiles.c', 'w') as f:
|
||||
f.write('#include "tiles.h"\n\n')
|
||||
f.write(f'const unsigned char TileData[{(6+16)*16}] = {{\n')
|
||||
|
||||
for i, fl in enumerate(floors):
|
||||
f.write(f' // Floor variant {i}\n')
|
||||
b = to_gb_format(fl)
|
||||
f.write(' ' + ', '.join(f"0x{val:02X}" for val in b) + ',\n')
|
||||
|
||||
for i, w in enumerate(walls):
|
||||
f.write(f' // Wall {i}\n')
|
||||
b = to_gb_format(w)
|
||||
f.write(' ' + ', '.join(f"0x{val:02X}" for val in b) + ',\n')
|
||||
|
||||
f.write('};\n')
|
||||
|
||||
colors = {
|
||||
0: (224, 248, 208),
|
||||
1: (136, 192, 112),
|
||||
2: (52, 104, 86),
|
||||
3: (8, 24, 32)
|
||||
}
|
||||
|
||||
cols = 6
|
||||
rows = 4
|
||||
img = Image.new('RGB', (cols * 10, rows * 10), (255, 255, 255))
|
||||
tiles = floors + walls
|
||||
for idx, t in enumerate(tiles):
|
||||
c = idx % cols
|
||||
r = idx // cols
|
||||
x_offset = c * 10 + 1
|
||||
y_offset = r * 10 + 1
|
||||
for ty in range(8):
|
||||
for tx in range(8):
|
||||
color = colors[int(t[ty, tx])]
|
||||
img.putpixel((x_offset + tx, y_offset + ty), color)
|
||||
|
||||
img = img.resize((cols * 10 * 4, rows * 10 * 4), Image.Resampling.NEAREST)
|
||||
img.save('/home/enne2/.gemini/antigravity/brain/69a2b2a9-088f-47ee-9f3c-9ba7ac332992/bush_tiles_preview.png')
|
||||
|
||||
print("tiles.c generated with bush tiles!")
|
||||
+21
-21
@@ -4,45 +4,45 @@ const unsigned char TileData[352] = {
|
||||
// Floor variant 0
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// Floor variant 1
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// Floor variant 2
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// Floor variant 3
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// Floor variant 4
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x18, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
// Floor variant 5
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// Wall 0
|
||||
0x7E, 0x7E, 0x7C, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x7E, 0x7C, 0x7C, 0x00, 0x00,
|
||||
0x3C, 0x00, 0x7E, 0x00, 0xA5, 0x7A, 0x90, 0xEE, 0x48, 0x3F, 0x1E, 0xFE, 0x7E, 0x7E, 0x30, 0x30,
|
||||
// Wall 1
|
||||
0x00, 0x02, 0xFC, 0x02, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0xFC, 0xFE, 0x00, 0x02,
|
||||
0x6C, 0x00, 0xFE, 0x00, 0x93, 0x6E, 0x24, 0xFB, 0x90, 0xEE, 0x6A, 0xFF, 0xFE, 0xFE, 0x9C, 0x9C,
|
||||
// Wall 2
|
||||
0x00, 0x42, 0x3C, 0x42, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E,
|
||||
0x0C, 0x00, 0x7E, 0x00, 0x36, 0x4D, 0x48, 0xB6, 0x12, 0x7D, 0x48, 0x76, 0x24, 0x5E, 0x0A, 0x7C,
|
||||
// Wall 3
|
||||
0x00, 0x02, 0xFC, 0x02, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE,
|
||||
0x64, 0x00, 0xFE, 0x00, 0xDB, 0x26, 0xA4, 0x5E, 0x49, 0xB7, 0x12, 0xFD, 0xC8, 0xF6, 0x24, 0xDF,
|
||||
// Wall 4
|
||||
0x00, 0x40, 0x3F, 0x40, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x3F, 0x7F, 0x00, 0x40,
|
||||
0x36, 0x00, 0x7F, 0x00, 0xD9, 0x36, 0x25, 0xDB, 0x52, 0x2F, 0xBD, 0xDF, 0x7F, 0x7F, 0x22, 0x22,
|
||||
// Wall 5
|
||||
0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x5A, 0x00, 0xFF, 0x00, 0xA5, 0x5A, 0x90, 0x7F, 0x25, 0xDB, 0x72, 0xFF, 0xFF, 0xFF, 0x8F, 0x8F,
|
||||
// Wall 6
|
||||
0x00, 0x40, 0x3F, 0x40, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F,
|
||||
0x1F, 0x00, 0x7F, 0x00, 0x29, 0x57, 0x02, 0x7F, 0x48, 0x3F, 0x92, 0xED, 0x29, 0x57, 0x52, 0x6D,
|
||||
// Wall 7
|
||||
0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x18, 0x00, 0xFF, 0x00, 0xF7, 0x18, 0x09, 0xF7, 0x82, 0x7F, 0x48, 0xBF, 0x92, 0xED, 0x29, 0xD7,
|
||||
// Wall 8
|
||||
0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x3C, 0x7E, 0x00, 0x42,
|
||||
0x94, 0xEB, 0x29, 0x76, 0x42, 0x3E, 0x18, 0xFE, 0x04, 0x7A, 0xDA, 0xFE, 0x7E, 0x7E, 0x24, 0x24,
|
||||
// Wall 9
|
||||
0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0xFC, 0xFE, 0x00, 0x02,
|
||||
0x48, 0xF6, 0x94, 0xEA, 0x29, 0xF6, 0x42, 0xBE, 0x19, 0xFE, 0xDC, 0xFF, 0xFE, 0xFE, 0x20, 0x20,
|
||||
// Wall 10
|
||||
0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E,
|
||||
0x12, 0xEF, 0xA4, 0x7A, 0x4A, 0x75, 0x14, 0x7B, 0x20, 0x5E, 0x0C, 0x7E, 0x42, 0x7C, 0x20, 0x5E,
|
||||
// Wall 11
|
||||
0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE,
|
||||
0xA0, 0xDE, 0x12, 0xEF, 0xA4, 0x7B, 0x4A, 0xF5, 0x94, 0x7A, 0x20, 0xDE, 0x8C, 0x7F, 0x42, 0xFD,
|
||||
// Wall 12
|
||||
0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x3F, 0x7F, 0x00, 0x40,
|
||||
0x21, 0xFE, 0x50, 0x6F, 0x09, 0x77, 0x52, 0x3D, 0x25, 0xFA, 0x4F, 0x3F, 0x7F, 0x7F, 0x38, 0x38,
|
||||
// Wall 13
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x46, 0xBF, 0x21, 0xFE, 0x50, 0xEF, 0x09, 0xF7, 0x52, 0xBD, 0xBD, 0xFA, 0xFF, 0xFF, 0x67, 0x67,
|
||||
// Wall 14
|
||||
0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F,
|
||||
0x48, 0xF7, 0x23, 0xDF, 0x10, 0x7F, 0x28, 0x77, 0x84, 0xFB, 0x29, 0x5E, 0x92, 0x7D, 0x25, 0x5E,
|
||||
// Wall 15
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x25, 0xDE, 0x48, 0xF7, 0x23, 0xDF, 0x90, 0x7F, 0x28, 0xF7, 0x84, 0xFB, 0x29, 0xDE, 0x92, 0x7D,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user