physics_engine/tools/parse_map.py

152 lines
3.3 KiB
Python

from PIL import Image
import sys
from dataclasses import dataclass
from generate import renderer
from os import path
visited = set()
@dataclass
class vec3:
x: float
y: float
z: float
@dataclass
class Platform:
scale: vec3
position: vec3
def parse_width(x, y, get_pixel):
width = 0
while True:
px = get_pixel(x, y)
if px[0] != 0:
width += 1
x += 1
else:
break
return width
def parse_height(x, y, get_pixel):
height = 0
while True:
px = get_pixel(x, y)
if px[0] != 0:
height += 1
y += 1
else:
break
return height
def round_to_one(n):
if n == 0:
return 1
else:
return n
def visit_pixels(x, y, width, height):
for yi in range(round_to_one(height)):
for xi in range(round_to_one(width)):
xx = x + xi
yy = y + yi
location = (xx, yy)
assert location not in visited
visited.add(location)
def parse_platform(x, y, get_pixel):
width = parse_width(x, y, get_pixel)
height = parse_height(x, y, get_pixel)
visit_pixels(x, y, width, height)
if width != 0 and height != 0:
px = get_pixel(x, y)
position = vec3(
x + (width / 2),
(px[0] - 128),
y + (height / 2),
)
scale = vec3(
width,
1,
height,
)
return Platform(
position=position,
scale=scale,
)
else:
return None
def find_platforms(im):
width, height = im.size
pixels = im.convert("RGB").getdata()
def get_pixel(x, y):
return pixels[y * width + x]
platforms = []
for y in range(height):
for x in range(width):
if (x, y) not in visited:
platform = parse_platform(x, y, get_pixel)
if platform is not None:
platforms.append(platform)
return platforms
def format_vec3(v):
return ", ".join((
f"{n: 8.03f}"
for n in [v.x, v.y, v.z]
))
def generate_platform(platform):
yield "{"
yield f".position = vec3({format_vec3(platform.position)}),"
yield f".scale = vec3({format_vec3(platform.scale)}),"
yield "},"
def generate_level(name, platforms):
yield f"world::platform {name}_platforms[] = {{"
for platform in platforms:
yield from generate_platform(platform)
yield "};"
yield f"world::level {name}_level = {{"
yield f".platforms = {name}_platforms,"
yield f".platforms_length = (sizeof ({name}_platforms)) / (sizeof (world::platform)),"
yield "};"
def generate_file(name_platforms_list):
yield '#include "demo/lizard/world.hpp"'
yield ""
yield f"namespace demo {{"
yield ""
for name, platforms in name_platforms_list:
yield from generate_level(name, platforms)
yield ""
yield '}'
def level_name(p):
_, fn = path.split(p)
name, _ = path.splitext(fn)
return name
def find_all_platforms(maps):
for filename in maps:
with Image.open(filename) as im:
name = level_name(filename)
platforms = find_platforms(im)
yield (name, platforms)
maps = sys.argv[1:]
render, out = renderer()
render(generate_file(find_all_platforms(maps)))
sys.stdout.write(out.getvalue())