more work done
This commit is contained in:
parent
5cc5612f4e
commit
d323bb28fc
68 changed files with 714 additions and 19 deletions
134
scripts/_tmp_psx_mode1_live_row0_batch.py
Normal file
134
scripts/_tmp_psx_mode1_live_row0_batch.py
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import struct
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(r"k:/ghidra/Crusader_Decomp")
|
||||
L0_WDL_PATH = Path(r"e:/emu/psx/Crusader - No Remorse/LSET1/L0.WDL")
|
||||
GPU_PATH = ROOT / "binary/Crusader - No Remorse (USA) GPU RAM.bin"
|
||||
OUTPUT_DIR = ROOT / "out/psx_wdl/L0/mode1_live_clut_row_f0_x0"
|
||||
ROW_BYTES = 2048
|
||||
LIVE_CLUT_Y = 0xF0
|
||||
LIVE_CLUT_X = 0
|
||||
|
||||
sys.path.insert(0, str(ROOT / "tools"))
|
||||
|
||||
from psx_extract_wdl import (
|
||||
colorize_indexed_pixels,
|
||||
parse_lset_wdl,
|
||||
scan_sprite_bundles,
|
||||
write_bundle_atlas,
|
||||
write_overview_grid,
|
||||
write_png_rgba,
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
l0_data = L0_WDL_PATH.read_bytes()
|
||||
gpu = GPU_PATH.read_bytes()
|
||||
summary = parse_lset_wdl(l0_data)
|
||||
if summary is None:
|
||||
raise SystemExit("failed to parse L0.WDL")
|
||||
|
||||
region = next(region for region in summary["regions"] if region["name"] == "post_audio_region_04")
|
||||
region_data = l0_data[region["offset"] : region["offset"] + region["size"]]
|
||||
bundles = scan_sprite_bundles(region_data, max_candidates=160)
|
||||
|
||||
row = gpu[LIVE_CLUT_Y * ROW_BYTES : (LIVE_CLUT_Y + 1) * ROW_BYTES]
|
||||
row_words = struct.unpack("<1024H", row)
|
||||
palette = list(row_words[LIVE_CLUT_X : LIVE_CLUT_X + 256])
|
||||
|
||||
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
entries: list[dict[str, object]] = []
|
||||
summary_rows: list[dict[str, object]] = []
|
||||
mode1_count = 0
|
||||
|
||||
for bundle in bundles:
|
||||
if bundle["mode"] != 1 or not bundle["frames"]:
|
||||
continue
|
||||
mode1_count += 1
|
||||
bundle_dir = OUTPUT_DIR / f"bundle_{bundle['offset']:08X}"
|
||||
bundle_dir.mkdir(parents=True, exist_ok=True)
|
||||
rendered_frames: list[dict[str, object]] = []
|
||||
frame_rows: list[dict[str, object]] = []
|
||||
for frame in bundle["frames"]:
|
||||
rgba = colorize_indexed_pixels(frame["pixels"], frame["width"], frame["height"], bundle["mode"], palette)
|
||||
write_png_rgba(bundle_dir / f"frame_{frame['index']:03d}_live_row_f0_x0.png", rgba, frame["width"], frame["height"])
|
||||
rendered_frames.append(
|
||||
{
|
||||
"width": frame["width"],
|
||||
"height": frame["height"],
|
||||
"rgba": rgba,
|
||||
}
|
||||
)
|
||||
frame_rows.append(
|
||||
{
|
||||
"index": frame["index"],
|
||||
"width": frame["width"],
|
||||
"height": frame["height"],
|
||||
"origin_x": frame["origin_x"],
|
||||
"origin_y": frame["origin_y"],
|
||||
"data_start": frame["data_start"],
|
||||
"consumed": frame["consumed"],
|
||||
}
|
||||
)
|
||||
write_bundle_atlas(bundle_dir / "atlas_live_row_f0_x0.png", rendered_frames)
|
||||
metadata = {
|
||||
"offset": bundle["offset"],
|
||||
"mode": bundle["mode"],
|
||||
"palette_formula": "live_gpu_row_0xF0_x0_contiguous_256",
|
||||
"palette_source": {
|
||||
"gpu_dump": str(GPU_PATH),
|
||||
"x": LIVE_CLUT_X,
|
||||
"y": LIVE_CLUT_Y,
|
||||
},
|
||||
"frame_count": bundle["frame_count"],
|
||||
"exported_frames": frame_rows,
|
||||
}
|
||||
(bundle_dir / "palette_formula.json").write_text(json.dumps(metadata, indent=2), encoding="ascii")
|
||||
first_frame = bundle["frames"][0]
|
||||
first_rgba = rendered_frames[0]["rgba"]
|
||||
entries.append(
|
||||
{
|
||||
"width": first_frame["width"],
|
||||
"height": first_frame["height"],
|
||||
"rgba": first_rgba,
|
||||
"offset": bundle["offset"],
|
||||
"area": first_frame["width"] * first_frame["height"],
|
||||
}
|
||||
)
|
||||
summary_rows.append(
|
||||
{
|
||||
"offset": bundle["offset"],
|
||||
"width": first_frame["width"],
|
||||
"height": first_frame["height"],
|
||||
"frame_count": bundle["frame_count"],
|
||||
}
|
||||
)
|
||||
|
||||
entries.sort(key=lambda entry: entry["area"], reverse=True)
|
||||
overview_entries = [{"width": entry["width"], "height": entry["height"], "rgba": entry["rgba"]} for entry in entries]
|
||||
write_overview_grid(OUTPUT_DIR / "overview_live_row_f0_x0.png", overview_entries, columns=4)
|
||||
summary_rows.sort(key=lambda row: row["width"] * row["height"], reverse=True)
|
||||
(OUTPUT_DIR / "summary.json").write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"palette_formula": "live_gpu_row_0xF0_x0_contiguous_256",
|
||||
"mode1_bundle_count": mode1_count,
|
||||
"bundles": summary_rows,
|
||||
},
|
||||
indent=2,
|
||||
),
|
||||
encoding="ascii",
|
||||
)
|
||||
|
||||
print(f"mode1_bundles={mode1_count}")
|
||||
print(f"overview={OUTPUT_DIR / 'overview_live_row_f0_x0.png'}")
|
||||
print(f"summary={OUTPUT_DIR / 'summary.json'}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue