Browse Source

feat: rip true tiles from AI mockup

master
Matteo Benedetto 3 days ago
parent
commit
e91bb58237
  1. 120
      extract_to_tiles_c.py
  2. 80
      src/tiles.c

120
extract_to_tiles_c.py

@ -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!")

80
src/tiles.c

@ -1,38 +1,48 @@
#include "tiles.h"
const unsigned char TileData[272] = {
// Tile 0 (Mask Floor)
0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00,
// Tile 1 (Mask 0)
0x00, 0x00, 0x1E, 0x00, 0x3E, 0x00, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x3E, 0x3E, 0x1E, 0x1E,
// Tile 2 (Mask 1)
0x00, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0xFE, 0xFE, 0xFE, 0xFE,
// Tile 3 (Mask 2)
0x00, 0x00, 0x1E, 0x00, 0x3E, 0x00, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C,
// Tile 4 (Mask 3)
0x00, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC,
// Tile 5 (Mask 4)
0x00, 0x00, 0x1F, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x3F, 0x3F, 0x1F, 0x1F,
// Tile 6 (Mask 5)
0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// Tile 7 (Mask 6)
0x00, 0x00, 0x1F, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F,
// Tile 8 (Mask 7)
0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
// Tile 9 (Mask 8)
0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x3E, 0x3E, 0x1E, 0x1E,
// Tile 10 (Mask 9)
0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0xFE, 0xFE, 0xFE, 0xFE,
// Tile 11 (Mask 10)
0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C,
// Tile 12 (Mask 11)
0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC,
// Tile 13 (Mask 12)
0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x3F, 0x3F, 0x1F, 0x1F,
// Tile 14 (Mask 13)
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// Tile 15 (Mask 14)
0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F,
// Tile 16 (Mask 15)
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x10, 0xEF, 0x04, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
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,
// Floor variant 2
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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,
// Floor variant 4
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Floor variant 5
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Wall 0
0x7E, 0x7E, 0x7C, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x7E, 0x7C, 0x7C, 0x00, 0x00,
// Wall 1
0x00, 0x02, 0xFC, 0x02, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0xFC, 0xFE, 0x00, 0x02,
// Wall 2
0x00, 0x42, 0x3C, 0x42, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E,
// Wall 3
0x00, 0x02, 0xFC, 0x02, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE,
// Wall 4
0x00, 0x40, 0x3F, 0x40, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x3F, 0x7F, 0x00, 0x40,
// Wall 5
0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
// Wall 6
0x00, 0x40, 0x3F, 0x40, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F,
// Wall 7
0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
// Wall 8
0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x3C, 0x7E, 0x00, 0x42,
// Wall 9
0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0xFC, 0xFE, 0x00, 0x02,
// Wall 10
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,
};

Loading…
Cancel
Save