ys2-intro/assets/ys2/09_island_scroller_vertical_todo/tilemap_tool2.py
2025-11-15 13:09:41 +01:00

136 lines
3.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from PIL import Image
import csv
import sys
import os
TILE_W = 8
TILE_H = 8
TILES_PER_ROW = 24 # because 24 tiles * 8 px = 192 px rows in the map
def load_tileset(path):
tileset = Image.open(path).convert("RGBA")
ts_w, ts_h = tileset.size
tiles_x = ts_w // TILE_W
tiles_y = ts_h // TILE_H
tiles = []
for ty in range(tiles_y):
for tx in range(tiles_x):
tile = tileset.crop((
tx * TILE_W,
ty * TILE_H,
tx * TILE_W + TILE_W,
ty * TILE_H + TILE_H
))
tiles.append(tile)
print(f"Tileset loaded: {len(tiles)} tiles ({tiles_x}×{tiles_y})")
return tiles
def find_tile_index(block, tiles):
"""Return index of tile in tiles[] or raise error if not found."""
for i, t in enumerate(tiles):
if list(block.getdata()) == list(t.getdata()):
print(f"Made {i}, {t}")
return i
raise ValueError("Tile not found in tileset!")
def build_csv_from_image(src_path, tileset_path, csv_out):
img = Image.open(src_path).convert("RGBA")
w, h = img.size
tiles = load_tileset(tileset_path)
# Must be aligned
if w % TILE_W != 0 or h % TILE_H != 0:
raise ValueError("Image dimensions must be multiples of 8.")
map_w = w // TILE_W
map_h = h // TILE_H
print(f"Building CSV: {map_w}×{map_h} tiles")
rows = []
tile_indices = []
# Scan image in 8×8 blocks
for ty in range(map_h):
row_tiles = []
for tx in range(map_w):
block = img.crop((
tx * TILE_W,
ty * TILE_H,
tx * TILE_W + TILE_W,
ty * TILE_H + TILE_H
))
idx = find_tile_index(block, tiles)
row_tiles.append(idx)
tile_indices.append(row_tiles)
# Output CSV with line breaks after 24 tiles
with open(csv_out, "w", newline="") as f:
writer = csv.writer(f)
for row in tile_indices:
# 24-tile chunks
for i in range(0, len(row), TILES_PER_ROW):
writer.writerow(row[i:i + TILES_PER_ROW])
print(f"CSV written to {csv_out}")
def build_png_from_csv(csv_path, tileset_path, out_path):
tiles = load_tileset(tileset_path)
# Read CSV
tile_rows = []
with open(csv_path, newline="") as f:
reader = csv.reader(f)
for row in reader:
if row:
tile_rows.append([int(v) for v in row])
height_blocks = len(tile_rows)
width_blocks = len(tile_rows[0])
out_w = width_blocks * TILE_W
out_h = height_blocks * TILE_H
out_img = Image.new("RGBA", (out_w, out_h))
print(f"Reconstructing {out_w}×{out_h} image")
for ty, row in enumerate(tile_rows):
for tx, tile_index in enumerate(row):
tile = tiles[tile_index]
out_img.paste(tile, (tx * TILE_W, ty * TILE_H))
out_img.save(out_path)
print(f"Reconstructed PNG saved to {out_path}")
# -----------------------------------------------------------------------
# Command-line wrapper
# -----------------------------------------------------------------------
if __name__ == "__main__":
if len(sys.argv) < 5:
print("Usage:")
print(" python build_tilemap.py makemap <tileset.png> <image.png> <out.csv>")
print(" python build_tilemap.py makepng <tileset.png> <in.csv> <out.png>")
sys.exit(1)
mode = sys.argv[1].lower()
tile = sys.argv[2]
a = sys.argv[3]
b = sys.argv[4]
if mode == "makemap":
build_csv_from_image(a, tile, b)
elif mode == "makepng":
build_png_from_csv(a, tile, b)
else:
print("Unknown mode.")