mirror of
https://github.com/pmret/papermario.git
synced 2024-11-08 20:12:30 +01:00
Merge branch 'master' into star-rod-0-4-0
This commit is contained in:
commit
69e9f6e3ba
1
.gitignore
vendored
1
.gitignore
vendored
@ -10,6 +10,7 @@ venv/
|
||||
ctx.c
|
||||
expected/
|
||||
.vscode/launch.json
|
||||
/tools/star-rod
|
||||
|
||||
# Build artifacts
|
||||
build.ninja
|
||||
|
42
configure.py
42
configure.py
@ -23,7 +23,10 @@ NPC_SPRITES = "world_goombario world_kooper world_bombette world_parakarry world
|
||||
|
||||
MAPS = "dro_01 dro_02 hos_00 hos_01 hos_02 hos_03 hos_04 hos_05 hos_06 hos_10 hos_20 isk_01 isk_02 isk_03 isk_04 isk_05 isk_06 isk_07 isk_08 isk_09 isk_10 isk_11 isk_12 isk_13 isk_14 isk_16 isk_18 isk_19 iwa_00 iwa_01 iwa_02 iwa_03 iwa_04 iwa_10 iwa_11 osr_00 osr_01 osr_02 osr_03 kkj_00 kkj_01 kkj_02 kkj_03 kkj_10 kkj_11 kkj_12 kkj_13 kkj_14 kkj_15 kkj_16 kkj_17 kkj_18 kkj_19 kkj_20 kkj_21 kkj_22 kkj_23 kkj_24 kkj_25 kkj_26 kkj_27 kkj_28 kkj_29 kmr_00 kmr_02 kmr_03 kmr_04 kmr_05 kmr_06 kmr_07 kmr_09 kmr_10 kmr_11 kmr_12 kmr_20 kmr_30 kpa_01 kpa_03 kpa_04 kpa_08 kpa_09 kpa_10 kpa_11 kpa_12 kpa_13 kpa_14 kpa_15 kpa_16 kpa_17 kpa_32 kpa_33 kpa_40 kpa_41 kpa_50 kpa_52 kpa_60 kpa_61 kpa_62 kpa_63 kpa_70 kpa_80 kpa_90 kpa_91 kpa_94 kpa_95 kpa_96 kpa_102 kpa_111 kpa_112 kpa_113 kpa_115 kpa_116 kpa_117 kpa_118 kpa_119 kpa_121 kpa_130 kpa_133 kpa_134 machi mac_00 mac_01 mac_02 mac_03 mac_04 mac_05 mac_06 tik_01 tik_02 tik_03 tik_04 tik_05 tik_06 tik_07 tik_08 tik_09 tik_10 tik_12 tik_14 tik_15 tik_17 tik_18 tik_19 tik_20 tik_21 tik_22 tik_23 tik_25 kgr_01 kgr_02 nok_01 nok_02 nok_03 nok_04 nok_11 nok_12 nok_13 nok_14 nok_15 sbk_00 sbk_01 sbk_02 sbk_03 sbk_04 sbk_05 sbk_06 sbk_10 sbk_11 sbk_12 sbk_13 sbk_14 sbk_15 sbk_16 sbk_20 sbk_21 sbk_22 sbk_23 sbk_24 sbk_25 sbk_26 sbk_30 sbk_31 sbk_32 sbk_33 sbk_34 sbk_35 sbk_36 sbk_40 sbk_41 sbk_42 sbk_43 sbk_44 sbk_45 sbk_46 sbk_50 sbk_51 sbk_52 sbk_53 sbk_54 sbk_55 sbk_56 sbk_60 sbk_61 sbk_62 sbk_63 sbk_64 sbk_65 sbk_66 sbk_99 trd_00 trd_01 trd_02 trd_03 trd_04 trd_05 trd_06 trd_07 trd_08 trd_09 trd_10 tst_01 tst_02 tst_03 tst_04 tst_10 tst_11 tst_12 tst_13 tst_20 jan_00 jan_01 jan_02 jan_03 jan_04 jan_05 jan_06 jan_07 jan_08 jan_09 jan_10 jan_11 jan_12 jan_13 jan_14 jan_15 jan_16 jan_17 jan_18 jan_19 jan_22 jan_23 mim_01 mim_02 mim_03 mim_04 mim_05 mim_06 mim_07 mim_08 mim_09 mim_10 mim_11 mim_12 obk_01 obk_02 obk_03 obk_04 obk_05 obk_06 obk_07 obk_08 obk_09 arn_02 arn_03 arn_04 arn_05 arn_07 arn_08 arn_09 arn_10 arn_11 arn_12 arn_13 arn_20 dgb_01 dgb_02 dgb_03 dgb_04 dgb_05 dgb_06 dgb_07 dgb_08 dgb_09 dgb_10 dgb_11 dgb_12 dgb_13 dgb_14 dgb_15 dgb_16 dgb_17 dgb_18 kzn_01 kzn_02 kzn_03 kzn_04 kzn_05 kzn_06 kzn_07 kzn_08 kzn_09 kzn_10 kzn_11 kzn_17 kzn_18 kzn_19 kzn_20 kzn_22 kzn_23 flo_00 flo_03 flo_07 flo_08 flo_09 flo_10 flo_11 flo_12 flo_13 flo_14 flo_15 flo_16 flo_17 flo_18 flo_19 flo_21 flo_22 flo_23 flo_24 flo_25 sam_01 sam_02 sam_03 sam_04 sam_05 sam_06 sam_07 sam_08 sam_09 sam_10 sam_11 sam_12 pra_01 pra_02 pra_03 pra_04 pra_05 pra_09 pra_10 pra_11 pra_13 pra_14 pra_15 pra_16 pra_18 pra_19 pra_20 pra_21 pra_22 pra_29 pra_31 pra_32 pra_33 pra_34 pra_35 pra_40 omo_01 omo_02 omo_03 omo_04 omo_05 omo_06 omo_07 omo_08 omo_09 omo_10 omo_11 omo_12 omo_13 omo_14 omo_15 omo_16 omo_17 end_00 end_01 mgm_00 mgm_01 mgm_02 mgm_03 gv_01 kmr_bt03 kmr_bt04 kmr_bt05 kmr_bt06 nok_bt01 nok_bt02 nok_bt03 nok_bt04 trd_bt00 trd_bt01 trd_bt02 trd_bt03 trd_bt04 trd_bt05 iwa_bt01 iwa_bt02 sbk_bt02 isk_bt01 isk_bt02 isk_bt03 isk_bt04 isk_bt05 isk_bt06 isk_bt07 isk_bt08 arn_bt01 arn_bt02 arn_bt03 arn_bt04 arn_bt05 arn_bt06 dgb_bt01 dgb_bt02 dgb_bt03 dgb_bt04 dgb_bt05 mim_bt01 omo_bt01 omo_bt02 omo_bt03 omo_bt04 omo_bt05 omo_bt06 omo_bt07 kgr_bt01 flo_bt01 flo_bt02 flo_bt03 flo_bt04 flo_bt05 flo_bt06 jan_bt00 jan_bt01 jan_bt02 jan_bt03 jan_bt04 kzn_bt01 kzn_bt02 kzn_bt04 kzn_bt05 sam_bt01 sam_bt02 sam_bt03 sam_bt04 tik_bt01 tik_bt02 tik_bt03 tik_bt04 tik_bt05 pra_bt01 pra_bt02 pra_bt03 pra_bt04 mac_bt01 mac_bt02 kpa_bt01 kpa_bt02 kpa_bt03 kpa_bt04 kpa_bt05 kpa_bt07 kpa_bt08 kpa_bt09 kpa_bt11 kpa_bt13 kpa_bt14 hos_bt01 hos_bt02 kkj_bt01 kkj_bt02".split(" ")
|
||||
|
||||
ASSETS = sum([[f"{map_name}_shape", f"{map_name}_hit"] for map_name in MAPS], []) + "mac_tex tik_tex kgr_tex kmr_tex iwa_tex sbk_tex dro_tex isk_tex trd_tex nok_tex hos_tex kpa_tex osr_tex kkj_tex tst_tex jan_tex mim_tex obk_tex arn_tex dgb_tex kzn_tex flo_tex sam_tex pra_tex omo_tex end_tex mgm_tex gv__tex kmr_bg nok_bg sbk_bg sbk3_bg iwa_bg hos_bg arn_bg obk_bg omo_bg yos_bg jan_bg fla_bg flb_bg sra_bg yki_bg sam_bg kpa_bg title_bg title_data party_kurio party_kameki party_pinki party_pareta party_resa party_akari party_opuku party_pokopi".split(" ")
|
||||
def area_of_map(map_name: str) -> str:
|
||||
return "area_" + map_name.split("_")[0][0:3]
|
||||
|
||||
ASSETS = sum([[f"map/{area_of_map(map_name)}/{map_name}_shape", f"map/{area_of_map(map_name)}/{map_name}_hit"] for map_name in MAPS], []) + "mac_tex tik_tex kgr_tex kmr_tex iwa_tex sbk_tex dro_tex isk_tex trd_tex nok_tex hos_tex kpa_tex osr_tex kkj_tex tst_tex jan_tex mim_tex obk_tex arn_tex dgb_tex kzn_tex flo_tex sam_tex pra_tex omo_tex end_tex mgm_tex gv__tex kmr_bg nok_bg sbk_bg sbk3_bg iwa_bg hos_bg arn_bg obk_bg omo_bg yos_bg jan_bg fla_bg flb_bg sra_bg yki_bg sam_bg kpa_bg title_bg title_data party_kurio party_kameki party_pinki party_pareta party_resa party_akari party_opuku party_pokopi".split(" ")
|
||||
|
||||
def obj(path: str):
|
||||
if not path.startswith("$builddir/"):
|
||||
@ -120,7 +123,7 @@ def build_image(f: str, segment):
|
||||
out = "$builddir/" + path + "." + img_type + ".png"
|
||||
|
||||
flags = ""
|
||||
if img_type != "palette":
|
||||
if img_type != "palette" and not isinstance(segment, dict):
|
||||
if segment.flip_horizontal:
|
||||
flags += "--flip-x"
|
||||
if segment.flip_vertical:
|
||||
@ -141,7 +144,10 @@ def find_asset_dir(path):
|
||||
if os.path.exists(d + "/" + path):
|
||||
return d
|
||||
|
||||
print("unable to find asset: " + path)
|
||||
print("Unable to find asset: " + path)
|
||||
print("The asset dump may be incomplete. Run")
|
||||
print(" rm .splat_cache")
|
||||
print("And then run ./configure.py again.")
|
||||
exit(1)
|
||||
|
||||
def find_asset(path):
|
||||
@ -475,9 +481,33 @@ async def main():
|
||||
|
||||
for asset_name in ASSETS:
|
||||
if asset_name.endswith("_tex"): # uncompressed
|
||||
asset_files.append(find_asset(f"{asset_name}.bin"))
|
||||
asset_files.append(find_asset(f"{asset_name}.bin"))
|
||||
else: # uncompressed
|
||||
asset_files.append(find_asset(f"map/{asset_name}.bin"))
|
||||
asset_files.append(find_asset(f"map/{asset_name}.bin"))
|
||||
elif asset_name.startswith("party_"):
|
||||
source_file = f"$builddir/{asset_name}.bin"
|
||||
asset_file = f"$builddir/{asset_name}.Yay0"
|
||||
|
||||
n.build(source_file, "img", find_asset(f"party/{asset_name}.png"), implicit="tools/img/build.py", variables={
|
||||
"img_type": "party",
|
||||
"img_flags": "",
|
||||
})
|
||||
|
||||
asset_files.append(source_file)
|
||||
asset_files.append(asset_file)
|
||||
n.build(asset_file, "yay0compress", source_file, implicit="tools/Yay0compress")
|
||||
elif asset_name.endswith("_bg"):
|
||||
source_file = f"$builddir/{asset_name}.bin"
|
||||
asset_file = f"$builddir/{asset_name}.Yay0"
|
||||
|
||||
n.build(source_file, "img", find_asset(f"map/{asset_name}.png"), implicit="tools/img/build.py", variables={
|
||||
"img_type": "bg",
|
||||
"img_flags": "",
|
||||
})
|
||||
|
||||
asset_files.append(source_file)
|
||||
asset_files.append(asset_file)
|
||||
n.build(asset_file, "yay0compress", source_file, implicit="tools/Yay0compress")
|
||||
else:
|
||||
source_file = find_asset(f"{asset_name}.bin")
|
||||
asset_file = f"$builddir/assets/{asset_name}.Yay0"
|
||||
|
||||
|
@ -1418,8 +1418,8 @@ typedef struct TileDescriptor {
|
||||
} TileDescriptor; // size = 0x30
|
||||
|
||||
typedef struct BackgroundHeader {
|
||||
/* 0x00 */ UNK_PTR raster;
|
||||
/* 0x04 */ UNK_PTR palette;
|
||||
/* 0x00 */ void* raster;
|
||||
/* 0x04 */ void* palette;
|
||||
/* 0x08 */ u16 startX;
|
||||
/* 0x0A */ u16 startY;
|
||||
/* 0x0C */ u16 width;
|
||||
|
@ -3,6 +3,7 @@
|
||||
from sys import argv, stderr
|
||||
from math import floor, ceil
|
||||
from itertools import zip_longest
|
||||
from glob import glob
|
||||
import png
|
||||
|
||||
def unpack_color(s):
|
||||
@ -181,6 +182,67 @@ class Converter():
|
||||
|
||||
i = rgb_to_intensity(*rgba[:3])
|
||||
f.write(i.to_bytes(1, byteorder="big"))
|
||||
elif self.mode == "party":
|
||||
data = img.read()[2]
|
||||
img.preamble(True)
|
||||
palette = img.palette(alpha="force")
|
||||
|
||||
with open(self.outfile, "wb") as f:
|
||||
# palette
|
||||
for rgba in palette:
|
||||
if rgba[3] not in (0, 0xFF):
|
||||
self.warn("alpha mask mode but translucent pixels used")
|
||||
|
||||
color = pack_color(*rgba)
|
||||
f.write(color.to_bytes(2, byteorder="big"))
|
||||
|
||||
assert f.tell() == 0x200, "palette has wrong size"
|
||||
|
||||
# ci 8
|
||||
for row in reversed_if(data, self.flip_y):
|
||||
f.write(row)
|
||||
|
||||
f.write(b"\0\0\0\0\0\0\0\0\0\0") # padding
|
||||
elif self.mode == "bg":
|
||||
width, height, data, info = img.read()
|
||||
img.preamble(True)
|
||||
palettes = [img.palette(alpha="force")]
|
||||
|
||||
for palettepath in glob(self.infile.split(".")[0] + ".*.png"):
|
||||
pal = png.Reader(palettepath)
|
||||
pal.preamble(True)
|
||||
palettes.append(pal.palette(alpha="force"))
|
||||
|
||||
with open(self.outfile, "wb") as f:
|
||||
baseaddr = 0x80200000 # gBackgroundImage
|
||||
headers_len = 0x10 * len(palettes)
|
||||
palettes_len = 0x200 * len(palettes)
|
||||
|
||||
# header (struct BackgroundHeader)
|
||||
for i, palette in enumerate(palettes):
|
||||
f.write((baseaddr + palettes_len + headers_len).to_bytes(4, byteorder="big")) # raster offset
|
||||
f.write((baseaddr + headers_len + 0x200 * i).to_bytes(4, byteorder="big")) # palette offset
|
||||
f.write((12).to_bytes(2, byteorder="big")) # startX
|
||||
f.write((20).to_bytes(2, byteorder="big")) # startY
|
||||
f.write((width).to_bytes(2, byteorder="big")) # width
|
||||
f.write((height).to_bytes(2, byteorder="big")) # height
|
||||
|
||||
assert f.tell() == headers_len
|
||||
|
||||
for palette in palettes:
|
||||
# palette
|
||||
for rgba in palette:
|
||||
if rgba[3] not in (0, 0xFF):
|
||||
self.warn("alpha mask mode but translucent pixels used")
|
||||
|
||||
color = pack_color(*rgba)
|
||||
f.write(color.to_bytes(2, byteorder="big"))
|
||||
|
||||
assert f.tell() == palettes_len + headers_len
|
||||
|
||||
# ci 8
|
||||
for row in reversed_if(data, self.flip_y):
|
||||
f.write(row)
|
||||
else:
|
||||
print("unsupported mode", file=stderr)
|
||||
exit(1)
|
||||
|
@ -2,6 +2,9 @@ import os
|
||||
from segtypes.n64.segment import N64Segment
|
||||
from pathlib import Path
|
||||
from util.n64 import Yay0decompress
|
||||
from util.color import unpack_color
|
||||
from util.iter import iter_in_groups
|
||||
import png
|
||||
|
||||
|
||||
def decode_null_terminated_ascii(data):
|
||||
@ -14,12 +17,22 @@ def decode_null_terminated_ascii(data):
|
||||
return data[:length].decode('ascii')
|
||||
|
||||
|
||||
def parse_palette(data):
|
||||
palette = []
|
||||
|
||||
for a, b in iter_in_groups(data, 2):
|
||||
palette.append(unpack_color([a, b]))
|
||||
|
||||
return palette
|
||||
|
||||
|
||||
class N64SegPaperMarioMapFS(N64Segment):
|
||||
def __init__(self, segment, next_segment, options):
|
||||
super().__init__(segment, next_segment, options)
|
||||
|
||||
def split(self, rom_bytes, base_path):
|
||||
bin_dir = self.create_split_dir(base_path, self.options.get("assets_dir", "bin"))
|
||||
img_party_dir = self.create_split_dir(base_path, self.options.get("assets_dir", "img") + "/party")
|
||||
|
||||
data = rom_bytes[self.rom_start: self.rom_end]
|
||||
|
||||
@ -37,23 +50,64 @@ class N64SegPaperMarioMapFS(N64Segment):
|
||||
|
||||
if offset == 0:
|
||||
path = None
|
||||
elif name.startswith("party_"):
|
||||
path = os.path.join(img_party_dir, "{}.png".format(name))
|
||||
elif name.endswith("_hit") or name.endswith("_shape"):
|
||||
area = "area_" + name.split("_")[0][0:3]
|
||||
map_dir = self.create_split_dir(base_path, self.options.get("assets_dir", "bin") + f"/map/{area}")
|
||||
|
||||
path = os.path.join(map_dir, "{}.bin".format(name))
|
||||
elif name.endswith("_tex"):
|
||||
map_dir = self.create_split_dir(base_path, self.options.get("assets_dir", "bin") + f"/map")
|
||||
path = os.path.join(map_dir, "{}.bin".format(name))
|
||||
elif name.endswith("_bg"):
|
||||
map_dir = self.create_split_dir(base_path, self.options.get("assets_dir", "bin") + f"/map")
|
||||
path = os.path.join(map_dir, "{}.png".format(name))
|
||||
else:
|
||||
path = "{}.bin".format(name)
|
||||
self.create_parent_dir(bin_dir, path)
|
||||
path = os.path.join(bin_dir, "{}.bin".format(name))
|
||||
|
||||
if name == "end_data":
|
||||
break
|
||||
|
||||
with open(os.path.join(bin_dir, path), "wb") as f:
|
||||
bytes = rom_bytes[self.rom_start + 0x20 +
|
||||
offset: self.rom_start + 0x20 + offset + size]
|
||||
bytes = rom_bytes[self.rom_start + 0x20 +
|
||||
offset: self.rom_start + 0x20 + offset + size]
|
||||
|
||||
if is_compressed:
|
||||
self.log(f"Decompressing {name}...")
|
||||
bytes = Yay0decompress.decompress_yay0(bytes)
|
||||
Path(path).parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
f.write(bytes)
|
||||
self.log(f"Wrote {name} to {Path(bin_dir, path)}")
|
||||
if is_compressed:
|
||||
self.log(f"Decompressing {name}...")
|
||||
bytes = Yay0decompress.decompress_yay0(bytes)
|
||||
|
||||
if name.startswith("party_"):
|
||||
with open(path, "wb") as f:
|
||||
# CI-8
|
||||
w = png.Writer(150, 105, palette=parse_palette(bytes[:0x200]))
|
||||
w.write_array(f, bytes[0x200:])
|
||||
elif name.endswith("_bg"):
|
||||
def write_bg_png(bytes, path, header_offset=0):
|
||||
header = bytes[header_offset:header_offset+0x10]
|
||||
|
||||
raster_offset = int.from_bytes(header[0:4], byteorder="big") - 0x80200000
|
||||
palette_offset = int.from_bytes(header[4:8], byteorder="big") - 0x80200000
|
||||
assert int.from_bytes(header[8:12], byteorder="big") == 0x000C0014 # draw pos
|
||||
width = int.from_bytes(header[12:14], byteorder="big")
|
||||
height = int.from_bytes(header[14:16], byteorder="big")
|
||||
|
||||
with open(path, "wb") as f:
|
||||
# CI-8
|
||||
w = png.Writer(width, height, palette=parse_palette(bytes[palette_offset:palette_offset+512]))
|
||||
w.write_array(f, bytes[raster_offset:])
|
||||
|
||||
write_bg_png(bytes, path)
|
||||
|
||||
# sbk_bg has an alternative palette
|
||||
if name == "sbk_bg":
|
||||
write_bg_png(bytes, path.split(".")[0] + ".alt.png", header_offset=0x10)
|
||||
else:
|
||||
with open(path, "wb") as f:
|
||||
f.write(bytes)
|
||||
|
||||
self.log(f"Wrote {name} to {Path(bin_dir, path)}")
|
||||
|
||||
asset_idx += 1
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user