feat: rip true tiles from AI mockup

This commit is contained in:
2026-06-18 11:20:48 +02:00
parent 3ea3029f4b
commit e91bb58237
2 changed files with 165 additions and 35 deletions
+120
View File
@@ -0,0 +1,120 @@
import os
from PIL import Image
import numpy as np
img_path = '/home/enne2/.gemini/antigravity/brain/69a2b2a9-088f-47ee-9f3c-9ba7ac332992/test_mockup_clean.png'
img = Image.open(img_path).convert('RGB')
img = img.resize((160, 144), Image.Resampling.LANCZOS)
gray = img.convert('L')
arr = np.array(gray)
quantized = np.zeros_like(arr, dtype=np.uint8)
quantized[arr >= 192] = 0
quantized[(arr >= 128) & (arr < 192)] = 1
quantized[(arr >= 64) & (arr < 128)] = 2
quantized[arr < 64] = 3
is_wall = np.zeros((18, 20), dtype=bool)
for y in range(18):
for x in range(20):
tile = quantized[y*8:(y+1)*8, x*8:(x+1)*8]
if np.sum(tile > 0) > 32:
is_wall[y, x] = True
for y in range(18):
is_wall[y, 0] = False
is_wall[y, 19] = False
for x in range(20):
is_wall[0, x] = False
is_wall[16, x] = False
is_wall[17, x] = False
mockup_extracted = {}
# We'll extract 6 floor tiles to give variety!
floors = []
for y in range(2, 15):
for x in range(2, 18):
if not is_wall[y, x]:
floors.append(quantized[y*8:(y+1)*8, x*8:(x+1)*8])
if len(floors) == 6:
break
if len(floors) == 6: break
# If we couldn't find 6, just pad
while len(floors) < 6:
floors.append(np.zeros((8, 8), dtype=np.uint8))
for y in range(1, 16):
for x in range(1, 19):
if is_wall[y, x]:
n = is_wall[y-1, x]
s = is_wall[y+1, x]
e = is_wall[y, x+1]
w = is_wall[y, x-1]
mask = (8 if n else 0) | (4 if e else 0) | (2 if s else 0) | (1 if w else 0)
if mask not in mockup_extracted:
mockup_extracted[mask] = quantized[y*8:(y+1)*8, x*8:(x+1)*8]
# Ensure all 16 masks exist
# If a mask is missing, try to synthesize it by rotating/flipping or just defaulting to mask 15
base_wall = mockup_extracted.get(15, np.full((8,8), 2, dtype=np.uint8))
def patch_mask(mask):
if mask in mockup_extracted:
return mockup_extracted[mask]
# Very simple synthesis using the base wall 15, and floor tiles to cut the edges
t = np.copy(base_wall)
f = floors[0]
n = (mask & 8) != 0
e = (mask & 4) != 0
s = (mask & 2) != 0
w = (mask & 1) != 0
if not n:
t[0,:] = f[0,:]
t[1,:] = 1 # highlight
if not s:
t[6,:] = 3
t[7,:] = f[7,:]
if not w:
t[:,0] = f[:,0]
t[:,1] = 2
if not e:
t[:,7] = f[:,7]
t[:,6] = 2
return t
walls = []
for mask in range(16):
walls.append(patch_mask(mask))
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')
print("tiles.c generated directly from mockup!")
+45 -35
View File
@@ -1,38 +1,48 @@
#include "tiles.h" #include "tiles.h"
const unsigned char TileData[272] = { const unsigned char TileData[352] = {
// Tile 0 (Mask Floor) // Floor variant 0
0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Tile 1 (Mask 0) // Floor variant 1
0x00, 0x00, 0x1E, 0x00, 0x3E, 0x00, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x3E, 0x3E, 0x1E, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Tile 2 (Mask 1) // Floor variant 2
0x00, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0xFE, 0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Tile 3 (Mask 2) // Floor variant 3
0x00, 0x00, 0x1E, 0x00, 0x3E, 0x00, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Tile 4 (Mask 3) // Floor variant 4
0x00, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Tile 5 (Mask 4) // Floor variant 5
0x00, 0x00, 0x1F, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x3F, 0x3F, 0x1F, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Tile 6 (Mask 5) // Wall 0
0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x7E, 0x7C, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x7E, 0x7C, 0x7C, 0x00, 0x00,
// Tile 7 (Mask 6) // Wall 1
0x00, 0x00, 0x1F, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x02, 0xFC, 0x02, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0xFC, 0xFE, 0x00, 0x02,
// Tile 8 (Mask 7) // Wall 2
0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x42, 0x3C, 0x42, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E,
// Tile 9 (Mask 8) // Wall 3
0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x3E, 0x3E, 0x1E, 0x1E, 0x00, 0x02, 0xFC, 0x02, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE,
// Tile 10 (Mask 9) // Wall 4
0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0xFE, 0xFE, 0xFE, 0xFE, 0x00, 0x40, 0x3F, 0x40, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x3F, 0x7F, 0x00, 0x40,
// Tile 11 (Mask 10) // Wall 5
0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
// Tile 12 (Mask 11) // Wall 6
0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0x40, 0x3F, 0x40, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F,
// Tile 13 (Mask 12) // Wall 7
0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x3F, 0x3F, 0x1F, 0x1F, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
// Tile 14 (Mask 13) // Wall 8
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x3C, 0x7E, 0x00, 0x42,
// Tile 15 (Mask 14) // Wall 9
0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0xFC, 0xFE, 0x00, 0x02,
// Tile 16 (Mask 15) // Wall 10
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x10, 0xEF, 0x04, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E,
// Wall 11
0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE,
// Wall 12
0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x3F, 0x7F, 0x00, 0x40,
// Wall 13
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
// Wall 14
0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F,
// Wall 15
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
}; };