diff --git a/game/BUILD b/game/BUILD index c0eeff6..eda6a89 100644 --- a/game/BUILD +++ b/game/BUILD @@ -1,7 +1,23 @@ +load("@bazel_skylib//rules:run_binary.bzl", "run_binary") + cc_library( name = "game", - srcs = glob(["*.c"]), - hdrs = glob(["*.h"]), + srcs = glob(["*.c"]) + [":art/game_demo_sprites.c"], + hdrs = glob(["*.h"]) + [":art/game_demo_sprites.h"], visibility = ["//visibility:public"], deps = ["//device:device", "//sys:sys"] +) + +run_binary( + name = "game_demo_sprites", + args = [ + "game_demo_sprites", + "256", # n sprites + "0", # key color + "$(location :art/game_demo_sprites.png)", + "$(location :art/game_demo_sprites.c)" + ], + srcs = [":art/game_demo_sprites.png"], + outs = [":art/game_demo_sprites.c"], + tool = "//pytools:spritesheet", ) \ No newline at end of file diff --git a/game/art/game_demo_sprites.h b/game/art/game_demo_sprites.h new file mode 100644 index 0000000..f400544 --- /dev/null +++ b/game/art/game_demo_sprites.h @@ -0,0 +1,8 @@ +#ifndef CROCPARTY_GAME_DEMO_SPRITES_H +#define CROCPARTY_GAME_DEMO_SPRITES_H + +#include "sys/sys.h" + +sys_sprite game_demo_sprites[256]; + +#endif // CROCPARTY_GAME_DEMO_SPRITES_H \ No newline at end of file diff --git a/game/art/game_demo_sprites.png b/game/art/game_demo_sprites.png new file mode 100644 index 0000000..3a08325 Binary files /dev/null and b/game/art/game_demo_sprites.png differ diff --git a/pytools/BUILD b/pytools/BUILD index f30b13f..c0081b6 100644 --- a/pytools/BUILD +++ b/pytools/BUILD @@ -8,4 +8,14 @@ py_binary( requirement("Jinja2"), ], visibility = ["//visibility:public"], +) + +py_binary( + name = "spritesheet", + srcs = ["spritesheet.py", "shared.py"], + deps = [ + requirement("pillow"), + requirement("Jinja2"), + ], + visibility = ["//visibility:public"], ) \ No newline at end of file diff --git a/pytools/font.py b/pytools/font.py index a186701..e14afbd 100644 --- a/pytools/font.py +++ b/pytools/font.py @@ -26,7 +26,6 @@ def main(font_name, n_glyphs, fname_png, fname_c): def load_glyphs(fname_png: str): width, height, data = shared.load_image(fname_png) - monochrome = [pixel_to_monochrome(p) for p in data] glyphs = [] for gy in range(0, height, 8): @@ -36,7 +35,7 @@ def load_glyphs(fname_png: str): for px in range(0, 8): x = gx + px y = gy + py - if monochrome[y * width + x]: + if pixel_to_monochrome(data[y * width + x]): glyph |= 1 << (py * 8 + px) glyphs.append(glyph) diff --git a/pytools/spritesheet.py b/pytools/spritesheet.py new file mode 100644 index 0000000..344284b --- /dev/null +++ b/pytools/spritesheet.py @@ -0,0 +1,95 @@ +from typing import Tuple +from PIL import Image +import sys +import shared + +TEMPLATE = """ +// generated code! be nice! +#include "sys/sys.h" +sys_sprite {{spritesheet_name}}[{{n_sprites}}] = { + {% for sprite in sprites -%} + { .pixels={ + {% for row in sprite -%} + { {{ row|join(",") }} }{% if not loop.last %},{% endif %} + {% endfor %} + } }{% if not loop.last %},{% endif %} + {%- endfor %} +}; +""".lstrip() + + +def main(spritesheet_name, n_sprites, key_color, fname_png, fname_c): + sprites = load_sprites(fname_png, key_color) + assert(len(sprites) == n_sprites), f"must be exactly {n_sprites} sprites" + + 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, + ) + ) + + +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 + + +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]) \ No newline at end of file