From e37d56b7291ce61fe7bc5dd077bda35486f70f79 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Tue, 25 Jul 2023 05:43:09 +0000 Subject: [PATCH] tools/generate: move maps to a new module --- Makefile | 2 +- tools/generate/__main__.py | 192 +------------------------------------ tools/generate/generate.py | 25 ++++- tools/generate/maps.py | 166 ++++++++++++++++++++++++++++++++ tools/parse/map_header.py | 2 - 5 files changed, 193 insertions(+), 194 deletions(-) create mode 100644 tools/generate/maps.py diff --git a/Makefile b/Makefile index f8bded4..e4d1f60 100644 --- a/Makefile +++ b/Makefile @@ -75,6 +75,6 @@ main.elf: $(OBJ) clean: clean-sh clean-sh: - rm -rf res + rm -rf res gen PHONY: generated-headers diff --git a/tools/generate/__main__.py b/tools/generate/__main__.py index 6ea9f34..7f0aed3 100644 --- a/tools/generate/__main__.py +++ b/tools/generate/__main__.py @@ -1,207 +1,21 @@ from pathlib import Path from pprint import pprint -import io import sys -from parse import parse - -def sorted_map_headers(): - # hack to remove unused/duplicate underground_path_route_7 - map_headers = sorted(parse.map_headers, key=lambda m: m.name2) - return filter(lambda m: m.name1 != "UndergroundPathRoute7Copy", map_headers) - -def includes(): - for map_header in sorted_map_headers(): - block_path = parse.maps_blocks_list[map_header.blocks()] - yield f'#include "../res/{block_path}.h"' - for tileset_name in sorted(parse.tileset_constants_list): - tileset_index = parse.tileset_constants_list[tileset_name] - tileset_header = parse.tileset_headers_list[tileset_index] - - blockset_path = parse.gfx_tilesets_list[tileset_header.blockset()] - gfx_path = parse.gfx_tilesets_list[tileset_header.gfx()] - - yield f'#include "../res/{blockset_path}.h"' - yield f'#include "../res/{gfx_path}.h"' - yield "" - -def struct_start_size_t(): - return [ - "struct start_size_t {", - "uint8_t const * const start;", - "uint32_t size;", - "};", - ] - -def struct_tileset_t(): - tileset_names = ( - f"{name.lower()}," - for name in sorted(parse.tileset_constants_list) - ) - return [ - "struct tileset_t {", - "start_size_t blockset;", - "start_size_t tileset;", - "", - "enum tileset {", - *tileset_names, - "};", - "};", - ] - -def struct_map_t(): - map_names = ( - f"{map_header.name2.lower()}," - for map_header in sorted_map_headers() - ) - return [ - "struct map_t {", - "start_size_t blocks;", - "enum tileset_t::tileset tileset;", - "uint32_t width;", - "uint32_t height;", - "", - "enum map {", - *map_names, - "};", - "};", - ] - -def binary_res(path, suffix): - # _binary_res_gfx_blocksets_overworld_bst_start - name = path.replace('/', '_').replace('.', '_') - return f"_binary_res_{name}_{suffix}" - -def start_size_value(path): - start = binary_res(path, "start") - size = binary_res(path, "size") - - return [ - f"reinterpret_cast(&{start}),", - f"reinterpret_cast(&{size}),", - ] - -def blockset_tileset(name: str): - tileset_index = parse.tileset_constants_list[name] - tileset_header = parse.tileset_headers_list[tileset_index] - - blockset_path = parse.gfx_tilesets_list[tileset_header.blockset()] - gfx_path = parse.gfx_tilesets_list[tileset_header.gfx()] - - return [ - f"[tileset_t::{name.lower()}] = {{", - ".blockset = {", - *start_size_value(blockset_path), - "},", - ".tileset = {", - *start_size_value(gfx_path), - "}", - "}," - ] - -def tilesets_header(): - yield "extern const tileset_t tilesets[];" - -def tilesets(): - yield "const tileset_t tilesets[] = {" - for tileset in sorted(parse.tileset_constants_list): - yield from blockset_tileset(tileset) - yield "};" - -def map(map_header): - block_path = parse.maps_blocks_list[map_header.blocks()] - map_constant = parse.map_constants_list[map_header.name2] - return [ - f"[map_t::{map_header.name2.lower()}] = {{", - ".blocks = {", - *start_size_value(block_path), - "},", - f".tileset = tileset_t::{map_header.tileset.lower()},", - f".width = {map_constant.width},", - f".height = {map_constant.height},", - "},", - ] - -def maps_header(): - yield "extern const map_t maps[];" - -def maps(): - yield "const map_t maps[] = {" - for map_header in sorted_map_headers(): - yield from map(map_header) - yield "};" - -def _render(out, lines): - indent = " " - level = 0 - for l in lines: - if l and l[0] == "}": - level -= 2 - assert level >= 0, out.getvalue() - - out.write(indent * level + l + "\n") - - if l and l[-1] == "{": - level += 2 - - if level == 0 and l and l[-1] == ";": - out.write("\n") - return out - -def renderer(): - out = io.StringIO() - def render(lines): - return _render(out, lines) - return render, out - -def generate_maps_header(): - render, out = renderer() - render(includes()) - render(struct_start_size_t()) - render(struct_tileset_t()) - render(struct_map_t()) - render(tilesets_header()); - render(maps_header()); - return out - -def include_maps_header(): - yield '#include "maps.hpp"' - yield "" - -def generate_maps_source(): - render, out = renderer() - render(include_maps_header()) - render(tilesets()) - render(maps()) - return out +from generate import maps def generate(base_path): files = [ - (generate_maps_header, "maps.hpp"), - (generate_maps_source, "maps.cpp"), + (maps.generate_maps_header, "maps.hpp"), + (maps.generate_maps_source, "maps.cpp"), ] for func, filename in files: path = base_path / filename with open(path, 'w') as f: f.write(func().getvalue()) - print(path) # sys.argv[1] is secretly used in parse base_path = Path(sys.argv[2]) generate(base_path) -""" -map_headers[0].tileset == 'OVERWORLD' -map_headers[0].name1 = 'PalletTown' -map_headers[0].name2 = 'PALLET_TOWN' -map_headers[0].blocks() == 'PalletTown_Blocks' -map_constants_list['PALLET_TOWN'] == MapConstant(10, 19) -maps_blocks_list['PalletTown_Blocks'] == 'maps/PalletTown.blk' -tileset_constants_list['OVERWORLD'] == 0 -tileset_headers_list[0].name == 'Overworld' -tileset_headers_list[0].blockset() == 'Overworld_Block' -tileset_headers_list[0].gfx() == 'Overworld_GFX' -gfx_tilesets_list['Overworld_Block'] == 'gfx/blocksets/overworld.bst' -gfx_tilesets_list['Overworld_GFX'] == 'gfx/tilesets/overworld.2bpp' -""" diff --git a/tools/generate/generate.py b/tools/generate/generate.py index 6be1b31..3bc5554 100644 --- a/tools/generate/generate.py +++ b/tools/generate/generate.py @@ -1,3 +1,24 @@ -from pathlib import Path +import io -prefix = Path(sys.argv[2]) +def _render(out, lines): + indent = " " + level = 0 + for l in lines: + if l and l[0] == "}": + level -= 2 + assert level >= 0, out.getvalue() + + out.write(indent * level + l + "\n") + + if l and l[-1] == "{": + level += 2 + + if level == 0 and l and l[-1] == ";": + out.write("\n") + return out + +def renderer(): + out = io.StringIO() + def render(lines): + return _render(out, lines) + return render, out diff --git a/tools/generate/maps.py b/tools/generate/maps.py new file mode 100644 index 0000000..ffd00ea --- /dev/null +++ b/tools/generate/maps.py @@ -0,0 +1,166 @@ +from parse import parse + +from generate.generate import renderer + +def sorted_map_headers(): + # hack to remove unused/duplicate underground_path_route_7 + map_headers = sorted(parse.map_headers, key=lambda m: m.name2) + return filter(lambda m: m.name1 != "UndergroundPathRoute7Copy", map_headers) + +def includes(): + for map_header in sorted_map_headers(): + block_path = parse.maps_blocks_list[map_header.blocks()] + yield f'#include "../res/{block_path}.h"' + for tileset_name in sorted(parse.tileset_constants_list): + tileset_index = parse.tileset_constants_list[tileset_name] + tileset_header = parse.tileset_headers_list[tileset_index] + + blockset_path = parse.gfx_tilesets_list[tileset_header.blockset()] + gfx_path = parse.gfx_tilesets_list[tileset_header.gfx()] + + yield f'#include "../res/{blockset_path}.h"' + yield f'#include "../res/{gfx_path}.h"' + yield "" + +def struct_start_size_t(): + return [ + "struct start_size_t {", + "uint8_t const * const start;", + "uint32_t size;", + "};", + ] + +def struct_tileset_t(): + tileset_names = ( + f"{name.lower()}," + for name in sorted(parse.tileset_constants_list) + ) + return [ + "struct tileset_t {", + "start_size_t blockset;", + "start_size_t tileset;", + "", + "enum tileset {", + *tileset_names, + "};", + "};", + ] + +def struct_map_t(): + map_names = ( + f"{map_header.name2.lower()}," + for map_header in sorted_map_headers() + ) + return [ + "struct map_t {", + "start_size_t blocks;", + "enum tileset_t::tileset tileset;", + "uint32_t width;", + "uint32_t height;", + "", + "enum map {", + *map_names, + "};", + "};", + ] + +def binary_res(path, suffix): + # _binary_res_gfx_blocksets_overworld_bst_start + name = path.replace('/', '_').replace('.', '_') + return f"_binary_res_{name}_{suffix}" + +def start_size_value(path): + start = binary_res(path, "start") + size = binary_res(path, "size") + + return [ + f"reinterpret_cast(&{start}),", + f"reinterpret_cast(&{size}),", + ] + +def blockset_tileset(name: str): + tileset_index = parse.tileset_constants_list[name] + tileset_header = parse.tileset_headers_list[tileset_index] + + blockset_path = parse.gfx_tilesets_list[tileset_header.blockset()] + gfx_path = parse.gfx_tilesets_list[tileset_header.gfx()] + + return [ + f"[tileset_t::{name.lower()}] = {{", + ".blockset = {", + *start_size_value(blockset_path), + "},", + ".tileset = {", + *start_size_value(gfx_path), + "}", + "}," + ] + +def tilesets_header(): + yield "extern const tileset_t tilesets[];" + +def tilesets(): + yield "const tileset_t tilesets[] = {" + for tileset in sorted(parse.tileset_constants_list): + yield from blockset_tileset(tileset) + yield "};" + +def map(map_header): + block_path = parse.maps_blocks_list[map_header.blocks()] + map_constant = parse.map_constants_list[map_header.name2] + return [ + f"[map_t::{map_header.name2.lower()}] = {{", + ".blocks = {", + *start_size_value(block_path), + "},", + f".tileset = tileset_t::{map_header.tileset.lower()},", + f".width = {map_constant.width},", + f".height = {map_constant.height},", + "},", + ] + +def maps_header(): + yield "extern const map_t maps[];" + +def maps(): + yield "const map_t maps[] = {" + for map_header in sorted_map_headers(): + yield from map(map_header) + yield "};" + +def generate_maps_header(): + render, out = renderer() + render(includes()) + render(struct_start_size_t()) + render(struct_tileset_t()) + render(struct_map_t()) + render(tilesets_header()); + render(maps_header()); + return out + +def include_maps_header(): + yield '#include "maps.hpp"' + yield "" + +def generate_maps_source(): + render, out = renderer() + render(include_maps_header()) + render(tilesets()) + render(maps()) + return out + + +""" +map_headers[0].tileset == 'OVERWORLD' +map_headers[0].name1 = 'PalletTown' +map_headers[0].name2 = 'PALLET_TOWN' +map_headers[0].blocks() == 'PalletTown_Blocks' +map_constants_list['PALLET_TOWN'] == MapConstant(10, 19) +maps_blocks_list['PalletTown_Blocks'] == 'maps/PalletTown.blk' +tileset_constants_list['OVERWORLD'] == 0 +tileset_headers_list[0].name == 'Overworld' +tileset_headers_list[0].blockset() == 'Overworld_Block' +tileset_headers_list[0].gfx() == 'Overworld_GFX' +gfx_tilesets_list['Overworld_Block'] == 'gfx/blocksets/overworld.bst' +gfx_tilesets_list['Overworld_GFX'] == 'gfx/tilesets/overworld.2bpp' +""" diff --git a/tools/parse/map_header.py b/tools/parse/map_header.py index e053a40..defc93e 100644 --- a/tools/parse/map_header.py +++ b/tools/parse/map_header.py @@ -81,6 +81,4 @@ def parse(path): def parse_all(prefix): base_path = prefix / 'data/maps/headers' paths = [p for p in base_path.iterdir() if p.is_file()] - from pprint import pprint - pprint(paths) return [parse(path) for path in paths]