Minimal Game Boy Hello World using GBDK-2020 and PyBoy
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

120 lines
3.4 KiB

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