mirror of
https://github.com/pmret/papermario.git
synced 2024-11-08 12:02:30 +01:00
a
This commit is contained in:
parent
1f8f92e276
commit
592ffd4e48
1
.gitignore
vendored
1
.gitignore
vendored
@ -10,6 +10,7 @@ venv/
|
|||||||
ctx.c
|
ctx.c
|
||||||
expected/
|
expected/
|
||||||
.vscode/launch.json
|
.vscode/launch.json
|
||||||
|
/tools/star-rod
|
||||||
|
|
||||||
# Build artifacts
|
# Build artifacts
|
||||||
build.ninja
|
build.ninja
|
||||||
|
44
configure.py
44
configure.py
@ -129,7 +129,7 @@ def build_image(f: str, segment):
|
|||||||
out = "$builddir/" + path + "." + img_type + ".png"
|
out = "$builddir/" + path + "." + img_type + ".png"
|
||||||
|
|
||||||
flags = ""
|
flags = ""
|
||||||
if img_type != "palette":
|
if img_type != "palette" and not isinstance(segment, dict):
|
||||||
if segment.flip_horizontal:
|
if segment.flip_horizontal:
|
||||||
flags += "--flip-x"
|
flags += "--flip-x"
|
||||||
if segment.flip_vertical:
|
if segment.flip_vertical:
|
||||||
@ -150,7 +150,10 @@ def find_asset_dir(path):
|
|||||||
if os.path.exists(d + "/" + path):
|
if os.path.exists(d + "/" + path):
|
||||||
return d
|
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)
|
exit(1)
|
||||||
|
|
||||||
def find_asset(path):
|
def find_asset(path):
|
||||||
@ -484,9 +487,40 @@ async def main():
|
|||||||
|
|
||||||
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(find_asset(f"{asset_name}.bin"))
|
asset_files.append(find_asset(f"map/{asset_name}.bin"))
|
||||||
asset_files.append(find_asset(f"{asset_name}.bin"))
|
asset_files.append(find_asset(f"map/{asset_name}.bin"))
|
||||||
else: # uncompressed
|
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")
|
||||||
|
elif asset_name.endswith("_shape") or asset_name.endswith("_hit"):
|
||||||
|
source_file = find_asset(f"map/{asset_name}.bin")
|
||||||
|
asset_file = f"$builddir/assets/{asset_name}.Yay0"
|
||||||
|
|
||||||
|
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")
|
source_file = find_asset(f"{asset_name}.bin")
|
||||||
asset_file = f"$builddir/assets/{asset_name}.Yay0"
|
asset_file = f"$builddir/assets/{asset_name}.Yay0"
|
||||||
|
|
||||||
|
@ -1418,8 +1418,8 @@ typedef struct TileDescriptor {
|
|||||||
} TileDescriptor; // size = 0x30
|
} TileDescriptor; // size = 0x30
|
||||||
|
|
||||||
typedef struct BackgroundHeader {
|
typedef struct BackgroundHeader {
|
||||||
/* 0x00 */ UNK_PTR raster;
|
/* 0x00 */ void* raster;
|
||||||
/* 0x04 */ UNK_PTR palette;
|
/* 0x04 */ void* palette;
|
||||||
/* 0x08 */ u16 startX;
|
/* 0x08 */ u16 startX;
|
||||||
/* 0x0A */ u16 startY;
|
/* 0x0A */ u16 startY;
|
||||||
/* 0x0C */ u16 width;
|
/* 0x0C */ u16 width;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
from sys import argv, stderr
|
from sys import argv, stderr
|
||||||
from math import floor, ceil
|
from math import floor, ceil
|
||||||
from itertools import zip_longest
|
from itertools import zip_longest
|
||||||
|
from glob import glob
|
||||||
import png
|
import png
|
||||||
|
|
||||||
def unpack_color(s):
|
def unpack_color(s):
|
||||||
@ -181,6 +182,67 @@ class Converter():
|
|||||||
|
|
||||||
i = rgb_to_intensity(*rgba[:3])
|
i = rgb_to_intensity(*rgba[:3])
|
||||||
f.write(i.to_bytes(1, byteorder="big"))
|
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:
|
else:
|
||||||
print("unsupported mode", file=stderr)
|
print("unsupported mode", file=stderr)
|
||||||
exit(1)
|
exit(1)
|
||||||
|
@ -2,6 +2,9 @@ import os
|
|||||||
from segtypes.n64.segment import N64Segment
|
from segtypes.n64.segment import N64Segment
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from util.n64 import Yay0decompress
|
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):
|
def decode_null_terminated_ascii(data):
|
||||||
@ -14,12 +17,22 @@ def decode_null_terminated_ascii(data):
|
|||||||
return data[:length].decode('ascii')
|
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):
|
class N64SegPaperMarioMapFS(N64Segment):
|
||||||
def __init__(self, segment, next_segment, options):
|
def __init__(self, segment, next_segment, options):
|
||||||
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, self.options.get("assets_dir", "bin"))
|
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]
|
data = rom_bytes[self.rom_start: self.rom_end]
|
||||||
|
|
||||||
@ -37,23 +50,62 @@ class N64SegPaperMarioMapFS(N64Segment):
|
|||||||
|
|
||||||
if offset == 0:
|
if offset == 0:
|
||||||
path = None
|
path = None
|
||||||
|
elif name.startswith("party_"):
|
||||||
|
path = os.path.join(img_party_dir, "{}.png".format(name))
|
||||||
|
elif name.endswith("_hit") or name.endswith("_shape"):
|
||||||
|
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("_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:
|
else:
|
||||||
path = "{}.bin".format(name)
|
path = os.path.join(bin_dir, "{}.bin".format(name))
|
||||||
self.create_parent_dir(bin_dir, path)
|
|
||||||
|
|
||||||
if name == "end_data":
|
if name == "end_data":
|
||||||
break
|
break
|
||||||
|
|
||||||
with open(os.path.join(bin_dir, path), "wb") as f:
|
bytes = rom_bytes[self.rom_start + 0x20 +
|
||||||
bytes = rom_bytes[self.rom_start + 0x20 +
|
offset: self.rom_start + 0x20 + offset + size]
|
||||||
offset: self.rom_start + 0x20 + offset + size]
|
|
||||||
|
|
||||||
if is_compressed:
|
Path(path).parent.mkdir(parents=True, exist_ok=True)
|
||||||
self.log(f"Decompressing {name}...")
|
|
||||||
bytes = Yay0decompress.decompress_yay0(bytes)
|
|
||||||
|
|
||||||
f.write(bytes)
|
if is_compressed:
|
||||||
self.log(f"Wrote {name} to {Path(bin_dir, path)}")
|
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
|
asset_idx += 1
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user