From 5a447796d67190c6f8325175451861154e79be37 Mon Sep 17 00:00:00 2001 From: Luciano Ciccariello Date: Thu, 31 Oct 2024 21:06:06 +0000 Subject: [PATCH] Asset handler for palette definition in the header (#1852) Automates the extraction of `u_long** OVL_EXPORT(cluts)[]` in `assets/` at extraction time and its code generation in `src/[boss|st]/palette_def.h`. This has the advantage that now palettes can be loaded and modified externally, change in size and external tools has now context on the palette order and where in the VRAM they are located. This also simplifies `header.c`, getting rid of the whole `PAL_BULK` section. Creating headers for stages and boss rooms will get progressively simpler. The tool is pickier on the size of exported palettes. This allowed me to find gaps of data for potential unused palette data. I marked them in the NZ0 YAML. If there are no concerns and I get an approval, I will extend `config/assets.us.yaml` to the remaining overlays. --- config/assets.hd.yaml | 4 +- config/assets.us.yaml | 21 +- config/splat.hd.stcen.yaml | 7 + config/splat.hd.stwrp.yaml | 3 +- config/splat.us.bomar.yaml | 5 + config/splat.us.borbo3.yaml | 4 + config/splat.us.stcen.yaml | 10 +- config/splat.us.stdre.yaml | 9 + config/splat.us.stno3.yaml | 29 +++ config/splat.us.stnp3.yaml | 28 +++ config/splat.us.stnz0.yaml | 40 ++-- config/splat.us.strwrp.yaml | 3 +- config/splat.us.stst0.yaml | 14 +- config/splat.us.stwrp.yaml | 3 +- src/boss/.gitignore | 1 + src/boss/mar/header.c | 15 +- src/st/.gitignore | 1 + src/st/cen/header.c | 13 +- src/st/dre/header.c | 22 +- src/st/no3/header.c | 63 +----- src/st/np3/header.c | 50 +---- src/st/nz0/header.c | 47 +--- src/st/rwrp/header.c | 14 +- src/st/st0/header.c | 25 +-- src/st/wrp/header.c | 10 +- tools/sotn-assets/asset_config.go | 6 +- tools/sotn-assets/assets/assets.go | 1 + tools/sotn-assets/assets/cutscene/handler.go | 10 +- tools/sotn-assets/assets/layer/handler.go | 26 +-- tools/sotn-assets/assets/layout/handler.go | 12 +- .../sotn-assets/assets/paldef/palette_def.go | 201 ++++++++++++++++++ tools/sotn-assets/assets/rooms/handler.go | 14 +- .../sotn-assets/assets/spritebanks/handler.go | 26 +-- tools/sotn-assets/assets/spriteset/handler.go | 18 +- tools/sotn-assets/info.go | 6 +- tools/sotn-assets/info_test.go | 7 +- tools/sotn-assets/util/utils.go | 26 +++ tools/splat_ext/pal.py | 24 +++ 38 files changed, 437 insertions(+), 381 deletions(-) create mode 100644 tools/sotn-assets/assets/paldef/palette_def.go create mode 100644 tools/splat_ext/pal.py diff --git a/config/assets.hd.yaml b/config/assets.hd.yaml index 9a6d31afc..f46c34922 100644 --- a/config/assets.hd.yaml +++ b/config/assets.hd.yaml @@ -7,7 +7,7 @@ files: vram: 0x80180000 assets: - [0x40, sprite_banks, sprite_banks] - - [0xA0, skip] + - [0xA0, paldef, palette_def] - [0xDC, layers, layers] - [0x134, skip] - [0x1EC, layout, entity_layouts] @@ -22,7 +22,7 @@ files: vram: 0x80180000 assets: - [0x40, sprite_banks, sprite_banks] - - [0xA0, skip] + - [0xA0, paldef, palette_def] - [0xB8, layers, layers] - [0x1B8, skip] - [0x23C, layout, entity_layouts] diff --git a/config/assets.us.yaml b/config/assets.us.yaml index b8c5587d5..cb28ef2b8 100644 --- a/config/assets.us.yaml +++ b/config/assets.us.yaml @@ -7,7 +7,7 @@ files: vram: 0x80180000 assets: - [0x40, sprite_banks, sprite_banks] - - [0xA0, skip] + - [0xA0, paldef, palette_def] - [0xDC, layers, layers] - [0x134, skip] - [0x1EC, layout, entity_layouts] @@ -24,7 +24,7 @@ files: vram: 0x80180000 assets: - [0x40, sprite_banks, sprite_banks] - - [0xA0, skip] + - [0xA0, paldef, palette_def] - [0xE8, layers, layers] - [0x128, skip] - [0x220, layout, entity_layouts] @@ -53,7 +53,7 @@ files: vram: 0x80180000 assets: - [0x2C, sprite_banks, sprite_banks] - - [0x8C, skip] + - [0x8C, paldef, palette_def] - [0x1C4, layers, layers] - [0x5A4, skip] - [0x77C, layout, entity_layouts] @@ -70,7 +70,7 @@ files: vram: 0x80180000 assets: - [0x2C, sprite_banks, sprite_banks] - - [0x8C, skip] + - [0x8C, paldef, palette_def] - [0x1D0, layers, layers] - [0x558, skip] - [0x728, layout, entity_layouts] @@ -85,7 +85,7 @@ files: vram: 0x80180000 assets: - [0x2C, sprite_banks, sprite_banks] - - [0x8C, skip] + - [0x8C, paldef, palette_def] - [0x164, layers, layers] - [0x47C, skip] - [0x8EC, layout, entity_layouts] @@ -102,7 +102,7 @@ files: vram: 0x80180000 assets: - [0x40, sprite_banks, sprite_banks] - - [0xA0, skip] + - [0xA0, paldef, palette_def] - [0x124, layers, layers] - [0x1A4, skip] - [0x314, layout, entity_layouts] @@ -119,7 +119,7 @@ files: vram: 0x80180000 assets: - [0x40, sprite_banks, sprite_banks] - - [0xA0, skip] + - [0xA0, paldef, palette_def] - [0xB8, layers, layers] - [0x1B8, skip] - [0x23C, layout, entity_layouts] @@ -134,7 +134,7 @@ files: vram: 0x80180000 assets: - [0x40, sprite_banks, sprite_banks] - - [0xA0, skip] + - [0xA0, paldef, palette_def] - [0xB8, layers, layers] - [0x1B8, skip] - [0x23C, layout, entity_layouts] @@ -149,7 +149,8 @@ files: vram: 0x80180000 assets: - [0x2C, sprite_banks, sprite_banks] - - [0x8C, skip] + - [0x8C, paldef, palette_def] + - [0xBC, skip] - [0xCC, layers, layers] - [0xF4, skip] - [0x168, layout, entity_layouts] @@ -167,6 +168,8 @@ files: assets: - [0x2C, sprite_banks, sprite_banks] - [0x8C, skip] + - [0xAC, paldef, palette_def] + - [0xD0, skip] - [0xE0, layers, layers] - [0x108, skip] - [0x1EC, layout, entity_layouts] diff --git a/config/splat.hd.stcen.yaml b/config/splat.hd.stcen.yaml index 314a17d11..577554b67 100644 --- a/config/splat.hd.stcen.yaml +++ b/config/splat.hd.stcen.yaml @@ -18,6 +18,7 @@ options: use_legacy_include_asm: false migrate_rodata_to_functions: true asm_jtbl_label_macro: jlabel + extensions_path: tools/splat_ext symbol_name_format: hd_$VRAM section_order: - .data @@ -57,6 +58,12 @@ segments: - [0x1308, .data, rooms] - [0x1334, .data, e_layout] - [0x1424, data] + - [0x65AC, pal, D_801865AC] + - [0x66AC, pal, D_801866AC] # unused + - [0x67AC, pal, D_801867AC] + - [0x68AC, pal, D_801868AC] # unused + - [0x69AC, pal, D_801869AC] + - [0x69CC, pal, D_801869CC] - [0x6A0C, .data, tile_data] - [0xC62C, .data, sprites] - [0xD434, .rodata, cutscene] diff --git a/config/splat.hd.stwrp.yaml b/config/splat.hd.stwrp.yaml index 72755a929..801e11b22 100644 --- a/config/splat.hd.stwrp.yaml +++ b/config/splat.hd.stwrp.yaml @@ -56,7 +56,8 @@ segments: - [0x122C, .data, e_layout] # layout entries data - [0x1424, cmp, D_80181420] - [0x1768, cmp, D_80181764] - - [0x1D0C, raw, D_80181D08] + - [0x1D0C, pal, D_80181D0C] + - [0x1D2C, pal, D_80181D2C] # unused - [0x1D6C, .data, tile_data] # tile data - [0x296C, .data, tile_data] # tile definitions - [0x6D8C, .data, sprites] diff --git a/config/splat.us.bomar.yaml b/config/splat.us.bomar.yaml index 2a6770795..2652ad5fa 100644 --- a/config/splat.us.bomar.yaml +++ b/config/splat.us.bomar.yaml @@ -67,6 +67,11 @@ segments: - [0x15F0, raw, cutscene_alucard] - [0x2370, raw, cutscene_maria] - [0x30F0, data] + - [0x4EE0, pal, D_80184EE0] + - [0x4FE0, pal, D_80184FE0] # unused + - [0x50E0, pal, D_801850E0] + - [0x51E0, pal, D_801851E0] # unused + - [0x52E0, pal, D_801852E0] - [0x5300, .data, tile_data] # tile data - [0x5700, .data, tile_data] # tile definitions - [0x9710, .data, sprites] diff --git a/config/splat.us.borbo3.yaml b/config/splat.us.borbo3.yaml index 01d346736..7eeb7a483 100644 --- a/config/splat.us.borbo3.yaml +++ b/config/splat.us.borbo3.yaml @@ -18,6 +18,7 @@ options: use_legacy_include_asm: false migrate_rodata_to_functions: true asm_jtbl_label_macro: jlabel + extensions_path: tools/splat_ext symbol_name_format: us_$VRAM disassemble_all: True section_order: @@ -53,6 +54,9 @@ segments: - [0x1044, data, e_misc] - [0x1160, .data, e_particles] - [0x11E0, data] + - [0x7350, pal, D_80187350] + - [0x7550, pal, D_80187550] # unused + - [0x7610, pal, D_80187610] - [0x10E80, .rodata, rbo3] - [0x10F0C, .rodata, 12D64] - [0x10F3C, .rodata, e_red_door] diff --git a/config/splat.us.stcen.yaml b/config/splat.us.stcen.yaml index 4d9851a77..fede5dfee 100644 --- a/config/splat.us.stcen.yaml +++ b/config/splat.us.stcen.yaml @@ -64,10 +64,12 @@ segments: - [0x3A40, cmp, D_80183A40] - [0x4B70, cmp, D_80184B70] - [0x5830, cmp, D_80185830] - - [0x658C, raw, D_8018658C] - - [0x678C, raw, D_8018678C] - - [0x698C, raw, D_8018698C] - - [0x69AC, raw, D_801869AC] + - [0x658C, pal, D_8018658C] + - [0x668C, pal, D_8018668C] # unused + - [0x678C, pal, D_8018678C] + - [0x688C, pal, D_8018688C] # unused + - [0x698C, pal, D_8018698C] + - [0x69AC, pal, D_801869AC] - [0x69EC, .data, tile_data] # tile data - [0x81EC, .data, tile_data] # tile definitions - [0xC60C, .data, sprites] diff --git a/config/splat.us.stdre.yaml b/config/splat.us.stdre.yaml index efb80937e..06d03edec 100644 --- a/config/splat.us.stdre.yaml +++ b/config/splat.us.stdre.yaml @@ -68,6 +68,15 @@ segments: - [0x8D8C, raw, cutscene_mother] - [0x9B0C, raw, cutscene_succubus] - [0xA88C, data] + - [0xABE8, pal, D_8018ABE8] + - [0xADE8, pal, D_8018ADE8] # unused + - [0xAEA8, pal, D_8018AEA8] + - [0xAF48, pal, D_8018AF48] + - [0xB048, pal, D_8018B048] # unused + - [0xB148, pal, D_8018B148] + - [0xB248, pal, D_8018B248] # unused + - [0xB348, pal, D_8018B348] + - [0xB448, pal, D_8018B448] # unused - [0xB548, .data, tile_data] # tile data - [0xBD48, .data, tile_data] # tile definitions - [0x10168, .data, sprites] diff --git a/config/splat.us.stno3.yaml b/config/splat.us.stno3.yaml index 3ac206d9c..9b302f2b3 100644 --- a/config/splat.us.stno3.yaml +++ b/config/splat.us.stno3.yaml @@ -76,6 +76,35 @@ segments: - [0x11B88, raw, cutscene_alucard] - [0x12908, raw, cutscene_death] - [0x13688, data] + - [0x166B8, pal, D_801966B8] + - [0x17838, pal, D_80197838] + - [0x178F8, pal, D_801978F8] # unused + - [0x17918, pal, D_80197918] + - [0x17958, pal, D_80197958] + - [0x17998, pal, D_80197998] + - [0x179D8, pal, D_801979D8] + - [0x17A18, pal, D_80197A18] + - [0x17A58, pal, D_80197A58] + - [0x17A98, pal, D_80197A98] + - [0x17AD8, pal, D_80197AD8] + - [0x17B18, pal, D_80197B18] + - [0x17B58, pal, D_80197B58] + - [0x17B98, pal, D_80197B98] + - [0x17BD8, pal, D_80197BD8] + - [0x17C18, pal, D_80197C18] + - [0x17C58, pal, D_80197C58] + - [0x17C98, pal, D_80197C98] + - [0x17EF8, pal, D_80197EF8] + - [0x17F58, pal, D_80197F58] + - [0x17FB8, pal, D_80197FB8] + - [0x180B8, pal, D_801980B8] + - [0x18118, pal, D_80198118] + - [0x18218, pal, D_80198218] # unused + - [0x18318, pal, D_80198318] + - [0x18418, pal, D_80198418] # unused + - [0x18518, pal, D_80198518] + - [0x18578, pal, D_80198578] + - [0x18778, pal, D_80198778] # unused - [0x18838, .data, tile_data] # tile data - [0x26638, .data, tile_data] # tile definitions - [0x2EA68, .data, sprites] diff --git a/config/splat.us.stnp3.yaml b/config/splat.us.stnp3.yaml index da396c42f..4c0f6d8ce 100644 --- a/config/splat.us.stnp3.yaml +++ b/config/splat.us.stnp3.yaml @@ -76,6 +76,34 @@ segments: - [0x3A7C, .data, rooms] - [0x3B68, .data, e_layout] # layout entries data - [0x49E0, data] + - [0x14914, pal, D_80194914] + - [0x15A94, pal, D_80195A94] + - [0x15B54, pal, D_80195B54] # unused + - [0x15B74, pal, D_80195B74] + - [0x15BB4, pal, D_80195BB4] + - [0x15BF4, pal, D_80195BF4] + - [0x15C34, pal, D_80195C34] + - [0x15C74, pal, D_80195C74] + - [0x15CB4, pal, D_80195CB4] + - [0x15CF4, pal, D_80195CF4] + - [0x15D34, pal, D_80195D34] + - [0x15D74, pal, D_80195D74] + - [0x15DB4, pal, D_80195DB4] + - [0x15DF4, pal, D_80195DF4] + - [0x15E34, pal, D_80195E34] + - [0x15E74, pal, D_80195E74] + - [0x15EB4, pal, D_80195EB4] + - [0x15EF4, pal, D_80195EF4] + - [0x16154, pal, D_80196154] + - [0x161B4, pal, D_801961B4] + - [0x16214, pal, D_80196214] + - [0x16274, pal, D_80196274] + - [0x162D4, pal, D_801962D4] + - [0x163B4, pal, D_801963B4] + - [0x165B4, pal, D_801965B4] # unused + - [0x16674, pal, D_80196674] # overlaps with D_801966D4 + - [0x166D4, pal, D_801966D4] + - [0x167D4, pal, D_801967D4] - [0x168F4, .data, tile_data] # tile data - [0x21CF4, .data, tile_data] # tile definitions - [0x2A124, .data, sprites] diff --git a/config/splat.us.stnz0.yaml b/config/splat.us.stnz0.yaml index 438da831f..14da608ea 100644 --- a/config/splat.us.stnz0.yaml +++ b/config/splat.us.stnz0.yaml @@ -95,23 +95,29 @@ segments: - [0x13BA4, raw, cutscene_maria] - [0x14924, raw, cutscene_alucard] - [0x156A4, cmp, D_801956A4] - - [0x15C3C, raw, D_80195C3C] - - [0x15CDC, raw, D_80195CDC] - - [0x15D3C, raw, D_80195D3C] - - [0x15DBC, raw, D_80195DBC] - - [0x15E1C, raw, D_80195E1C] - - [0x15E3C, raw, D_80195E3C] - - [0x15E9C, raw, D_80195E9C] - - [0x15F1C, raw, D_80195F1C] - - [0x15F9C, raw, D_80195F9C] - - [0x1601C, raw, D_8019601C] - - [0x162DC, raw, D_801962DC] - - [0x1641C, raw, D_8019641C] - - [0x1647C, raw, D_8019647C] - - [0x1657C, raw, D_8019657C] - - [0x1663C, raw, D_8019663C] - - [0x1665C, raw, D_8019665C] - - [0x1685C, raw, D_8019685C] + - [0x15C3C, pal, D_80195C3C] + - [0x15CBC, pal, D_80195CBC] # unused + - [0x15CDC, pal, D_80195CDC] + - [0x15CFC, pal, D_80195CFC] # unused + - [0x15D3C, pal, D_80195D3C] + - [0x15DBC, pal, D_80195DBC] + - [0x15E1C, pal, D_80195E1C] + - [0x15E3C, pal, D_80195E3C] + - [0x15E9C, pal, D_80195E9C] + - [0x15F1C, pal, D_80195F1C] + - [0x15F9C, pal, D_80195F9C] + - [0x1601C, pal, D_8019601C] + - [0x1621C, pal, D_8019621C] # unused + - [0x162DC, pal, D_801962DC] + - [0x1641C, pal, D_8019641C] + - [0x1647C, pal, D_8019647C] + - [0x1657C, pal, D_8019657C] + - [0x1661C, pal, D_8019661C] # unused + - [0x1663C, pal, D_8019663C] + - [0x1665C, pal, D_8019665C] + - [0x1675C, pal, D_8019675C] # unused + - [0x1685C, pal, D_8019685C] + - [0x1695C, pal, D_8019695C] # unused - [0x16A5C, .data, tile_data] # tile data - [0x20A5C, .data, tile_data] # tile definitions - [0x26E8C, .data, sprites] diff --git a/config/splat.us.strwrp.yaml b/config/splat.us.strwrp.yaml index 97d287f29..caf9ea857 100644 --- a/config/splat.us.strwrp.yaml +++ b/config/splat.us.strwrp.yaml @@ -56,7 +56,8 @@ segments: - [0x1228, .data, rwrp/e_layout] # layout entries data - [0x1420, cmp, D_80181420] - [0x1764, cmp, D_80181764] - - [0x1D08, raw, D_80181D08] + - [0x1D08, pal, D_80181D08] + - [0x1F08, pal, D_80181F08] # unused - [0x1FC8, .data, rwrp/tile_data] # tile data - [0x2BC8, .data, rwrp/tile_data] # tile definitions - [0x6FE8, .data, rwrp/sprites] diff --git a/config/splat.us.stst0.yaml b/config/splat.us.stst0.yaml index 85db39fd3..c038d9ea8 100644 --- a/config/splat.us.stst0.yaml +++ b/config/splat.us.stst0.yaml @@ -66,7 +66,19 @@ segments: #- [0x17F80, cmp] - [0x187BC, data] #- [0x1A40C, cmp] - - [0x1A750, data] + - [0x1A750, pal, D_8019A750] + - [0x1A830, pal, D_8019A830] + - [0x1A930, pal, D_8019A930] # unused + - [0x1AA30, pal, D_8019AA30] + - [0x1AB30, pal, D_8019AB30] # unused + - [0x1AC30, pal, D_8019AC30] + - [0x1AD30, pal, D_8019AD30] + - [0x1AD70, pal, D_8019AD70] + - [0x1ADD0, pal, D_8019ADD0] + - [0x1AE70, pal, D_8019AE70] + - [0x1AF30, pal, D_8019AF30] + - [0x1B010, pal, D_8019B010] + - [0x1B210, pal, D_8019B210] # unused - [0x1B2D0, .data, tile_data] # tile data - [0x1E6D0, .data, tile_data] # tile definitions - [0x226E0, .data, sprites] diff --git a/config/splat.us.stwrp.yaml b/config/splat.us.stwrp.yaml index cc6249e38..418b58de2 100644 --- a/config/splat.us.stwrp.yaml +++ b/config/splat.us.stwrp.yaml @@ -55,7 +55,8 @@ segments: - [0x1228, .data, e_layout] # layout entries data - [0x1420, cmp, D_80181420] - [0x1764, cmp, D_80181764] - - [0x1D08, raw, D_80181D08] + - [0x1D08, pal, D_80181D08] + - [0x1D28, pal, D_80181D28] - [0x1D68, .data, tile_data] # tile data - [0x2968, .data, tile_data] # tile definitions - [0x6D88, .data, sprites] diff --git a/src/boss/.gitignore b/src/boss/.gitignore index 52cf83f12..284ff22cc 100644 --- a/src/boss/.gitignore +++ b/src/boss/.gitignore @@ -3,6 +3,7 @@ sprites.c e_laydef.c e_layout.c layers.h +palette_def.h sprite_banks.h tilemap_*.h tiledef_*.h diff --git a/src/boss/mar/header.c b/src/boss/mar/header.c index 541243061..71aeedd9c 100644 --- a/src/boss/mar/header.c +++ b/src/boss/mar/header.c @@ -24,20 +24,7 @@ AbbreviatedOverlay OVL_EXPORT(Overlay) = { }; #include "sprite_banks.h" - -extern u16* D_us_80184EE0[]; -extern u16* D_us_801850E0[]; -extern u16* D_us_801852E0[]; -static u16** D_us_8018008C[] = { - 0x00000005, 0x00002000, 0x00000080, D_us_80184EE0, - 0x00002080, 0x00000080, D_us_801850E0, 0x00002100, - 0x00000010, D_us_801852E0, PAL_TERMINATE(), -}; - -u_long* OVL_EXPORT(cluts)[] = { - D_us_8018008C, -}; - +#include "palette_def.h" #include "layers.h" static u_long* D_us_801800F4_TERM = GFX_TERMINATE(); diff --git a/src/st/.gitignore b/src/st/.gitignore index 52cf83f12..284ff22cc 100644 --- a/src/st/.gitignore +++ b/src/st/.gitignore @@ -3,6 +3,7 @@ sprites.c e_laydef.c e_layout.c layers.h +palette_def.h sprite_banks.h tilemap_*.h tiledef_*.h diff --git a/src/st/cen/header.c b/src/st/cen/header.c index 766a5c548..944db8c98 100644 --- a/src/st/cen/header.c +++ b/src/st/cen/header.c @@ -28,18 +28,7 @@ Overlay OVL_EXPORT(Overlay) = { }; #include "sprite_banks.h" - -extern u16* D_8018658C[0x80]; -extern u16* D_8018678C[0x80]; -extern u16* D_8018698C[0x10]; -extern u16* D_801869AC[0x20]; -static u_long* D_801800A0[] = { - MAKE_PAL_OP(PAL_BULK_COPY, 0), PAL_BULK(0x2000, D_8018658C), - PAL_BULK(0x2080, D_8018678C), PAL_BULK(0x2100, D_8018698C), - PAL_BULK(0x2230, D_801869AC), PAL_TERMINATE(), -}; -u_long* OVL_EXPORT(cluts)[] = {D_801800A0}; - +#include "palette_def.h" #include "layers.h" static u32 D_8019C704[24]; diff --git a/src/st/dre/header.c b/src/st/dre/header.c index ee969f2b6..3f0bd1678 100644 --- a/src/st/dre/header.c +++ b/src/st/dre/header.c @@ -23,25 +23,5 @@ Overlay OVL_EXPORT(Overlay) = { }; #include "sprite_banks.h" - -extern u16* D_8018AEA8[0x50]; -extern u16* D_8018AF48[0x80]; -extern u16* D_8018B148[0x80]; -extern u16* D_8018B348[0x80]; -extern u16* D_8018ABE8[0x100]; - -static u_long* Clut[] = { - MAKE_PAL_OP(PAL_BULK_COPY, 0), - PAL_BULK(0x2000, D_8018AEA8), - PAL_BULK(0x2080, D_8018AF48), - PAL_BULK(0x2100, D_8018B148), - PAL_BULK(0x2180, D_8018B348), - PAL_BULK(0x2E00, D_8018ABE8), - PAL_TERMINATE(), -}; - -u_long* OVL_EXPORT(cluts)[] = { - Clut, -}; - +#include "palette_def.h" #include "layers.h" diff --git a/src/st/no3/header.c b/src/st/no3/header.c index 1bc5a1604..e100a0281 100644 --- a/src/st/no3/header.c +++ b/src/st/no3/header.c @@ -24,68 +24,7 @@ AbbreviatedOverlay OVL_EXPORT(Overlay) = { }; #include "sprite_banks.h" - -extern u16* D_80198578[0x100]; -extern u16* D_801966B8[0x8C0]; -extern u16* D_80197838[0x60]; -extern u16* D_80197918[0x20]; -extern u16* D_80197958[0x20]; -extern u16* D_80197998[0x20]; -extern u16* D_801979D8[0x20]; -extern u16* D_80197A18[0x20]; -extern u16* D_80197A58[0x20]; -extern u16* D_80197A98[0x20]; -extern u16* D_80197AD8[0x20]; -extern u16* D_80197B18[0x20]; -extern u16* D_80197B58[0x20]; -extern u16* D_80197B98[0x20]; -extern u16* D_80197BD8[0x20]; -extern u16* D_80197C18[0x20]; -extern u16* D_80197C58[0x20]; -extern u16* D_80197C98[0x130]; -extern u16* D_80197EF8[0x30]; -extern u16* D_80197F58[0x30]; -extern u16* D_80197FB8[0x80]; -extern u16* D_801980B8[0x30]; -extern u16* D_80198518[0x30]; -extern u16* D_80198118[0x80]; -extern u16* D_80198318[0x80]; - -// n.b.! very similar to np3 -static u_long* Clut[] = { - MAKE_PAL_OP(PAL_BULK_COPY, 0), - PAL_BULK(0xD00, D_80198578), - PAL_BULK(0x2000, D_801966B8), - PAL_BULK(0x28C0, D_80197838), - PAL_BULK(0x2920, D_80197918), - PAL_BULK(0x2940, D_80197958), - PAL_BULK(0x2960, D_80197998), - PAL_BULK(0x2980, D_801979D8), - PAL_BULK(0x29A0, D_80197A18), - PAL_BULK(0x29C0, D_80197A58), - PAL_BULK(0x29E0, D_80197A98), - PAL_BULK(0x2A00, D_80197AD8), - PAL_BULK(0x2A20, D_80197B18), - PAL_BULK(0x2A40, D_80197B58), - PAL_BULK(0x2A60, D_80197B98), - PAL_BULK(0x2A80, D_80197BD8), - PAL_BULK(0x2AA0, D_80197C18), - PAL_BULK(0x2AC0, D_80197C58), - PAL_BULK(0x2B20, D_80197C98), - PAL_BULK(0x2C50, D_80197EF8), - PAL_BULK(0x2C80, D_80197F58), - PAL_BULK(0x2CB0, D_80197FB8), - PAL_BULK(0x2D30, D_801980B8), - PAL_BULK(0x2D60, D_80198518), - PAL_BULK(0x2E00, D_80198118), - PAL_BULK(0x2E80, D_80198318), - PAL_TERMINATE(), -}; - -u_long* OVL_EXPORT(cluts)[] = { - Clut, -}; - +#include "palette_def.h" #include "layers.h" static GfxBank D_801805A4 = { diff --git a/src/st/np3/header.c b/src/st/np3/header.c index 897b05574..ecaae7601 100644 --- a/src/st/np3/header.c +++ b/src/st/np3/header.c @@ -24,53 +24,5 @@ static AbbreviatedOverlay OVL_EXPORT(Overlay) = { }; #include "sprite_banks.h" - -extern u16* D_801963B4[0x100]; -extern u16* D_80194914[0x8C0]; -extern u16* D_80195A94[0x60]; -extern u16* D_80195B74[0x20]; -extern u16* D_80195BB4[0x20]; -extern u16* D_80195BF4[0x20]; -extern u16* D_80195C34[0x20]; -extern u16* D_80195C74[0x20]; -extern u16* D_80195CB4[0x20]; -extern u16* D_80195CF4[0x20]; -extern u16* D_80195D34[0x20]; -extern u16* D_80195D74[0x20]; -extern u16* D_80195DB4[0x20]; -extern u16* D_80195DF4[0x20]; -extern u16* D_80195E34[0x20]; -extern u16* D_80195E74[0x20]; -extern u16* D_80195EB4[0x20]; -extern u16* D_80195EF4[0x130]; -extern u16* D_80196154[0x30]; -extern u16* D_801961B4[0x30]; -extern u16* D_801962D4[0x70]; -extern u16* D_80196214[0x30]; -extern u16* D_80196274[0x30]; -extern u16* D_80196674[0x90]; -extern u16* D_801966D4[0x80]; -extern u16* D_801967D4[0x90]; - -static u_long* Clut[] = { - MAKE_PAL_OP(PAL_BULK_COPY, 0), PAL_BULK(0xD00, D_801963B4), - PAL_BULK(0x2000, D_80194914), PAL_BULK(0x28C0, D_80195A94), - PAL_BULK(0x2920, D_80195B74), PAL_BULK(0x2940, D_80195BB4), - PAL_BULK(0x2960, D_80195BF4), PAL_BULK(0x2980, D_80195C34), - PAL_BULK(0x29A0, D_80195C74), PAL_BULK(0x29C0, D_80195CB4), - PAL_BULK(0x29E0, D_80195CF4), PAL_BULK(0x2A00, D_80195D34), - PAL_BULK(0x2A20, D_80195D74), PAL_BULK(0x2A40, D_80195DB4), - PAL_BULK(0x2A60, D_80195DF4), PAL_BULK(0x2A80, D_80195E34), - PAL_BULK(0x2AA0, D_80195E74), PAL_BULK(0x2AC0, D_80195EB4), - PAL_BULK(0x2B20, D_80195EF4), PAL_BULK(0x2C50, D_80196154), - PAL_BULK(0x2C80, D_801961B4), PAL_BULK(0x2CB0, D_801962D4), - PAL_BULK(0x2D30, D_80196214), PAL_BULK(0x2D60, D_80196274), - PAL_BULK(0x2D90, D_80196674), PAL_BULK(0x2E20, D_801966D4), - PAL_BULK(0x2EA0, D_801967D4), PAL_TERMINATE(), -}; - -u_long* OVL_EXPORT(cluts)[] = { - Clut, -}; - +#include "palette_def.h" #include "layers.h" diff --git a/src/st/nz0/header.c b/src/st/nz0/header.c index fc02e596f..fc405133d 100644 --- a/src/st/nz0/header.c +++ b/src/st/nz0/header.c @@ -8,7 +8,7 @@ void InitRoomEntities(); void UpdateStageEntities(); extern s16** OVL_EXPORT(spriteBanks)[]; -extern u_long** OVL_EXPORT(cluts)[]; +extern u_long* OVL_EXPORT(cluts)[]; extern LayoutEntity* OVL_EXPORT(pStObjLayoutHorizontal)[]; extern u_long* OVL_EXPORT(gfxBanks)[]; extern MyRoomDef OVL_EXPORT(rooms_layers)[]; @@ -29,50 +29,7 @@ AbbreviatedOverlay OVL_EXPORT(Overlay) = { }; #include "sprite_banks.h" - -extern u16* D_80195C3C[0x40]; -extern u16* D_80195CDC[0x10]; -extern u16* D_80195D3C[0x40]; -extern u16* D_80195DBC[0x30]; -extern u16* D_80195E1C[0x10]; -extern u16* D_80195E3C[0x30]; -extern u16* D_80195E9C[0x40]; -extern u16* D_80195F1C[0x40]; -extern u16* D_80195F9C[0x40]; -extern u16* D_8019601C[0x100]; -extern u16* D_801962DC[0xA0]; -extern u16* D_8019641C[0x30]; -extern u16* D_8019647C[0x80]; -extern u16* D_8019657C[0x50]; -extern u16* D_8019663C[0x10]; -extern u16* D_8019665C[0x80]; -extern u16* D_8019685C[0x80]; -static u_long* D_8018008C[] = { - MAKE_PAL_OP(PAL_BULK_COPY, 0), - PAL_BULK(0x2000, D_80195C3C), - PAL_BULK(0x2040, D_80195CDC), - PAL_BULK(0x2050, D_80195D3C), - PAL_BULK(0x2090, D_80195DBC), - PAL_BULK(0x20C0, D_80195E1C), - PAL_BULK(0x20D0, D_80195E3C), - PAL_BULK(0x2110, D_80195F1C), - PAL_BULK(0x2150, D_80195F9C), - PAL_BULK(0x2190, D_80195E9C), - PAL_BULK(0x21D0, D_801962DC), - PAL_BULK(0x2270, D_8019641C), - PAL_BULK(0x22A0, D_8019647C), - PAL_BULK(0x2320, D_8019657C), - PAL_BULK(0x2370, D_8019663C), - PAL_BULK(0x2380, D_8019665C), - PAL_BULK(0x2400, D_8019685C), - PAL_BULK(0x2E00, D_8019601C), - PAL_TERMINATE(), -}; - -u_long** OVL_EXPORT(cluts)[] = { - &D_8018008C, -}; - +#include "palette_def.h" #include "layers.h" static u_long* D_8018047C[] = { diff --git a/src/st/rwrp/header.c b/src/st/rwrp/header.c index 8daa4e58d..c32d78f3e 100644 --- a/src/st/rwrp/header.c +++ b/src/st/rwrp/header.c @@ -23,17 +23,5 @@ static Overlay OVL_EXPORT(Overlay) = { }; #include "sprite_banks.h" - -extern u16* D_80181D08[0x100]; - -static u_long* Clut[] = { - MAKE_PAL_OP(PAL_BULK_COPY, 0), - PAL_BULK(0x2E00, D_80181D08), - PAL_TERMINATE(), -}; - -u_long* OVL_EXPORT(cluts)[] = { - Clut, -}; - +#include "palette_def.h" #include "layers.h" diff --git a/src/st/st0/header.c b/src/st/st0/header.c index db20ce45f..febcd7741 100644 --- a/src/st/st0/header.c +++ b/src/st/st0/header.c @@ -26,28 +26,5 @@ static Overlay OVL_EXPORT(Overlay) = { }; #include "sprite_banks.h" - -extern u16* D_8019A750[0x70]; -extern u16* D_8019AD30[0x20]; -extern u16* D_8019AC30[0x80]; -extern u16* D_8019AD70[0x30]; -extern u16* D_8019ADD0[0x50]; -extern u16* D_8019AE70[0x60]; -extern u16* D_8019AF30[0x70]; -extern u16* D_8019A830[0x80]; -extern u16* D_8019AA30[0x80]; -extern u16* D_8019B010[0x100]; - -static u_long* Clut[] = { - MAKE_PAL_OP(PAL_BULK_COPY, 0), PAL_BULK(0x2000, D_8019A750), - PAL_BULK(0x2100, D_8019AD30), PAL_BULK(0x2120, D_8019AC30), - PAL_BULK(0x21A0, D_8019AD70), PAL_BULK(0x21D0, D_8019ADD0), - PAL_BULK(0x2220, D_8019AE70), PAL_BULK(0x2280, D_8019AF30), - PAL_BULK(0x2300, D_8019A830), PAL_BULK(0x2480, D_8019AA30), - PAL_BULK(0x2800, D_8019B010), PAL_TERMINATE()}; - -u_long* OVL_EXPORT(cluts)[] = { - Clut, -}; - +#include "palette_def.h" #include "layers.h" diff --git a/src/st/wrp/header.c b/src/st/wrp/header.c index 95d4e885f..662840b79 100644 --- a/src/st/wrp/header.c +++ b/src/st/wrp/header.c @@ -28,15 +28,7 @@ Overlay OVL_EXPORT(Overlay) = { }; #include "sprite_banks.h" - -extern u16 D_80181D08[16]; -u_long* D_801800A0[] = { - MAKE_PAL_OP(PAL_BULK_COPY, 0), - PAL_BULK(0x2000, D_80181D08), - PAL_TERMINATE(), -}; -u_long* OVL_EXPORT(cluts)[] = {D_801800A0}; - +#include "palette_def.h" #include "layers.h" static u_long* D_801801B8[] = { diff --git a/tools/sotn-assets/asset_config.go b/tools/sotn-assets/asset_config.go index 48d8a9c84..2add93f64 100644 --- a/tools/sotn-assets/asset_config.go +++ b/tools/sotn-assets/asset_config.go @@ -6,6 +6,7 @@ import ( "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/assets/cutscene" "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/assets/layer" "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/assets/layout" + "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/assets/paldef" "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/assets/rooms" "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/assets/skip" "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/assets/spritebanks" @@ -40,6 +41,7 @@ var handlers = func() map[string]assets.Handler { cutscene.Handler, layer.Handler, layout.Handler, + paldef.Handler, rooms.Handler, skip.Handler, spritebanks.Handler, @@ -95,7 +97,7 @@ func enqueueExtractAssetEntry( eg.Go(func() error { defer func() { if err := recover(); err != nil { - fmt.Printf("unable to extract asset %q: %v", name, err) + fmt.Printf("unable to extract asset %q in %q: %v", name, assetDir, err) } }() if err := handler.Extract(assets.ExtractArgs{ @@ -107,7 +109,7 @@ func enqueueExtractAssetEntry( Name: name, Args: args, }); err != nil { - return fmt.Errorf("unable to extract asset %q: %v", name, err) + return fmt.Errorf("unable to extract asset %q in %q: %v", name, assetDir, err) } return nil }) diff --git a/tools/sotn-assets/assets/assets.go b/tools/sotn-assets/assets/assets.go index 50340097d..3099befad 100644 --- a/tools/sotn-assets/assets/assets.go +++ b/tools/sotn-assets/assets/assets.go @@ -38,6 +38,7 @@ type InfoAssetEntry struct { } type InfoSplatEntry struct { DataRange datarange.DataRange + Kind string Name string Comment string } diff --git a/tools/sotn-assets/assets/cutscene/handler.go b/tools/sotn-assets/assets/cutscene/handler.go index 108150b40..d2394f123 100644 --- a/tools/sotn-assets/assets/cutscene/handler.go +++ b/tools/sotn-assets/assets/cutscene/handler.go @@ -5,11 +5,11 @@ import ( "fmt" "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/assets" "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/psx" + "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/util" "gopkg.in/yaml.v2" "io" "os" "path" - "path/filepath" "strconv" "strings" ) @@ -29,12 +29,6 @@ func (h *handler) Extract(e assets.ExtractArgs) error { if err != nil { return err } - outFileName := assetPath(e.AssetDir, e.Name) - dir := filepath.Dir(outFileName) - if err := os.MkdirAll(dir, 0755); err != nil { - fmt.Printf("failed to create directory %s: %v\n", dir, err) - return err - } yaml := "script:\n" for _, command := range script { if len(command) == 0 { @@ -49,7 +43,7 @@ func (h *handler) Extract(e assets.ExtractArgs) error { yaml += fmt.Sprintf(" - [%s]\n", strings.Join(command, ", ")) } } - return os.WriteFile(outFileName, []byte(yaml), 0644) + return util.WriteFile(assetPath(e.AssetDir, e.Name), []byte(yaml)) } type scriptSrc struct { diff --git a/tools/sotn-assets/assets/layer/handler.go b/tools/sotn-assets/assets/layer/handler.go index 86bf985dd..4cbaa20d9 100644 --- a/tools/sotn-assets/assets/layer/handler.go +++ b/tools/sotn-assets/assets/layer/handler.go @@ -2,15 +2,14 @@ package layer import ( "bytes" - "encoding/json" "fmt" "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/assets" "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/datarange" "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/psx" "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/sotn" + "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/util" "os" "path" - "path/filepath" ) type handler struct{} @@ -49,18 +48,7 @@ func (h *handler) Extract(e assets.ExtractArgs) error { tileDefsRange = datarange.MergeDataRanges([]datarange.DataRange{tileDefsRange, unusedTileDefRange}) } - outFileName := path.Join(e.AssetDir, "layers.json") - dir := filepath.Dir(outFileName) - if err := os.MkdirAll(dir, 0755); err != nil { - fmt.Printf("failed to create directory %s: %v\n", dir, err) - return err - } - - content, err := json.MarshalIndent(l, "", " ") - if err != nil { - return err - } - if err := os.WriteFile(outFileName, content, 0644); err != nil { + if err := util.WriteJsonFile(path.Join(e.AssetDir, "layers.json"), l); err != nil { return fmt.Errorf("unable to create layers file: %w", err) } @@ -90,14 +78,8 @@ func (h *handler) Extract(e assets.ExtractArgs) error { if err := os.WriteFile(path.Join(e.AssetDir, defs.Collisions), tileDefsData.Cols, 0644); err != nil { return fmt.Errorf("unable to create %q: %w", defs.Collisions, err) } - - content, err = json.MarshalIndent(defs, "", " ") - if err != nil { - return err - } - fileName := path.Join(e.AssetDir, tiledefFileName(offset)) - if err := os.WriteFile(fileName, content, 0644); err != nil { - return fmt.Errorf("unable to create %q: %w", fileName, err) + if err := util.WriteJsonFile(path.Join(e.AssetDir, tiledefFileName(offset)), defs); err != nil { + return fmt.Errorf("unable to create layers file: %w", err) } } return nil diff --git a/tools/sotn-assets/assets/layout/handler.go b/tools/sotn-assets/assets/layout/handler.go index cf1c40bd5..be936fba0 100644 --- a/tools/sotn-assets/assets/layout/handler.go +++ b/tools/sotn-assets/assets/layout/handler.go @@ -2,14 +2,13 @@ package layout import ( "bytes" - "encoding/json" "fmt" "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/assets" "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/assets/graphics" "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/psx" "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/sotn" + "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/util" "io" - "os" "path" ) @@ -29,14 +28,7 @@ func (h *handler) Extract(e assets.ExtractArgs) error { return err } layouts, _, err := readEntityLayout(r, ovlName, layoutOff, entryCount, true) - if err != nil { - return err - } - content, err := json.MarshalIndent(layouts, "", " ") - if err != nil { - return err - } - return os.WriteFile(assetPath(e.AssetDir, e.Name), content, 0644) + return util.WriteJsonFile(assetPath(e.AssetDir, e.Name), layouts) } func (h *handler) Build(e assets.BuildArgs) error { diff --git a/tools/sotn-assets/assets/paldef/palette_def.go b/tools/sotn-assets/assets/paldef/palette_def.go new file mode 100644 index 000000000..81f24ad5d --- /dev/null +++ b/tools/sotn-assets/assets/paldef/palette_def.go @@ -0,0 +1,201 @@ +package paldef + +import ( + "bytes" + "encoding/binary" + "encoding/json" + "fmt" + "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/assets" + "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/datarange" + "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/psx" + "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/sotn" + "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/util" + "io" + "os" + "path" + "sort" + "strings" +) + +const palBulkCopy = 5 // PAL_BULK_COPY +const palTerminate = 0xFFFFFFFF // PAL_BULK_COPY + +type handler struct{} + +var Handler = &handler{} + +func (h *handler) Name() string { return "paldef" } + +func (h *handler) Extract(e assets.ExtractArgs) error { + r := bytes.NewReader(e.Data) + clutAddr := e.RamBase.Sum(e.End - 4) + if err := clutAddr.MoveFile(r, e.RamBase); err != nil { + return fmt.Errorf("invalid offset: %w", err) + } + var palDefAddr psx.Addr + if err := binary.Read(r, binary.LittleEndian, &palDefAddr); err != nil { + return fmt.Errorf("error reading exported clut first entry: %w", err) + } + if palDefAddr.Real(psx.RamStageBegin) != e.Start { + return fmt.Errorf("invalid palette entry offset, got %s but expected %s", palDefAddr, e.RamBase.Sum(e.Start)) + } + entries, err := readPaletteEntries(r, e.RamBase, palDefAddr) + if err != nil { + return err + } + return util.WriteJsonFile(assetPath(e.AssetDir, e.Name), entries) +} + +func (h *handler) Build(e assets.BuildArgs) error { + data, err := os.ReadFile(assetPath(e.AssetDir, e.Name)) + if err != nil { + return err + } + var entries []paletteEntry + if err := json.Unmarshal(data, &entries); err != nil { + return err + } + content := strings.Builder{} + content.WriteString("// clang-format off\n") + for _, entry := range entries { + content.WriteString(fmt.Sprintf("extern u16* %s[0x%X];\n", + util.RemoveFileNameExt(entry.Name), entry.Length)) + } + content.WriteString("static u_long* pal_def[] = {\n") + content.WriteString(" MAKE_PAL_OP(PAL_BULK_COPY, 0),\n") + for _, entry := range entries { + content.WriteString(fmt.Sprintf(" PAL_BULK(0x%04X, %s),\n", + entry.Destination, + util.RemoveFileNameExt(entry.Name))) + } + content.WriteString(" PAL_TERMINATE(),\n") + content.WriteString("};\n") + content.WriteString("u_long* OVL_EXPORT(cluts)[] = {pal_def};\n") + return os.WriteFile(sourcePath(e.SrcDir, e.Name), []byte(content.String()), 0644) +} + +func (h *handler) Info(a assets.InfoArgs) (assets.InfoResult, error) { + r := bytes.NewReader(a.StageData) + header, err := sotn.ReadStageHeader(r) + if err != nil { + return assets.InfoResult{}, err + } + if err := header.Cluts.MoveFile(r, psx.RamStageBegin); err != nil { + return assets.InfoResult{}, fmt.Errorf("invalid offset: %w", err) + } + var palDefAddr psx.Addr + if err := binary.Read(r, binary.LittleEndian, &palDefAddr); err != nil { + return assets.InfoResult{}, fmt.Errorf("error reading exported clut first entry: %w", err) + } + if !palDefAddr.InRange(psx.RamStageBegin, psx.RamStageEnd) { + return assets.InfoResult{}, fmt.Errorf("invalid palette entry at %s, address out of the stage range: got %s", header.Cluts, palDefAddr) + } + entries, err := readPaletteEntries(r, psx.RamStageBegin, palDefAddr) + if err != nil { + return assets.InfoResult{}, err + } + palDefRange := datarange.New(palDefAddr, header.Cluts.Sum(4)) + var splatEntries []assets.InfoSplatEntry + for _, entry := range entries { + splatEntries = append(splatEntries, assets.InfoSplatEntry{ + DataRange: datarange.FromAddr(entry.addr, entry.Length*2), + Kind: "pal", + Name: util.RemoveFileNameExt(entry.Name), + }) + } + splatEntries = addGuessedUnusedPalettes(splatEntries) + splatEntries = append(splatEntries, assets.InfoSplatEntry{ + DataRange: palDefRange, + Name: "header", + Comment: "palette definitions", + }) + return assets.InfoResult{ + AssetEntries: []assets.InfoAssetEntry{ + { + DataRange: palDefRange, + Kind: h.Name(), + Name: "palette_def", + }, + }, + SplatEntries: splatEntries, + }, nil +} + +func assetPath(dir, name string) string { + return path.Join(dir, fmt.Sprintf("%s.json", name)) +} + +func sourcePath(dir, name string) string { + return path.Join(dir, fmt.Sprintf("%s.h", name)) +} + +type paletteEntry struct { + Destination int `json:"destination"` + Length int `json:"length"` + Name string `json:"name"` + addr psx.Addr +} + +func readPaletteEntries(r io.ReadSeeker, baseAddr, addr psx.Addr) ([]paletteEntry, error) { + var entries []paletteEntry + if err := addr.MoveFile(r, baseAddr); err != nil { + return nil, fmt.Errorf("invalid offset: %w", err) + } + var paletteOp uint32 + if err := binary.Read(r, binary.LittleEndian, &paletteOp); err != nil { + return nil, fmt.Errorf("error reading palette entries: %w", err) + } + if paletteOp != palBulkCopy { + return nil, fmt.Errorf("invalid palette op, expected %08X but got %08X", palBulkCopy, paletteOp) + } + for i := 0; ; i++ { + var dst uint32 + var length uint32 + var addr psx.Addr + _ = binary.Read(r, binary.LittleEndian, &dst) + if dst == palTerminate { + break + } + _ = binary.Read(r, binary.LittleEndian, &length) + _ = binary.Read(r, binary.LittleEndian, &addr) + if dst > 0x8000 { + return nil, fmt.Errorf("invalid palette entry at %s, destination out of range: got 0x%08X, expected less than 0x8000", baseAddr.Sum(i*4*3+4), dst) + } + if length > 0x1000 { + return nil, fmt.Errorf("invalid palette entry at %s, length out of range: got 0x%08X, expected less than 0x1000", baseAddr.Sum(i*4*3+4), length) + } + if !addr.InRange(psx.RamStageBegin, psx.RamStageEnd) { + return nil, fmt.Errorf("invalid palette entry at %s, address out of the stage range: got %s", baseAddr.Sum(i*4*3+4), addr) + } + entries = append(entries, paletteEntry{ + Destination: int(dst), + Length: int(length), + Name: fmt.Sprintf("D_%08X.bin", uint32(addr)), + addr: addr, + }) + } + return entries, nil +} + +func addGuessedUnusedPalettes(entries []assets.InfoSplatEntry) []assets.InfoSplatEntry { + sort.Slice(entries, func(i, j int) bool { + return entries[i].DataRange.Begin() < entries[j].DataRange.Begin() + }) + newEntries := make([]assets.InfoSplatEntry, 0, len(entries)) + newEntries = append(newEntries, entries[0]) + for i := 1; i < len(entries); i++ { + // if there is a gap between two entries then we add the new guessed unused palette + addrLeft := entries[i-1].DataRange.End() + addrRight := entries[i].DataRange.Begin() + if addrLeft != addrRight { + newEntries = append(newEntries, assets.InfoSplatEntry{ + DataRange: datarange.New(addrLeft, addrRight), + Name: fmt.Sprintf("D_%08X", uint32(addrLeft)), + Kind: "pal", + Comment: "unused", + }) + } + newEntries = append(newEntries, entries[i]) + } + return newEntries +} diff --git a/tools/sotn-assets/assets/rooms/handler.go b/tools/sotn-assets/assets/rooms/handler.go index 2117d6f0f..60e7f0afb 100644 --- a/tools/sotn-assets/assets/rooms/handler.go +++ b/tools/sotn-assets/assets/rooms/handler.go @@ -9,10 +9,10 @@ import ( "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/datarange" "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/psx" "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/sotn" + "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/util" "io" "os" "path" - "path/filepath" "strings" ) @@ -39,17 +39,7 @@ func (h *handler) Extract(e assets.ExtractArgs) error { if err != nil { return fmt.Errorf("failed to read rooms: %w", err) } - content, err := json.MarshalIndent(rooms, "", " ") - if err != nil { - return err - } - outFileName := assetPath(e.AssetDir, e.Name) - dir := filepath.Dir(outFileName) - if err := os.MkdirAll(dir, 0755); err != nil { - fmt.Printf("failed to create directory %s: %v\n", dir, err) - return err - } - return os.WriteFile(outFileName, content, 0644) + return util.WriteJsonFile(assetPath(e.AssetDir, e.Name), rooms) } func (h *handler) Build(e assets.BuildArgs) error { diff --git a/tools/sotn-assets/assets/spritebanks/handler.go b/tools/sotn-assets/assets/spritebanks/handler.go index 1daa4e166..4fb6f8d28 100644 --- a/tools/sotn-assets/assets/spritebanks/handler.go +++ b/tools/sotn-assets/assets/spritebanks/handler.go @@ -2,15 +2,13 @@ package spritebanks import ( "bytes" - "encoding/json" "fmt" "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/assets" "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/datarange" "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/psx" "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/sotn" - "os" + "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/util" "path" - "path/filepath" ) const banksCount = 24 // the number seems to be fixed @@ -30,17 +28,7 @@ func (h *handler) Extract(e assets.ExtractArgs) error { if err != nil { return fmt.Errorf("failed to read sprites: %w", err) } - content, err := json.MarshalIndent(banks, "", " ") - if err != nil { - return err - } - outFileName := assetPath(e.AssetDir, e.Name) - dir := filepath.Dir(outFileName) - if err := os.MkdirAll(dir, 0755); err != nil { - fmt.Printf("failed to create directory %s: %v\n", dir, err) - return err - } - return os.WriteFile(outFileName, content, 0644) + return util.WriteJsonFile(assetPath(e.AssetDir, e.Name), banks) } func (h *handler) Build(e assets.BuildArgs) error { @@ -75,15 +63,5 @@ func (h *handler) Info(a assets.InfoArgs) (assets.InfoResult, error) { } func assetPath(dir, name string) string { - if name == "" { - name = "sprite_banks" - } return path.Join(dir, fmt.Sprintf("%s.json", name)) } - -func sourcePath(dir, name string) string { - if name == "" { - name = "sprite_banks" - } - return path.Join(dir, fmt.Sprintf("%s.h", name)) -} diff --git a/tools/sotn-assets/assets/spriteset/handler.go b/tools/sotn-assets/assets/spriteset/handler.go index 6504132a0..d4bb86532 100644 --- a/tools/sotn-assets/assets/spriteset/handler.go +++ b/tools/sotn-assets/assets/spriteset/handler.go @@ -5,9 +5,9 @@ import ( "encoding/json" "fmt" "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/assets" + "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/util" "os" "path" - "path/filepath" "strings" ) @@ -18,9 +18,6 @@ var Handler = &handler{} func (h *handler) Name() string { return "spriteset" } func (h *handler) Extract(e assets.ExtractArgs) error { - if e.Name == "" { - return fmt.Errorf("data at 0x%X must have a name", e.Start) - } var sprites []*spriteParts var err error if e.Start != e.End { @@ -32,18 +29,7 @@ func (h *handler) Extract(e assets.ExtractArgs) error { } else { sprites = make([]*spriteParts, 0) } - content, err := json.MarshalIndent(sprites, "", " ") - if err != nil { - return err - } - - outFileName := assetPath(e.AssetDir, e.Name) - dir := filepath.Dir(outFileName) - if err := os.MkdirAll(dir, 0755); err != nil { - fmt.Printf("failed to create directory %s: %v\n", dir, err) - return err - } - return os.WriteFile(outFileName, content, 0644) + return util.WriteJsonFile(assetPath(e.AssetDir, e.Name), sprites) } func (h *handler) Build(e assets.BuildArgs) error { diff --git a/tools/sotn-assets/info.go b/tools/sotn-assets/info.go index 9003b48dd..08ef002a3 100644 --- a/tools/sotn-assets/info.go +++ b/tools/sotn-assets/info.go @@ -60,7 +60,11 @@ func infoSplatEntries(w io.Writer, entries []assets.InfoSplatEntry) { return entries[i].DataRange.Begin() < entries[j].DataRange.Begin() }) for i, e := range entries { - s := fmt.Sprintf(" - [0x%X, .data, %s]", e.DataRange.Begin().Real(psx.RamStageBegin), e.Name) + kind := ".data" + if e.Kind != "" { + kind = e.Kind + } + s := fmt.Sprintf(" - [0x%X, %s, %s]", e.DataRange.Begin().Real(psx.RamStageBegin), kind, e.Name) if e.Comment != "" { s = fmt.Sprintf("%s # %s", s, e.Comment) } diff --git a/tools/sotn-assets/info_test.go b/tools/sotn-assets/info_test.go index a161a9585..0dc45f1b2 100644 --- a/tools/sotn-assets/info_test.go +++ b/tools/sotn-assets/info_test.go @@ -22,7 +22,7 @@ func TestGatherAssetInfo(t *testing.T) { t.Run("asset config hints", func(t *testing.T) { assert.Contains(t, stdout, "asset config hints:\n") assert.Contains(t, stdout, " - [0x2C, sprite_banks, sprite_banks]") - assert.Contains(t, stdout, " - [0x8C, skip]") + assert.Contains(t, stdout, " - [0x8C, paldef, palette_def]") assert.Contains(t, stdout, " - [0x164, layers, layers]\n") assert.Contains(t, stdout, " - [0x8EC, layout, entity_layouts]\n") assert.Contains(t, stdout, " - [0x272C, rooms, rooms]") @@ -34,6 +34,7 @@ func TestGatherAssetInfo(t *testing.T) { t.Run("splat config hints", func(t *testing.T) { assert.Contains(t, stdout, "splat config hints:\n") assert.Contains(t, stdout, " - [0x0, .data, header]\n") + assert.Contains(t, stdout, " - [0x8C, .data, header] # palette definitions\n") assert.Contains(t, stdout, " - [0x164, .data, header] # layers\n") assert.Contains(t, stdout, " - [0x8EC, .data, e_laydef] # layout entries header\n") assert.Contains(t, stdout, " - [0xA94, data]\n") @@ -41,6 +42,10 @@ func TestGatherAssetInfo(t *testing.T) { assert.Contains(t, stdout, " - [0x2830, data]\n") assert.Contains(t, stdout, " - [0x2884, .data, e_layout] # layout entries data\n") assert.Contains(t, stdout, " - [0x3B0C, data]\n") + assert.Contains(t, stdout, " - [0x15C3C, pal, D_80195C3C]\n") + assert.Contains(t, stdout, " - [0x1601C, pal, D_8019601C]\n") + assert.Contains(t, stdout, " - [0x1621C, pal, D_8019621C] # unused\n") + assert.Contains(t, stdout, " - [0x162DC, pal, D_801962DC]\n") assert.Contains(t, stdout, " - [0x16A5C, .data, tile_data] # tile data\n") assert.Contains(t, stdout, " - [0x20A5C, .data, tile_data] # tile definitions\n") assert.Contains(t, stdout, " - [0x26E8C, .data, sprites]\n") diff --git a/tools/sotn-assets/util/utils.go b/tools/sotn-assets/util/utils.go index eea1ffefc..a010ffae0 100644 --- a/tools/sotn-assets/util/utils.go +++ b/tools/sotn-assets/util/utils.go @@ -1,7 +1,11 @@ package util import ( + "encoding/json" + "fmt" "github.com/xeeynamo/sotn-decomp/tools/sotn-assets/psx" + "os" + "path/filepath" "slices" "strings" ) @@ -69,3 +73,25 @@ func SortUniqueOffsets(slice []psx.Addr) []psx.Addr { }) return newSlice } + +// WriteFile ensures the directory of the file to create exists +func WriteFile(name string, content []byte) error { + dir := filepath.Dir(name) + if err := os.MkdirAll(dir, 0755); err != nil { + return fmt.Errorf("failed to create directory %q: %v\n", dir, err) + } + return os.WriteFile(name, content, 0644) +} + +// WriteJsonFile converts the passed object as a JSON and internally calls WriteFile +func WriteJsonFile(name string, v any) error { + content, err := json.MarshalIndent(v, "", " ") + if err != nil { + return err + } + return WriteFile(name, content) +} + +func RemoveFileNameExt(name string) string { + return strings.TrimSuffix(name, filepath.Ext(name)) +} diff --git a/tools/splat_ext/pal.py b/tools/splat_ext/pal.py new file mode 100644 index 000000000..da5286ea9 --- /dev/null +++ b/tools/splat_ext/pal.py @@ -0,0 +1,24 @@ +from splat.util import options, log +from splat.segtypes.n64.i4 import N64SegI4 +from splat.segtypes.n64.rgba16 import N64SegRgba16 +from splat.segtypes.n64.segment import N64Segment +from typing import Optional +from pathlib import Path + + +class PSXSegPal(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, yaml), + + def out_path(self) -> Optional[Path]: + return options.opts.asset_path / self.dir / self.name + + def src_path(self) -> Optional[Path]: + return options.opts.asset_path / self.dir / f"{self.name}.bin" + + def split(self, rom_bytes): + path = self.src_path() + path.parent.mkdir(parents=True, exist_ok=True) + + with open(path, "wb") as f: + f.write(rom_bytes[self.rom_start : self.rom_end])