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.
This commit is contained in:
Luciano Ciccariello 2024-10-31 21:06:06 +00:00 committed by GitHub
parent c82d3726cb
commit 5a447796d6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
38 changed files with 437 additions and 381 deletions

View File

@ -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]

View File

@ -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]

View File

@ -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]

View File

@ -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]

View File

@ -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]

View File

@ -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]

View File

@ -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]

View File

@ -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]

View File

@ -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]

View File

@ -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]

View File

@ -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]

View File

@ -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]

View File

@ -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]

View File

@ -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]

1
src/boss/.gitignore vendored
View File

@ -3,6 +3,7 @@ sprites.c
e_laydef.c
e_layout.c
layers.h
palette_def.h
sprite_banks.h
tilemap_*.h
tiledef_*.h

View File

@ -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();

1
src/st/.gitignore vendored
View File

@ -3,6 +3,7 @@ sprites.c
e_laydef.c
e_layout.c
layers.h
palette_def.h
sprite_banks.h
tilemap_*.h
tiledef_*.h

View File

@ -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];

View File

@ -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"

View File

@ -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 = {

View File

@ -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"

View File

@ -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[] = {

View File

@ -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"

View File

@ -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"

View File

@ -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[] = {

View File

@ -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
})

View File

@ -38,6 +38,7 @@ type InfoAssetEntry struct {
}
type InfoSplatEntry struct {
DataRange datarange.DataRange
Kind string
Name string
Comment string
}

View File

@ -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 {

View File

@ -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

View File

@ -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 {

View File

@ -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
}

View File

@ -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 {

View File

@ -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))
}

View File

@ -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 {

View File

@ -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)
}

View File

@ -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")

View File

@ -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))
}

24
tools/splat_ext/pal.py Normal file
View File

@ -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])