tools/generate: move maps to a new module

This commit is contained in:
Zack Buhman 2023-07-25 05:43:09 +00:00
parent b03055c3a5
commit e37d56b729
5 changed files with 193 additions and 194 deletions

View File

@ -75,6 +75,6 @@ main.elf: $(OBJ)
clean: clean-sh clean: clean-sh
clean-sh: clean-sh:
rm -rf res rm -rf res gen
PHONY: generated-headers PHONY: generated-headers

View File

@ -1,207 +1,21 @@
from pathlib import Path from pathlib import Path
from pprint import pprint from pprint import pprint
import io
import sys import sys
from parse import parse from generate import maps
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<uint8_t*>(&{start}),",
f"reinterpret_cast<uint32_t>(&{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
def generate(base_path): def generate(base_path):
files = [ files = [
(generate_maps_header, "maps.hpp"), (maps.generate_maps_header, "maps.hpp"),
(generate_maps_source, "maps.cpp"), (maps.generate_maps_source, "maps.cpp"),
] ]
for func, filename in files: for func, filename in files:
path = base_path / filename path = base_path / filename
with open(path, 'w') as f: with open(path, 'w') as f:
f.write(func().getvalue()) f.write(func().getvalue())
print(path)
# sys.argv[1] is secretly used in parse # sys.argv[1] is secretly used in parse
base_path = Path(sys.argv[2]) base_path = Path(sys.argv[2])
generate(base_path) 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'
"""

View File

@ -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

166
tools/generate/maps.py Normal file
View File

@ -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<uint8_t*>(&{start}),",
f"reinterpret_cast<uint32_t>(&{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'
"""

View File

@ -81,6 +81,4 @@ def parse(path):
def parse_all(prefix): def parse_all(prefix):
base_path = prefix / 'data/maps/headers' base_path = prefix / 'data/maps/headers'
paths = [p for p in base_path.iterdir() if p.is_file()] 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] return [parse(path) for path in paths]