papermario/tools/splat_ext/pm_map_data.py
Ethan Roseman 73af4eb5a0
Tables & Chairs (sorry no chairs actually) (#800)
* git subrepo pull --force tools/splat

subrepo:
  subdir:   "tools/splat"
  merged:   "ec7bd4868e"
upstream:
  origin:   "https://github.com/ethteck/splat.git"
  branch:   "master"
  commit:   "ec7bd4868e"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"

* wips

* more

* wipperz

* it workz

* mdl_make_local_vertex_copy

* sleep_bubble finished + gfx

* fire_breath gfx

* func_800F0490

* func_800EFE2C

* 8a860 funcs

* cleanup + dead cod

* dead clean

* git subrepo pull --force tools/splat

subrepo:
  subdir:   "tools/splat"
  merged:   "a1730f38ad"
upstream:
  origin:   "https://github.com/ethteck/splat.git"
  branch:   "master"
  commit:   "a1730f38ad"
git-subrepo:
  version:  "0.4.5"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "aa416e4"

* cleanup + splat prep

* git subrepo pull --force tools/splat

subrepo:
  subdir:   "tools/splat"
  merged:   "4e5fca24a5"
upstream:
  origin:   "https://github.com/ethteck/splat.git"
  branch:   "master"
  commit:   "4e5fca24a5"
git-subrepo:
  version:  "0.4.5"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "aa416e4"

* bits

* clean

* bss c -> asm

* btl_update_starpoints_display

* is_debug + cleanup

* load_script / 190B20 data

* all the symz

* clean

* cleanup + stuff
2022-10-04 23:09:23 +09:00

206 lines
6.6 KiB
Python

import os
from pathlib import Path
from segtypes.n64.segment import N64Segment
from segtypes.n64.ia8 import N64SegIa8
from segtypes.n64.rgba32 import N64SegRgba32
from segtypes.n64.ci4 import N64SegCi4
from util.n64 import Yay0decompress
from util.color import unpack_color
from segtypes.n64.palette import iter_in_groups
from util import options
import png
import yaml as yaml_loader
import n64img.image
script_dir = Path(os.path.dirname(os.path.realpath(__file__)))
def decode_null_terminated_ascii(data):
length = 0
for byte in data:
if byte == 0:
break
length += 1
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
def add_file_ext(name: str) -> str:
if name.startswith("party_"):
return name + ".png"
elif name.endswith("_hit") or name.endswith("_shape"):
return name + ".bin" # TODO: xml
elif name.endswith("_tex"):
return name + ".bin" # TODO: texture archive
elif name.endswith("_bg"):
return name + ".png"
else:
return name + ".bin"
class N64SegPm_map_data(N64Segment):
def __init__(
self,
rom_start,
rom_end,
type,
name,
vram_start,
args,
yaml,
):
super().__init__(
rom_start,
rom_end,
type,
name,
vram_start,
args=args,
yaml=yaml,
)
with open(script_dir / "map_data.yaml") as f:
self.files = yaml_loader.load(f.read(), Loader=yaml_loader.SafeLoader)
def split(self, rom_bytes):
fs_dir = options.opts.asset_path / self.dir / self.name
(fs_dir / "title").mkdir(parents=True, exist_ok=True)
data = rom_bytes[self.rom_start : self.rom_end]
asset_idx = 0
while True:
asset_data = data[0x20 + asset_idx * 0x1C :]
name = decode_null_terminated_ascii(asset_data[0:])
offset = int.from_bytes(asset_data[0x10:0x14], byteorder="big")
size = int.from_bytes(asset_data[0x14:0x18], byteorder="big")
decompressed_size = int.from_bytes(asset_data[0x18:0x1C], byteorder="big")
is_compressed = size != decompressed_size
if offset == 0:
path = None
else:
path = fs_dir / add_file_ext(name)
if name == "end_data":
break
bytes_start = self.rom_start + 0x20 + offset
bytes = rom_bytes[bytes_start : bytes_start + size]
if is_compressed:
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 == "title_data":
if "ver/us" in str(options.opts.target_path):
w = 200
h = 112
img = n64img.image.RGBA32(
data=bytes[0x2210 : 0x2210 + w * h * 4], width=w, height=h
)
img.write(fs_dir / "title/logotype.png")
w = 144
h = 32
img = n64img.image.IA8(
data=bytes[0x10 : 0x10 + w * h], width=w, height=h
)
img.write(fs_dir / "title/copyright.png")
w = 128
h = 32
img = n64img.image.IA8(
data=bytes[0x1210 : 0x1210 + w * h], width=w, height=h
)
img.write(fs_dir / "title/press_start.png")
else:
w = 272
h = 88
img = n64img.image.RGBA32(
data=bytes[0x1830 : 0x1830 + w * h * 4], width=w, height=h
)
img.write(fs_dir / "title/logotype.png")
w = 128
h = 32
img = n64img.image.CI4(
data=bytes[0x10 : 0x10 + w * h], width=w, height=h
)
img.palette = parse_palette(bytes[0x810:0x830])
img.write(fs_dir / "title/copyright.png")
w = 128
h = 32
img = n64img.image.IA8(
data=bytes[0x830 : 0x830 + w * h], width=w, height=h
)
img.write(fs_dir / "title/press_start.png")
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, fs_dir / f"{name}.alt.png", header_offset=0x10)
else:
with open(path, "wb") as f:
f.write(bytes)
asset_idx += 1
def get_linker_entries(self):
from segtypes.linker_entry import LinkerEntry
fs_dir = options.opts.asset_path / self.dir / self.name
return [
LinkerEntry(
self,
[fs_dir / add_file_ext(name) for name in self.files],
fs_dir.with_suffix(".dat"),
".data",
),
]