assets_dir

This commit is contained in:
Alex Bates 2021-02-06 03:36:46 +00:00
parent 19390fcb02
commit ce7c13b5b1
14 changed files with 87 additions and 56 deletions

6
.gitignore vendored
View File

@ -26,11 +26,7 @@ build.ninja
/tools/permuter_settings.toml /tools/permuter_settings.toml
# Assets # Assets
/bin /assets
/img
/msg
/sprite
/src/**/*.png
# Star Rod # Star Rod
/sprite/SpriteTable.xml /sprite/SpriteTable.xml

View File

@ -16,6 +16,8 @@ import split
INCLUDE_ASM_RE = re.compile(r"___INCLUDE_ASM\([^,]+, ([^,]+), ([^,)]+)") # note _ prefix INCLUDE_ASM_RE = re.compile(r"___INCLUDE_ASM\([^,]+, ([^,]+), ([^,)]+)") # note _ prefix
TARGET = "papermario" TARGET = "papermario"
BUILD_DIR = "build"
ASSET_DIRS = ["assets"]
NPC_SPRITES = "world_goombario world_kooper world_bombette world_parakarry world_bow world_watt world_sushie world_lakilester battle_goombario battle_kooper battle_bombette battle_parakarry battle_bow battle_watt battle_sushie battle_lakilester kooper_without_shell world_eldstar world_mamar world_skolar world_muskular world_misstar world_klevar world_kalmar battle_eldstar battle_mamar battle_skolar battle_muskular battle_misstar battle_klevar battle_kalmar twink jr_troopa spiked_jr_troopa spiked_para_jr_troopa mage_jr_troopa para_jr_troopa goomba spiked_goomba paragoomba koopa_troopa para_troopa fuzzy bob_omb bullet_bill bill_blaster monty_mole cleft pokey battle_bandit buzzy_beetle swooper stone_chomp putrid_piranha piranha_plant sentinel world_clubba battle_clubba shy_guy groove_guy sky_guy pyro_guy spy_guy medi_guy fuzzipede jungle_guy heart_plant hurt_plant m_bush bubble kent_c_koopa dayzee lakitu spiny bzzap ruff_puff spike_top duplighost albino_dino blooper baby_blooper gulpit dry_bones thrown_bone bony_beetle magikoopa flying_magikoopa world_koopatrol koopatrol hammer_bros bush_basic bush_blocky bush_dry bush_leafy bush_matted world_kammy battle_kammy goomba_bros goomba_king spiky_goomnut dark_toad koopa_bros buzzar tutankoopa chain_chomp world_tubba battle_tubba tubbas_heart big_lantern_ghost shy_squad_guy marshal_guy stilt_guy stilt_guy_unfold shy_stack_guy shy_stack_unfold shy_stack_damage shy_stack_rock general_guy general_guy_bomb tank_guy lava_piranha_head petit_piranha lava_bud huff_n_puff tuff_puff monstar crystal_king world_bowser battle_bowser luigi toad three_sisters vanna_t toad_kid toad_guard harry_t toad_minister postmaster conductor_toad train_station_toad fishmael artist_toad koopa koopa_without_shell world_bob_omb whacka dryite mouser boo yoshi yoshi_kid raven bubulb penguin shiver_toad world_bandit goompa goombaria gooma goompapa goomama the_master chan lee merlon chet_rippo rowf minh_t russ_t tayce_t fice_t bartender chanterelle rip_cheato chuck_quizmo merluvlee merlar merlow star_kid kolorado_wife koopa_koot kolorado battle_kolorado archeologist nomadimouse world_merlee battle_merlee disguised_moustafa moustafa oaklie bootler yakkey gourmet_guy village_leader leaders_friend rafael_raven tolielup gate_flower petunia posie lily rosie sun lakilulu ninji mayor_penguin mayor_penguin_wife penguin_patrol herringway merle star_rod fire coin parade_peach parade_koopas parade_burnt_bowser parade_luigi parade_partners parade_yoshis parade_kolorados parade_chicks parade_ice_show parade_toads parade_batons parade_drums parade_flags parade_horns parade_tubba_balloon parade_wizards parade_mario parade_shy_guys parade_twink leaf".split(" ") NPC_SPRITES = "world_goombario world_kooper world_bombette world_parakarry world_bow world_watt world_sushie world_lakilester battle_goombario battle_kooper battle_bombette battle_parakarry battle_bow battle_watt battle_sushie battle_lakilester kooper_without_shell world_eldstar world_mamar world_skolar world_muskular world_misstar world_klevar world_kalmar battle_eldstar battle_mamar battle_skolar battle_muskular battle_misstar battle_klevar battle_kalmar twink jr_troopa spiked_jr_troopa spiked_para_jr_troopa mage_jr_troopa para_jr_troopa goomba spiked_goomba paragoomba koopa_troopa para_troopa fuzzy bob_omb bullet_bill bill_blaster monty_mole cleft pokey battle_bandit buzzy_beetle swooper stone_chomp putrid_piranha piranha_plant sentinel world_clubba battle_clubba shy_guy groove_guy sky_guy pyro_guy spy_guy medi_guy fuzzipede jungle_guy heart_plant hurt_plant m_bush bubble kent_c_koopa dayzee lakitu spiny bzzap ruff_puff spike_top duplighost albino_dino blooper baby_blooper gulpit dry_bones thrown_bone bony_beetle magikoopa flying_magikoopa world_koopatrol koopatrol hammer_bros bush_basic bush_blocky bush_dry bush_leafy bush_matted world_kammy battle_kammy goomba_bros goomba_king spiky_goomnut dark_toad koopa_bros buzzar tutankoopa chain_chomp world_tubba battle_tubba tubbas_heart big_lantern_ghost shy_squad_guy marshal_guy stilt_guy stilt_guy_unfold shy_stack_guy shy_stack_unfold shy_stack_damage shy_stack_rock general_guy general_guy_bomb tank_guy lava_piranha_head petit_piranha lava_bud huff_n_puff tuff_puff monstar crystal_king world_bowser battle_bowser luigi toad three_sisters vanna_t toad_kid toad_guard harry_t toad_minister postmaster conductor_toad train_station_toad fishmael artist_toad koopa koopa_without_shell world_bob_omb whacka dryite mouser boo yoshi yoshi_kid raven bubulb penguin shiver_toad world_bandit goompa goombaria gooma goompapa goomama the_master chan lee merlon chet_rippo rowf minh_t russ_t tayce_t fice_t bartender chanterelle rip_cheato chuck_quizmo merluvlee merlar merlow star_kid kolorado_wife koopa_koot kolorado battle_kolorado archeologist nomadimouse world_merlee battle_merlee disguised_moustafa moustafa oaklie bootler yakkey gourmet_guy village_leader leaders_friend rafael_raven tolielup gate_flower petunia posie lily rosie sun lakilulu ninji mayor_penguin mayor_penguin_wife penguin_patrol herringway merle star_rod fire coin parade_peach parade_koopas parade_burnt_bowser parade_luigi parade_partners parade_yoshis parade_kolorados parade_chicks parade_ice_show parade_toads parade_batons parade_drums parade_flags parade_horns parade_tubba_balloon parade_wizards parade_mario parade_shy_guys parade_twink leaf".split(" ")
@ -26,6 +28,7 @@ ASSETS = sum([[f"{map_name}_shape", f"{map_name}_hit"] for map_name in MAPS], []
def obj(path: str): def obj(path: str):
if not path.startswith("$builddir/"): if not path.startswith("$builddir/"):
path = "$builddir/" + path path = "$builddir/" + path
path = re.sub(r"/assets/", "/", path)
return path + ".o" return path + ".o"
def read_splat(splat_config: str): def read_splat(splat_config: str):
@ -48,7 +51,10 @@ def read_splat(splat_config: str):
for segment in all_segments: for segment in all_segments:
for subdir, path, obj_type, start in segment.get_ld_files(): for subdir, path, obj_type, start in segment.get_ld_files():
if path.endswith(".c") or path.endswith(".s") or path.endswith(".data") or path.endswith(".rodata"):
path = subdir + "/" + path path = subdir + "/" + path
else:
assert subdir == "assets", subdir + " " + path
objects.add(path) objects.add(path)
segments[path] = segment segments[path] = segment
@ -57,7 +63,7 @@ def read_splat(splat_config: str):
for split_file in segment.files: for split_file in segment.files:
if split_file["subtype"] in ["i4", "i8", "ia4", "ia8", "ia16", "rgba16", "rgba32", "ci4", "ci8", "palette"]: if split_file["subtype"] in ["i4", "i8", "ia4", "ia8", "ia16", "rgba16", "rgba32", "ci4", "ci8", "palette"]:
path = os.path.join( path = os.path.join(
"src", #segment.get_subdir(split_file["subtype"]),
split_file["name"] + "." + segment.get_ext(split_file["subtype"]) split_file["name"] + "." + segment.get_ext(split_file["subtype"])
) )
@ -103,7 +109,7 @@ async def build_c_file(c_file: str, generated_headers, ccache, cppflags):
def build_yay0_file(bin_file: str): def build_yay0_file(bin_file: str):
yay0_file = f"$builddir/{os.path.splitext(bin_file)[0]}.Yay0" yay0_file = f"$builddir/{os.path.splitext(bin_file)[0]}.Yay0"
n.build(yay0_file, "yay0compress", bin_file, implicit="tools/Yay0compress") n.build(yay0_file, "yay0compress", find_asset(bin_file), implicit="tools/Yay0compress")
build_bin_object(yay0_file) build_bin_object(yay0_file)
def build_bin_object(bin_file: str): def build_bin_object(bin_file: str):
@ -120,7 +126,7 @@ def build_image(f: str, segment):
if segment.flip_vertical: if segment.flip_vertical:
flags += "--flip-y" flags += "--flip-y"
n.build(out, "img", path + ".png", implicit="tools/img/build.py", variables={ n.build(out, "img", find_asset(path + ".png"), implicit="tools/img/build.py", variables={
"img_type": img_type, "img_type": img_type,
"img_flags": flags, "img_flags": flags,
}) })
@ -130,6 +136,17 @@ def cmd_exists(cmd):
return subprocess.call("type " + cmd, shell=True, return subprocess.call("type " + cmd, shell=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0 stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0
def find_asset_dir(path):
for d in ASSET_DIRS:
if os.path.exists(d + "/" + path):
return d
print("unable to find asset: " + path)
exit(1)
def find_asset(path):
return find_asset_dir(path) + "/" + path
async def main(): async def main():
global n, cpp, task_sem, num_tasks, num_tasks_done global n, cpp, task_sem, num_tasks, num_tasks_done
@ -194,12 +211,12 @@ async def main():
# generate build.ninja # generate build.ninja
n = ninja_syntax.Writer(open("build.ninja", "w"), width=120) n = ninja_syntax.Writer(open("build.ninja", "w"), width=120)
cppflags = "-Iinclude -Isrc -D _LANGUAGE_C -D _FINALROM -ffreestanding -DF3DEX_GBI_2 -D_MIPS_SZLONG=32 " + args.cflags cppflags = f"-I{BUILD_DIR}/include -Iinclude -Isrc -D _LANGUAGE_C -D _FINALROM -ffreestanding -DF3DEX_GBI_2 -D_MIPS_SZLONG=32 " + args.cflags
cflags = "-O2 -quiet -G 0 -mcpu=vr4300 -mfix4300 -mips3 -mgp32 -mfp32 -Wuninitialized -Wshadow " + args.cflags cflags = "-O2 -quiet -G 0 -mcpu=vr4300 -mfix4300 -mips3 -mgp32 -mfp32 -Wuninitialized -Wshadow " + args.cflags
iconv = "tools/iconv.py UTF-8 SHIFT-JIS" if sys.platform == "darwin" else "iconv --from UTF-8 --to SHIFT-JIS" iconv = "tools/iconv.py UTF-8 SHIFT-JIS" if sys.platform == "darwin" else "iconv --from UTF-8 --to SHIFT-JIS"
cross = "mips-linux-gnu-" cross = "mips-linux-gnu-"
n.variable("builddir", "build") n.variable("builddir", BUILD_DIR)
n.variable("target", TARGET) n.variable("target", TARGET)
n.variable("cross", cross) n.variable("cross", cross)
n.variable("python", sys.executable) n.variable("python", sys.executable)
@ -339,22 +356,26 @@ async def main():
def add_generated_header(h: str): def add_generated_header(h: str):
generated_headers.append(h) generated_headers.append(h)
if not os.path.exists(h): he = re.sub(r"\$builddir", BUILD_DIR, h)
if not os.path.exists(he):
# mkdir -p # mkdir -p
os.makedirs(os.path.dirname(h), exist_ok=True) os.makedirs(os.path.dirname(he), exist_ok=True)
# touch it so cpp doesn't complain if its #included # touch it so cpp doesn't complain if its #included
open(h, "w").close() open(he, "w").close()
# mark it as really old so ninja builds it # mark it as really old so ninja builds it
os.utime(h, (0, 0)) os.utime(he, (0, 0))
return h return h
n.build(add_generated_header("include/ld_addrs.h"), "ld_addrs_h", "$builddir/$target.ld") n.build(add_generated_header("$builddir/include/ld_addrs.h"), "ld_addrs_h", "$builddir/$target.ld")
# messages # messages
msg_files = glob("src/**/*.msg", recursive=True) + glob("msg/**/*.msg", recursive=True) msg_files = []
for d in ASSET_DIRS:
msg_files.extend(glob(d + "/**/*.msg", recursive=True))
for msg_file in msg_files: for msg_file in msg_files:
n.build( n.build(
f"$builddir/{msg_file}.bin", f"$builddir/{msg_file}.bin",
@ -367,7 +388,7 @@ async def main():
"msg_combine", "msg_combine",
[f"$builddir/{msg_file}.bin" for msg_file in msg_files], [f"$builddir/{msg_file}.bin" for msg_file in msg_files],
implicit="tools/msg/combine.py", implicit="tools/msg/combine.py",
implicit_outputs=[add_generated_header(f"{msg_file}.h") for msg_file in msg_files], implicit_outputs=[add_generated_header(f"$builddir/include/{msg_file.split('/', 1)[1]}.h") for msg_file in msg_files],
variables={ "msg_combine_headers": [f"{msg_file}.h" for msg_file in msg_files] } variables={ "msg_combine_headers": [f"{msg_file}.h" for msg_file in msg_files] }
) )
n.build("$builddir/msg.o", "bin", "$builddir/msg.bin") n.build("$builddir/msg.o", "bin", "$builddir/msg.bin")
@ -375,16 +396,17 @@ async def main():
# sprites # sprites
npc_sprite_yay0s = [] npc_sprite_yay0s = []
for sprite_id, sprite_name in enumerate(NPC_SPRITES, 1): for sprite_id, sprite_name in enumerate(NPC_SPRITES, 1):
sources = glob(f"sprite/npc/{sprite_name}/**/*.*", recursive=True) asset_dir = find_asset_dir(f"sprite/npc/{sprite_name}")
sources = glob(f"{asset_dir}/npc/{sprite_name}/**/*.*", recursive=True)
variables = { variables = {
"sprite_name": sprite_name, "sprite_name": sprite_name,
"sprite_dir": f"sprite/npc/{sprite_name}", "sprite_dir": f"{asset_dir}/sprite/npc/{sprite_name}",
"sprite_id": sprite_id, "sprite_id": sprite_id,
} }
# generated header # generated header
n.build( n.build(
add_generated_header(f"include/sprite/npc/{sprite_name}.h"), add_generated_header(f"$builddir/include/sprite/npc/{sprite_name}.h"),
"sprite_animations_h", "sprite_animations_h",
implicit=sources + ["tools/gen_sprite_animations_h.py"], implicit=sources + ["tools/gen_sprite_animations_h.py"],
variables=variables, variables=variables,
@ -418,7 +440,7 @@ async def main():
elif f.endswith(".Yay0"): elif f.endswith(".Yay0"):
build_yay0_file(os.path.splitext(f)[0] + ".bin") build_yay0_file(os.path.splitext(f)[0] + ".bin")
elif f.endswith(".bin"): elif f.endswith(".bin"):
build_bin_object(f) build_bin_object(find_asset(f))
elif f.endswith(".data"): elif f.endswith(".data"):
n.build(obj(f), "as", "asm/" + f + ".s") n.build(obj(f), "as", "asm/" + f + ".s")
elif f.endswith(".rodata"): elif f.endswith(".rodata"):
@ -429,13 +451,15 @@ async def main():
if isinstance(segment, dict): if isinstance(segment, dict):
# image within a code section # image within a code section
out = "$builddir/" + f + ".bin" out = "$builddir/" + f + ".bin"
n.build(out, "img", re.sub(r"\.pal\.png", ".png", f), implicit="tools/img/build.py", variables={ infile = find_asset(re.sub(r"\.pal\.png", ".png", f))
n.build(out, "img", infile, implicit="tools/img/build.py", variables={
"img_type": segment["subtype"], "img_type": segment["subtype"],
"img_flags": "", "img_flags": "",
}) })
if ".pal.png" not in f: if ".pal.png" not in f:
n.build(add_generated_header(f + ".h"), "img_header", f, implicit="tools/img/header.py") n.build(add_generated_header("$builddir/include/" + f + ".h"), "img_header", infile, implicit="tools/img/header.py")
n.build("$builddir/" + f + ".o", "bin", out) n.build("$builddir/" + f + ".o", "bin", out)
else: else:
@ -444,17 +468,17 @@ async def main():
# combine sprites # combine sprites
n.build(f"$builddir/{f}.bin", "npc_sprites", npc_sprite_yay0s, implicit="tools/compile_npc_sprites.py") n.build(f"$builddir/{f}.bin", "npc_sprites", npc_sprite_yay0s, implicit="tools/compile_npc_sprites.py")
n.build(obj(f), "bin", f"$builddir/{f}.bin") n.build(obj(f), "bin", f"$builddir/{f}.bin")
elif f == "/msg": # XXX: why does this have a leading '/'?? elif segment.type == "PaperMarioMessages":
continue # done already above continue # done already above
elif f == "bin/assets/assets": elif segment.type == "PaperMarioMapFS":
asset_files = [] # even indexes: uncompressed; odd indexes: compressed asset_files = [] # even indexes: uncompressed; odd indexes: compressed
for asset_name in ASSETS: for asset_name in ASSETS:
if asset_name.endswith("_tex"): # uncompressed if asset_name.endswith("_tex"): # uncompressed
asset_files.append(f"bin/assets/{asset_name}.bin") asset_files.append(find_asset(f"{asset_name}.bin"))
asset_files.append(f"bin/assets/{asset_name}.bin") asset_files.append(find_asset(f"{asset_name}.bin"))
else: # uncompressed else: # uncompressed
source_file = f"bin/assets/{asset_name}.bin" source_file = find_asset(f"{asset_name}.bin")
asset_file = f"$builddir/assets/{asset_name}.Yay0" asset_file = f"$builddir/assets/{asset_name}.Yay0"
asset_files.append(source_file) asset_files.append(source_file)
@ -463,7 +487,6 @@ async def main():
n.build("$builddir/assets.bin", "assets", asset_files) n.build("$builddir/assets.bin", "assets", asset_files)
n.build(obj(f), "bin", "$builddir/assets.bin") n.build(obj(f), "bin", "$builddir/assets.bin")
else: else:
print("warning: dont know what to do with object " + f) print("warning: dont know what to do with object " + f)
n.newline() n.newline()

View File

@ -5,7 +5,7 @@ from pathlib import Path
import os import os
path.append(os.path.join(os.path.dirname(__file__), "splat")) path.append(os.path.join(os.path.dirname(__file__), "splat"))
from splat_ext.PaperMarioNpcSprites import Sprite from splat_ext.PaperMarioNpcSprites import Sprite
from convert_image import pack_color, iter_in_groups from img.build import pack_color, iter_in_groups
if __name__ == "__main__": if __name__ == "__main__":
if len(argv) != 3: if len(argv) != 3:

View File

@ -9,6 +9,7 @@ options:
extensions: splat_ext extensions: splat_ext
symbol_addrs_path: tools/symbol_addrs.txt symbol_addrs_path: tools/symbol_addrs.txt
platform: n64 platform: n64
assets_dir: assets
segments: segments:
- name: header - name: header
type: header type: header

View File

@ -4,7 +4,7 @@ from util.n64 import Yay0decompress
class N64SegYay0(N64Segment): class N64SegYay0(N64Segment):
def split(self, rom_bytes, base_path): def split(self, rom_bytes, base_path):
out_dir = self.create_parent_dir(base_path + "/bin", self.name) out_dir = self.create_parent_dir(base_path + "/" + self.options.get("assets_dir", "bin"), self.name)
path = os.path.join(out_dir, os.path.basename(self.name) + ".bin") path = os.path.join(out_dir, os.path.basename(self.name) + ".bin")
with open(path, "wb") as f: with open(path, "wb") as f:
@ -16,7 +16,7 @@ class N64SegYay0(N64Segment):
def get_ld_files(self): def get_ld_files(self):
return [("bin", f"{self.name}.Yay0", ".data", self.rom_start)] return [(self.options.get("assets_dir", "bin"), f"{self.name}.Yay0", ".data", self.rom_start)]
@staticmethod @staticmethod

View File

@ -5,7 +5,7 @@ from pathlib import Path
class N64SegBin(N64Segment): class N64SegBin(N64Segment):
def split(self, rom_bytes, base_path): def split(self, rom_bytes, base_path):
out_dir = self.create_split_dir(base_path, "bin") out_dir = self.create_split_dir(base_path, self.options.get("assets_dir", "bin"))
bin_path = os.path.join(out_dir, self.name + ".bin") bin_path = os.path.join(out_dir, self.name + ".bin")
Path(bin_path).parent.mkdir(parents=True, exist_ok=True) Path(bin_path).parent.mkdir(parents=True, exist_ok=True)
@ -14,7 +14,7 @@ class N64SegBin(N64Segment):
self.log(f"Wrote {self.name} to {bin_path}") self.log(f"Wrote {self.name} to {bin_path}")
def get_ld_files(self): def get_ld_files(self):
return [("bin", f"{self.name}.bin", ".data", self.rom_start)] return [(self.options.get("assets_dir", "bin"), f"{self.name}.bin", ".data", self.rom_start)]
@staticmethod @staticmethod
def get_default_name(addr): def get_default_name(addr):

View File

@ -11,7 +11,7 @@ class N64SegCi8(N64SegRgba16):
self.path = None self.path = None
def split(self, rom_bytes, base_path): def split(self, rom_bytes, base_path):
out_dir = self.create_parent_dir(base_path + "/img", self.name) out_dir = self.create_parent_dir(base_path + "/" + self.options.get("assets_dir", "img"), self.name)
self.path = os.path.join(out_dir, os.path.basename(self.name) + ".png") self.path = os.path.join(out_dir, os.path.basename(self.name) + ".png")
data = rom_bytes[self.rom_start: self.rom_end] data = rom_bytes[self.rom_start: self.rom_end]

View File

@ -738,7 +738,7 @@ class N64SegCode(N64Segment):
if file_type == "c": if file_type == "c":
c_path = os.path.join( c_path = os.path.join(
base_path, base_path,
"src", self.get_subdir(split_file["subtype"]),
split_file["name"] + "." + self.get_ext(split_file["subtype"]) split_file["name"] + "." + self.get_ext(split_file["subtype"])
) )
@ -813,10 +813,12 @@ class N64SegCode(N64Segment):
f.write(file_text) f.write(file_text)
elif file_type == "bin" and ("bin" in self.options["modes"] or "all" in self.options["modes"]): elif file_type == "bin" and ("bin" in self.options["modes"] or "all" in self.options["modes"]):
out_dir = self.create_split_dir(base_path, "bin")
bin_path = os.path.join( bin_path = os.path.join(
out_dir, split_file["name"] + "." + self.get_ext(split_file["subtype"])) base_path,
self.get_subdir(split_file["subtype"]),
split_file["name"] + "." + self.get_ext(split_file["subtype"])
)
Path(bin_path).parent.mkdir(parents=True, exist_ok=True) Path(bin_path).parent.mkdir(parents=True, exist_ok=True)
with open(bin_path, "wb") as f: with open(bin_path, "wb") as f:
f.write(rom_bytes[split_file["start"]: split_file["end"]]) f.write(rom_bytes[split_file["start"]: split_file["end"]])
@ -829,7 +831,7 @@ class N64SegCode(N64Segment):
out_path = os.path.join( out_path = os.path.join(
base_path, base_path,
"src", self.get_subdir(split_file["subtype"]),
split_file["name"] + "." + self.get_ext(split_file["subtype"]) split_file["name"] + "." + self.get_ext(split_file["subtype"])
) )
img_bytes = rom_bytes[split_file["start"]:split_file["end"]] img_bytes = rom_bytes[split_file["start"]:split_file["end"]]
@ -845,7 +847,7 @@ class N64SegCode(N64Segment):
out_path = os.path.join( out_path = os.path.join(
base_path, base_path,
"src", self.get_subdir(split_file["subtype"]),
split_file["name"] + "." + self.get_ext(split_file["subtype"]) split_file["name"] + "." + self.get_ext(split_file["subtype"])
) )
@ -857,6 +859,8 @@ class N64SegCode(N64Segment):
image = N64SegCi4.parse_image(img_bytes, width, height) image = N64SegCi4.parse_image(img_bytes, width, height)
w = png.Writer(width, height, palette=palette) w = png.Writer(width, height, palette=palette)
Path(out_path).parent.mkdir(parents=True, exist_ok=True)
with open(out_path, "wb") as f: with open(out_path, "wb") as f:
w.write_array(f, image) w.write_array(f, image)
@ -864,12 +868,15 @@ class N64SegCode(N64Segment):
# TODO write orphaned palettes # TODO write orphaned palettes
@staticmethod def get_subdir(self, subtype):
def get_subdir(subtype): if subtype in ["c", ".data", ".rodata", ".bss"]:
if subtype in ["c", ".data", ".rodata", ".bss", "i4", "i8", "ia4", "ia8", "ia16", "rgba16", "rgba32", "ci4", "ci8", "palette"]:
return "src" return "src"
elif subtype in ["asm", "hasm", "header"]: elif subtype in ["asm", "hasm", "header"]:
return "asm" return "asm"
elif subtype == "bin":
return self.options.get("assets_dir", "bin")
elif subtype in ["i4", "i8", "ia4", "ia8", "ia16", "rgba16", "rgba32", "ci4", "ci8", "palette"]:
return self.options.get("assets_dir", "img")
return subtype return subtype
@staticmethod @staticmethod

View File

@ -33,7 +33,7 @@ class N64SegPalette(N64Segment):
) )
def split(self, rom_bytes, base_path): def split(self, rom_bytes, base_path):
out_dir = self.create_parent_dir(base_path + "/img", self.name) out_dir = self.create_parent_dir(base_path + "/" + self.options.get("assets_dir", "img"), self.name)
self.path = os.path.join( self.path = os.path.join(
out_dir, os.path.basename(self.name) + ".png") out_dir, os.path.basename(self.name) + ".png")
@ -62,4 +62,4 @@ class N64SegPalette(N64Segment):
if self.compressed: if self.compressed:
ext += ".Yay0" ext += ".Yay0"
return [("img", f"{self.name}{ext}", ".data", self.rom_start)] return [(self.options.get("assets_dir", "img"), f"{self.name}{ext}", ".data", self.rom_start)]

View File

@ -48,7 +48,7 @@ class N64SegRgba16(N64Segment):
return super().should_run() or "img" in self.options["modes"] return super().should_run() or "img" in self.options["modes"]
def split(self, rom_bytes, base_path): def split(self, rom_bytes, base_path):
out_dir = self.create_parent_dir(base_path + "/img", self.name) out_dir = self.create_parent_dir(base_path + "/" + self.options.get("assets_dir", "img"), self.name)
path = os.path.join(out_dir, os.path.basename(self.name) + ".png") path = os.path.join(out_dir, os.path.basename(self.name) + ".png")
data = rom_bytes[self.rom_start: self.rom_end] data = rom_bytes[self.rom_start: self.rom_end]
@ -82,4 +82,4 @@ class N64SegRgba16(N64Segment):
if self.compressed: if self.compressed:
ext += ".Yay0" ext += ".Yay0"
return [("img", f"{self.name}{ext}", ".data", self.rom_start)] return [(self.options.get("assets_dir", "img"), f"{self.name}{ext}", ".data", self.rom_start)]

View File

@ -142,7 +142,11 @@ class Segment:
path_cname = re.sub(r"[^0-9a-zA-Z_]", "_", path) path_cname = re.sub(r"[^0-9a-zA-Z_]", "_", path)
s += f" {path_cname} = .;\n" s += f" {path_cname} = .;\n"
if subdir == self.options.get("assets_dir"):
path = PurePath(path)
else:
path = PurePath(subdir) / PurePath(path) path = PurePath(subdir) / PurePath(path)
path = path.with_suffix(".o" if replace_ext else path.suffix + ".o") path = path.with_suffix(".o" if replace_ext else path.suffix + ".o")
s += f" BUILD_DIR/{path}({obj_type});\n" s += f" BUILD_DIR/{path}({obj_type});\n"

View File

@ -19,7 +19,7 @@ class N64SegPaperMarioMapFS(N64Segment):
super().__init__(segment, next_segment, options) super().__init__(segment, next_segment, options)
def split(self, rom_bytes, base_path): def split(self, rom_bytes, base_path):
bin_dir = self.create_split_dir(base_path, "bin/assets") bin_dir = self.create_split_dir(base_path, self.options.get("assets_dir", "bin"))
data = rom_bytes[self.rom_start: self.rom_end] data = rom_bytes[self.rom_start: self.rom_end]
@ -59,7 +59,7 @@ class N64SegPaperMarioMapFS(N64Segment):
def get_ld_files(self): def get_ld_files(self):
return [("bin/assets", self.name, ".data", self.rom_start)] return [(self.options.get("assets_dir", "bin"), self.name, ".data", self.rom_start)]
@staticmethod @staticmethod

View File

@ -367,7 +367,7 @@ class N64SegPaperMarioMessages(N64Segment):
self.log(f"Reading {len(msg_offsets)} messages in section {name} (0x{i:02X})") self.log(f"Reading {len(msg_offsets)} messages in section {name} (0x{i:02X})")
path = Path(base_path, self.name, name + ".msg") path = Path(base_path, self.options["assets_dir"], self.name, name + ".msg")
path.parent.mkdir(parents=True, exist_ok=True) path.parent.mkdir(parents=True, exist_ok=True)
with open(path, "w") as self.f: with open(path, "w") as self.f:
for j, msg_offset in enumerate(msg_offsets): for j, msg_offset in enumerate(msg_offsets):
@ -378,7 +378,7 @@ class N64SegPaperMarioMessages(N64Segment):
self.f.write("\n[/message]\n") self.f.write("\n[/message]\n")
def get_ld_files(self): def get_ld_files(self):
return [("", self.name, ".data", self.rom_start)] return [(self.options["assets_dir"], self.name, ".data", self.rom_start)]
@staticmethod @staticmethod
def get_default_name(addr): def get_default_name(addr):

View File

@ -259,7 +259,7 @@ class N64SegPaperMarioNpcSprites(N64Segment):
self.files = DEFAULT_SPRITE_NAMES self.files = DEFAULT_SPRITE_NAMES
def split(self, rom_bytes, base_path): def split(self, rom_bytes, base_path):
out_dir = self.create_split_dir(base_path, "sprite/" + self.name) out_dir = self.create_split_dir(base_path, self.options["assets_dir"] + "/sprite/" + self.name)
data = rom_bytes[self.rom_start:self.rom_end] data = rom_bytes[self.rom_start:self.rom_end]
pos = 0 pos = 0
@ -294,7 +294,7 @@ class N64SegPaperMarioNpcSprites(N64Segment):
sprite.write_to_dir(sprite_dir) sprite.write_to_dir(sprite_dir)
def get_ld_files(self): def get_ld_files(self):
return [("sprite", self.name, ".data", self.rom_start)] return [(self.options["assets_dir"], "sprite/" + self.name, ".data", self.rom_start)]
@staticmethod @staticmethod
def get_default_name(addr): def get_default_name(addr):