crocparty/pytools/spritesheet.py

102 lines
2.6 KiB
Python
Raw Permalink Normal View History

2024-02-27 01:04:37 +00:00
from typing import Tuple
from PIL import Image
import sys
import shared
TEMPLATE = """
// generated code! be nice!
#include "sys/sys.h"
sys_sprite spr_{{spritesheet_name}}_data[{{n_sprites}}] = {
2024-02-27 01:04:37 +00:00
{% for sprite in sprites -%}
{ .pixels={
{% for row in sprite -%}
{ {{ row|join(",") }} }{% if not loop.last %},{% endif %}
{% endfor %}
} }{% if not loop.last %},{% endif %}
{%- endfor %}
};
sys_spritesheet spr_{{spritesheet_name}} = {
.sprites=spr_{{spritesheet_name}}_data,
.width={{width}},
.height={{height}},
};
2024-02-27 01:04:37 +00:00
""".lstrip()
def main(spritesheet_name, n_sprites, key_color, fname_png, fname_c):
sprites, width, height = load_sprites(fname_png, key_color)
2024-02-27 23:57:37 +00:00
assert(len(sprites) == n_sprites), f"must be exactly {n_sprites} sprites, not {len(sprites)}"
2024-02-27 01:04:37 +00:00
with open(fname_c, "wt") as output:
output.write(
shared.templates.from_string(TEMPLATE).render(
spritesheet_name=spritesheet_name,
n_sprites=n_sprites,
sprites=sprites,
width=width,
height=height,
2024-02-27 01:04:37 +00:00
)
)
def load_sprites(fname_png: str, key_color: int):
width, height, data = shared.load_image(fname_png)
sprites = []
for gy in range(0, height, 8):
for gx in range(0, width, 8):
pixels = []
for py in range(0, 8):
row = []
for px in range(0, 8):
x = gx + px
y = gy + py
pal = pixel_to_palette(data[y * width + x], key_color, x, y)
row.append(pal)
pixels.append(row)
sprites.append(pixels)
return sprites, width//8, height//8
2024-02-27 01:04:37 +00:00
palette_colors = {
(0, 0, 0): 0,
(29, 43, 83): 1,
(126, 37, 83): 2,
(0, 135, 81): 3,
(171, 82, 54): 4,
(95, 87, 79): 5,
(194, 195, 199): 6,
(255, 241, 232): 7,
(255, 0, 77): 8,
(255, 163, 0): 9,
(255, 236, 39): 10,
(0, 228, 54): 11,
(41, 173, 255): 12,
(131, 118, 156): 13,
(255, 119, 168): 14,
(255, 204, 170): 15,
}
def pixel_to_palette(rgba, key_color, x, y):
(r, g, b, a) = rgba
if a < 128:
return 255
rgb = (r, g, b)
ix = palette_colors.get(rgb)
if ix is None:
raise ValueError(f"unrecognized color at ({x}, {y}): {rgb}")
if ix == key_color:
return 255
return ix
if __name__ == "__main__":
assert len(sys.argv) == 6, \
"there must be five args (spritesheet name, n sprites, key color, src png, out c)"
main(sys.argv[1], int(sys.argv[2]), int(sys.argv[3]), sys.argv[4], sys.argv[5])