diff --git a/port/pdextract/common.h b/port/pdextract/common.h new file mode 100644 index 000000000..50f777ad0 --- /dev/null +++ b/port/pdextract/common.h @@ -0,0 +1,71 @@ +#ifndef _COMMON_H +#define _COMMON_H +#include +#include +#include + +#define srctoh16(value) be16toh(value) +#define srctoh32(value) be32toh(value) +#define srctoh64(value) be64toh(value) + +#ifdef FORCE_BE32 +#define htodst16(value) htobe16(value) +#define htodst32(value) htobe32(value) +#define htodst64(value) htobe64(value) +#define dsttoh16(value) be16toh(value) +#define dsttoh32(value) be32toh(value) +#define dsttoh64(value) be64toh(value) +#else +#define htodst16(value) (value) +#define htodst32(value) (value) +#define htodst64(value) (value) +#define dsttoh16(value) (value) +#define dsttoh32(value) (value) +#define dsttoh64(value) (value) +#endif + +#define srctodst16(value) htodst16(srctoh16(value)) +#define srctodst32(value) htodst32(srctoh32(value)) +#define srctodst64(value) htodst64(srctoh64(value)) + +#ifdef FORCE_BE32 +#define uintptr_t uint32_t +#endif + +enum romversion { + ROMVERSION_NTSC10, + ROMVERSION_NTSCFINAL, + ROMVERSION_PALFINAL, + ROMVERSION_JPNFINAL, + ROMVERSION_NTSCBETA, + ROMVERSION_PALBETA, + ROMVERSION_UNKNOWN, +}; + +extern uint8_t *g_Rom; +extern enum romversion g_RomVersion; +extern char g_OutPath[1024]; + +typedef uint32_t n64ptr_t; + +#define ALIGN(val, size) ((val + (size - 1)) & ~(size - 1)) +#define ALIGN16(val) ((val + 0xf) & ~0xf) +#define ALIGN8(val) ((val + 0x7) & ~0x7) +#define ALIGN4(val) ((val + 0x3) & ~0x3) + +#define ARRAYCOUNT(arr) (int) (sizeof(arr) / sizeof(arr[0])) + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +FILE *openfile(char *filename); +size_t rzip_get_infsize(uint8_t *src); +int rzip_inflate(uint8_t *dst, size_t dstlen, uint8_t *src, size_t srclen); +int rzip_deflate(uint8_t *dst, size_t *dstlen, uint8_t *src, size_t srclen); + +void gbi_reset(void); +void gbi_set_segment(int segment, uint32_t offset); +void gbi_set_vtx(uint32_t src_offset, uint32_t dst_offset); +uint32_t gbi_convert_gdl(uint8_t *dst, uint32_t dstpos, uint8_t *src, uint32_t srcpos); + +#endif diff --git a/port/pdextract/ext_anims.c b/port/pdextract/ext_anims.c new file mode 100644 index 000000000..09d413200 --- /dev/null +++ b/port/pdextract/ext_anims.c @@ -0,0 +1,77 @@ +#include +#include +#include +#include "common.h" + +struct animtableentry { + uint16_t numframes; + uint16_t bytesperframe; + uint32_t data; + uint16_t headerlen; + uint8_t framelen; + uint8_t flags; +}; + +static void extract_anims_data(uint32_t romoffset, size_t len) +{ + char outfilename[1024]; + sprintf(outfilename, "%s/anims_data.bin", g_OutPath); + + FILE *fp = openfile(outfilename); + fwrite(&g_Rom[romoffset], len, 1, fp); + fclose(fp); +} + +static void extract_anims_table(uint32_t romoffset) +{ + int num_anims = srctoh32(*(uint32_t *) &g_Rom[romoffset]); + struct animtableentry *srcanims = (struct animtableentry *) &g_Rom[romoffset + 4]; + + size_t dstlen = ALIGN16(4 + num_anims * sizeof(struct animtableentry)); + uint8_t *dst = calloc(1, dstlen); + *(uint32_t *) dst = htodst32(num_anims); + struct animtableentry *dstanims = (struct animtableentry *) (dst + 4); + + for (int i = 0; i < num_anims; i++) { + dstanims[i].numframes = srctodst16(srcanims[i].numframes); + dstanims[i].bytesperframe = srctodst16(srcanims[i].bytesperframe); + dstanims[i].data = srctodst32(srcanims[i].data); + dstanims[i].headerlen = srctodst16(srcanims[i].headerlen); + dstanims[i].framelen = srcanims[i].framelen; + dstanims[i].flags = srcanims[i].flags; + } + + char outfilename[1024]; + sprintf(outfilename, "%s/anims_table.bin", g_OutPath); + + FILE *fp = openfile(outfilename); + fwrite(dst, dstlen, 1, fp); + fclose(fp); + + free(dst); +} + +void extract_anims(void) +{ + uint32_t table_offset = 0; + uint32_t data_offset = 0; + + switch (g_RomVersion) { + case ROMVERSION_NTSC10: + case ROMVERSION_NTSCFINAL: + data_offset = 0x1a15c0; + table_offset = 0x7cd1a0; + break; + case ROMVERSION_PALFINAL: + data_offset = 0x18cdc0; + table_offset = 0x7b89a0; + break; + case ROMVERSION_JPNFINAL: + data_offset = 0x190c50; + table_offset = 0x7bc830; + break; + } + + extract_anims_data(data_offset, table_offset - data_offset); + extract_anims_table(table_offset); +} diff --git a/port/pdextract/ext_audio.c b/port/pdextract/ext_audio.c new file mode 100644 index 000000000..8a6278e4f --- /dev/null +++ b/port/pdextract/ext_audio.c @@ -0,0 +1,485 @@ +#include +#include +#include +#include "common.h" + +enum { + AL_ADPCM_WAVE = 0, + AL_RAW16_WAVE +}; + +struct generic_adpcm_book { + int32_t order; + int32_t npredictors; + int16_t book[128]; +}; + +struct generic_adpcm_loop { + uint32_t start; + uint32_t end; + uint32_t count; + int16_t state[16]; +}; + +struct generic_raw_loop { + uint32_t start; + uint32_t end; + uint32_t count; +}; + +struct generic_envelope { + int32_t attackTime; + int32_t decayTime; + int32_t releaseTime; + uint8_t attackVolume; + uint8_t decayVolume; +}; + +struct generic_keymap { + uint8_t velocityMin; + uint8_t velocityMax; + uint8_t keyMin; + uint8_t keyMax; + uint8_t keyBase; + int8_t detune; +}; + +struct n64_adpcm_waveinfo { + uint32_t loop; // ptr to struct generic_adpcm_loop + uint32_t book; // ptr to struct generic_adpcm_book +}; + +struct host_adpcm_waveinfo { + uintptr_t loop; // ptr to struct generic_adpcm_loop + uintptr_t book; // ptr to struct generic_adpcm_book +}; + +struct n64_raw_waveinfo { + uint32_t loop; // ptr to struct generic_raw_loop +}; + +struct host_raw_waveinfo { + uintptr_t loop; // ptr to struct generic_raw_loop +}; + +struct n64_wavetable { + uint32_t base; + int32_t len; + uint8_t type; + uint8_t flags; + union { + struct n64_adpcm_waveinfo adpcmWave; + struct n64_raw_waveinfo rawWave; + } waveInfo; +}; + +struct host_wavetable { + uintptr_t base; + int32_t len; + uint8_t type; + uint8_t flags; + union { + struct host_adpcm_waveinfo adpcmWave; + struct host_raw_waveinfo rawWave; + } waveInfo; +}; + +struct n64_sound { + uint32_t envelope; // ptr to struct generic_envelope + uint32_t keyMap; // ptr to struct generic_keymap + uint32_t wavetable; // ptr to struct n64_wavetable + uint8_t samplePan; + uint8_t sampleVolume; + uint8_t flags; +}; + +struct host_sound { + uintptr_t envelope; // ptr to struct generic_envelope + uintptr_t keyMap; // ptr to struct generic_keymap + uintptr_t wavetable; // ptr to struct host_wavetable + uint8_t samplePan; + uint8_t sampleVolume; + uint8_t flags; +}; + +struct n64_instrument { + uint8_t volume; + uint8_t pan; + uint8_t priority; + uint8_t flags; + uint8_t tremType; + uint8_t tremRate; + uint8_t tremDepth; + uint8_t tremDelay; + uint8_t vibType; + uint8_t vibRate; + uint8_t vibDepth; + uint8_t vibDelay; + int16_t bendRange; + int16_t soundCount; + uint32_t soundArray[1]; // ptr to struct n64_sound +}; + +struct host_instrument { + uint8_t volume; + uint8_t pan; + uint8_t priority; + uint8_t flags; + uint8_t tremType; + uint8_t tremRate; + uint8_t tremDepth; + uint8_t tremDelay; + uint8_t vibType; + uint8_t vibRate; + uint8_t vibDepth; + uint8_t vibDelay; + int16_t bendRange; + int16_t soundCount; + uintptr_t soundArray[1]; // ptr to struct host_sound +}; + +struct n64_bank { + int16_t instCount; + uint8_t flags; + uint8_t pad; + int32_t sampleRate; + uint32_t percussion; // ptr to struct n64_instrument + uint32_t instArray[1]; // ptr to struct n64_instrument +}; + +struct host_bank { + int16_t instCount; + uint8_t flags; + uint8_t pad; + int32_t sampleRate; + uintptr_t percussion; // ptr to struct host_instrument + uintptr_t instArray[1]; // ptr to struct host_instrument +}; + +struct n64_bankfile { + int16_t revision; + int16_t bankCount; + uint32_t bankArray[1]; // ptr to struct n64_bank +}; + +struct host_bankfile { + int16_t revision; + int16_t bankCount; + uintptr_t bankArray[1]; // ptr to struct host_bank +}; + +static int convert_audio_envelope(uint8_t *dst, int dstpos, uint8_t *src, int srcpos) +{ + struct generic_envelope *n64_envelope = (struct generic_envelope *) &src[srcpos]; + struct generic_envelope *host_envelope = (struct generic_envelope *) &dst[dstpos]; + + dstpos += sizeof(struct generic_envelope); + + host_envelope->attackTime = srctodst32(n64_envelope->attackTime); + host_envelope->decayTime = srctodst32(n64_envelope->decayTime); + host_envelope->releaseTime = srctodst32(n64_envelope->releaseTime); + host_envelope->attackVolume = n64_envelope->attackVolume; + host_envelope->decayVolume = n64_envelope->decayVolume; + + return dstpos; +} + +static int convert_audio_keymap(uint8_t *dst, int dstpos, uint8_t *src, int srcpos) +{ + struct generic_keymap *n64_keymap = (struct generic_keymap *) &src[srcpos]; + struct generic_keymap *host_keymap = (struct generic_keymap *) &dst[dstpos]; + + dstpos += sizeof(struct generic_keymap); + + host_keymap->velocityMin = n64_keymap->velocityMin; + host_keymap->velocityMax = n64_keymap->velocityMax; + host_keymap->keyMin = n64_keymap->keyMin; + host_keymap->keyMax = n64_keymap->keyMax; + host_keymap->keyBase = n64_keymap->keyBase; + host_keymap->detune = n64_keymap->detune; + + return dstpos; +} + +static int convert_audio_adpcm_loop(uint8_t *dst, int dstpos, uint8_t *src, int srcpos) +{ + struct generic_adpcm_loop *n64_loop = (struct generic_adpcm_loop *) &src[srcpos]; + struct generic_adpcm_loop *host_loop = (struct generic_adpcm_loop *) &dst[dstpos]; + + dstpos += sizeof(struct generic_adpcm_loop); + + host_loop->start = srctodst32(n64_loop->start); + host_loop->end = srctodst32(n64_loop->end); + host_loop->count = srctodst32(n64_loop->count); + + for (int i = 0; i < ARRAYCOUNT(host_loop->state); i++) { + host_loop->state[i] = srctodst16(n64_loop->state[i]); + } + + return dstpos; +} + +static int convert_audio_adpcm_book(uint8_t *dst, int dstpos, uint8_t *src, int srcpos) +{ + struct generic_adpcm_book *n64_book = (struct generic_adpcm_book *) &src[srcpos]; + struct generic_adpcm_book *host_book = (struct generic_adpcm_book *) &dst[dstpos]; + + dstpos += sizeof(struct generic_adpcm_book); + + host_book->order = srctodst32(n64_book->order); + host_book->npredictors = srctodst32(n64_book->npredictors); + + for (int i = 0; i < ARRAYCOUNT(host_book->book); i++) { + host_book->book[i] = srctodst16(n64_book->book[i]); + } + + return dstpos; +} + +static int convert_audio_raw_loop(uint8_t *dst, int dstpos, uint8_t *src, int srcpos) +{ + struct generic_raw_loop *n64_loop = (struct generic_raw_loop *) &src[srcpos]; + struct generic_raw_loop *host_loop = (struct generic_raw_loop *) &dst[dstpos]; + + dstpos += sizeof(struct generic_raw_loop); + + host_loop->start = srctodst32(n64_loop->start); + host_loop->end = srctodst32(n64_loop->end); + host_loop->count = srctodst32(n64_loop->count); + + return dstpos; +} + +static int convert_audio_wavetable(uint8_t *dst, int dstpos, uint8_t *src, int srcpos) +{ + struct n64_wavetable *n64_wavetable = (struct n64_wavetable *) &src[srcpos]; + struct host_wavetable *host_wavetable = (struct host_wavetable *) &dst[dstpos]; + + dstpos += sizeof(struct host_wavetable); + + host_wavetable->base = srctodst32(n64_wavetable->base); + host_wavetable->len = srctodst32(n64_wavetable->len); + host_wavetable->type = n64_wavetable->type; + host_wavetable->flags = n64_wavetable->flags; + + if (host_wavetable->type == AL_ADPCM_WAVE) { + if (n64_wavetable->waveInfo.adpcmWave.loop) { + host_wavetable->waveInfo.adpcmWave.loop = htodst32(dstpos); + srcpos = srctoh32(n64_wavetable->waveInfo.adpcmWave.loop); + dstpos = convert_audio_adpcm_loop(dst, dstpos, src, srcpos); + } else { + host_wavetable->waveInfo.adpcmWave.loop = 0; + } + + if (n64_wavetable->waveInfo.adpcmWave.book) { + host_wavetable->waveInfo.adpcmWave.book = htodst32(dstpos); + srcpos = srctoh32(n64_wavetable->waveInfo.adpcmWave.book); + dstpos = convert_audio_adpcm_book(dst, dstpos, src, srcpos); + } else { + host_wavetable->waveInfo.adpcmWave.book = 0; + } + } else if (host_wavetable->type == AL_RAW16_WAVE) { + if (n64_wavetable->waveInfo.rawWave.loop) { + host_wavetable->waveInfo.rawWave.loop = htodst32(dstpos); + srcpos = srctoh32(n64_wavetable->waveInfo.rawWave.loop); + dstpos = convert_audio_raw_loop(dst, dstpos, src, srcpos); + } else { + host_wavetable->waveInfo.rawWave.loop = 0; + } + } + + return dstpos; +} + +static int convert_audio_sound(uint8_t *dst, int dstpos, uint8_t *src, int srcpos) +{ + struct n64_sound *n64_sound = (struct n64_sound *) &src[srcpos]; + struct host_sound *host_sound = (struct host_sound *) &dst[dstpos]; + + dstpos += sizeof(struct host_sound); + + if (n64_sound->envelope) { + host_sound->envelope = htodst32(dstpos); + srcpos = srctoh32(n64_sound->envelope); + dstpos = convert_audio_envelope(dst, dstpos, src, srcpos); + } else { + host_sound->envelope = 0; + } + + if (n64_sound->keyMap) { + host_sound->keyMap = htodst32(dstpos); + srcpos = srctoh32(n64_sound->keyMap); + dstpos = convert_audio_keymap(dst, dstpos, src, srcpos); + } else { + host_sound->keyMap = 0; + } + + if (n64_sound->wavetable) { + host_sound->wavetable = htodst32(dstpos); + srcpos = srctoh32(n64_sound->wavetable); + dstpos = convert_audio_wavetable(dst, dstpos, src, srcpos); + } else { + host_sound->wavetable = 0; + } + + host_sound->samplePan = n64_sound->samplePan; + host_sound->sampleVolume = n64_sound->sampleVolume; + host_sound->flags = n64_sound->flags; + + return dstpos; +} + +static int convert_audio_instrument(uint8_t *dst, int dstpos, uint8_t *src, int srcpos) +{ + struct n64_instrument *n64_instrument = (struct n64_instrument *) &src[srcpos]; + struct host_instrument *host_instrument = (struct host_instrument *) &dst[dstpos]; + int soundCount = srctoh16(n64_instrument->soundCount); + + host_instrument->volume = n64_instrument->volume; + host_instrument->pan = n64_instrument->pan; + host_instrument->priority = n64_instrument->priority; + host_instrument->flags = n64_instrument->flags; + host_instrument->tremType = n64_instrument->tremType; + host_instrument->tremRate = n64_instrument->tremRate; + host_instrument->tremDepth = n64_instrument->tremDepth; + host_instrument->tremDelay = n64_instrument->tremDelay; + host_instrument->vibType = n64_instrument->vibType; + host_instrument->vibRate = n64_instrument->vibRate; + host_instrument->vibDepth = n64_instrument->vibDepth; + host_instrument->vibDelay = n64_instrument->vibDelay; + host_instrument->bendRange = srctodst16(n64_instrument->bendRange); + host_instrument->soundCount = htodst16(soundCount); + + dstpos = dstpos + sizeof(struct host_instrument) + sizeof(uintptr_t) * (soundCount - 1); + + for (int i = 0; i < soundCount; i++) { + host_instrument->soundArray[i] = htodst32(dstpos); + srcpos = srctoh32(n64_instrument->soundArray[i]); + dstpos = convert_audio_sound(dst, dstpos, src, srcpos); + } + + return dstpos; +} + +static int convert_audio_bank(uint8_t *dst, int dstpos, uint8_t *src, int srcpos) +{ + struct n64_bank *n64_bank = (struct n64_bank *) &src[srcpos]; + struct host_bank *host_bank = (struct host_bank *) &dst[dstpos]; + int instCount = srctoh16(n64_bank->instCount); + + host_bank->instCount = htodst16(instCount); + host_bank->flags = n64_bank->flags; + host_bank->pad = n64_bank->pad; + host_bank->sampleRate = srctodst32(n64_bank->sampleRate); + + dstpos = dstpos + sizeof(struct host_bank) + sizeof(uintptr_t) * (instCount - 1); + + if (n64_bank->percussion) { + host_bank->percussion = htodst32(dstpos); + srcpos = srctoh32(n64_bank->percussion); + dstpos = convert_audio_instrument(dst, dstpos, src, srcpos); + } else { + host_bank->percussion = 0; + } + + for (int i = 0; i < instCount; i++) { + host_bank->instArray[i] = htodst32(dstpos); + srcpos = srctoh32(n64_bank->instArray[i]); + dstpos = convert_audio_instrument(dst, dstpos, src, srcpos); + } + + return dstpos; +} + +static int convert_audio_bankfile(uint8_t *dst, int dstpos, uint8_t *src, int srcpos) +{ + struct n64_bankfile *n64_bankfile = (struct n64_bankfile *) &src[srcpos]; + struct host_bankfile *host_bankfile = (struct host_bankfile *) &dst[dstpos]; + int bankCount = srctoh16(n64_bankfile->bankCount); + + host_bankfile->revision = srctodst16(n64_bankfile->revision); + host_bankfile->bankCount = htodst16(bankCount); + + dstpos = dstpos + sizeof(struct host_bankfile) + sizeof(uintptr_t) * (bankCount - 1); + + for (int i = 0; i < bankCount; i++) { + host_bankfile->bankArray[i] = htodst32(dstpos); + srcpos = srctoh32(n64_bankfile->bankArray[i]); + dstpos = convert_audio_bank(dst, dstpos, src, srcpos); + } + + return dstpos; +} + +static void extract_audio_ctl(const char *filename, uint32_t romoffset, size_t srclen) +{ + size_t dstlen = srclen * 4; + uint8_t *src = &g_Rom[romoffset]; + uint8_t *dst = calloc(1, dstlen); + int dstpos = 0; + + dstpos = convert_audio_bankfile(dst, dstpos, src, 0); + + char outfilename[1024]; + sprintf(outfilename, "%s/%s.ctl", g_OutPath, filename); + + FILE *fp = openfile(outfilename); + fwrite(dst, ALIGN16(dstpos), 1, fp); + fclose(fp); + + free(dst); +} + +static void extract_audio_tbl(const char *filename, uint32_t romoffset, size_t len) +{ + char outfilename[1024]; + sprintf(outfilename, "%s/%s.tbl", g_OutPath, filename); + + FILE *fp = openfile(outfilename); + fwrite(&g_Rom[romoffset], len, 1, fp); + fclose(fp); +} + +void extract_audio(void) +{ + uint32_t sfx_ctl = 0; + uint32_t sfx_tbl = 0; + uint32_t sfx_end = 0; + + uint32_t seq_ctl = 0; + uint32_t seq_tbl = 0; + uint32_t seq_end = 0; + + switch (g_RomVersion) { + case ROMVERSION_NTSC10: + case ROMVERSION_NTSCFINAL: + sfx_ctl = 0x80a250; + sfx_tbl = 0x839dd0; + sfx_end = 0xcfbf30; + seq_ctl = 0xcfbf30; + seq_tbl = 0xd05f90; + seq_end = 0xe82000; + break; + case ROMVERSION_PALFINAL: + sfx_ctl = 0x7f87e0; + sfx_tbl = 0x828360; + sfx_end = 0xcea4c0; + seq_ctl = 0xcea4c0; + seq_tbl = 0xcf4520; + seq_end = 0xe70590; + break; + case ROMVERSION_JPNFINAL: + sfx_ctl = 0x7fc670; + sfx_tbl = 0x82c1f0; + sfx_end = 0xcee350; + seq_ctl = 0xcee350; + seq_tbl = 0xcf83b0; + seq_end = 0xe74420; + break; + } + + extract_audio_ctl("sfx", sfx_ctl, sfx_tbl - sfx_ctl); + extract_audio_tbl("sfx", sfx_tbl, sfx_end - sfx_tbl); + extract_audio_ctl("seq", seq_ctl, seq_tbl - seq_ctl); + extract_audio_tbl("seq", seq_tbl, seq_end - seq_tbl); +} diff --git a/port/pdextract/ext_banners.c b/port/pdextract/ext_banners.c new file mode 100644 index 000000000..dd9b3370e --- /dev/null +++ b/port/pdextract/ext_banners.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include "common.h" + +void extract_banner(const char *filename, uint32_t romoffset, size_t len) +{ + char outfilename[1024]; + sprintf(outfilename, "%s/%s.bin", g_OutPath, filename); + + FILE *fp = openfile(outfilename); + fwrite(&g_Rom[romoffset], len, 1, fp); + fclose(fp); +} + +void extract_banners(void) +{ + uint32_t accessingpak = 0; + uint32_t copyright = 0; + + switch (g_RomVersion) { + case ROMVERSION_NTSC10: + case ROMVERSION_NTSCFINAL: + copyright = 0x1ffea20; + accessingpak = 0x1fff550; + break; + case ROMVERSION_PALFINAL: + copyright = 0x1ff5500; + accessingpak = 0x1ff6030; + break; + case ROMVERSION_JPNFINAL: + copyright = 0x1ffd6b0; + accessingpak = 0x1ffe1e0; + break; + } + + extract_banner("copyright", copyright, 0xb30); + extract_banner("accessingpak", accessingpak, 0x8b0); +} diff --git a/port/pdextract/ext_file_audio.c b/port/pdextract/ext_file_audio.c new file mode 100644 index 000000000..3411034fa --- /dev/null +++ b/port/pdextract/ext_file_audio.c @@ -0,0 +1,14 @@ +#include +#include +#include +#include "common.h" + +void extract_file_audio(char *filename, uint32_t romoffset, size_t len) +{ + char outfilename[1024]; + sprintf(outfilename, "%s/files/%s", g_OutPath, filename); + + FILE *fp = openfile(outfilename); + fwrite(&g_Rom[romoffset], len, 1, fp); + fclose(fp); +} diff --git a/port/pdextract/ext_file_bg.c b/port/pdextract/ext_file_bg.c new file mode 100644 index 000000000..ec8a15a07 --- /dev/null +++ b/port/pdextract/ext_file_bg.c @@ -0,0 +1,500 @@ +#include +#include +#include +#include +#include "common.h" + +/** + * 4 bytes decompressed size of primary data + * 4 bytes compressed size of section 1 in its entirety + * 4 bytes compressed size of primary data + * Section 1: + * Primary: (zipped) + * 4 bytes null + * 4 bytes pointer to room table + * 4 bytes pointer to portal table + * 4 bytes pointer to bgcmds + * 4 bytes pointer to lights table + * 4 bytes null + * (room table) + * (portal table) + * (bgcmds) + * (lights table) + * room 1 (zipped) + * room 2 (zipped) + * ... + * Section 2: + * 2 bytes decompressed size of section (mask with 0x7fff) + * 2 bytes compressed size of section + * Texture ID list (zipped) + * Section 3: + * 2 bytes decompressed size of section (mask with 0x7fff) + * 2 bytes compressed size of section + * Zipped: + * (room bbox table) + * (list of roomgfxdata sizes) + * (list of light counts per room) + */ + +struct fileheader { + uint32_t primary_infsize; + uint32_t section1_cmpsize; + uint32_t primary_cmpsize; +}; + +struct sectionheader { + uint16_t infsize; + uint16_t cmpsize; +}; + +struct n64_primaryheader { + uint32_t unused1; + uint32_t ptr_rooms; + uint32_t ptr_portals; + uint32_t ptr_bgcmds; + uint32_t ptr_lights; + uint32_t unused2; +}; + +struct host_primaryheader { + uintptr_t unused1; + uintptr_t ptr_rooms; + uintptr_t ptr_portals; + uintptr_t ptr_bgcmds; + uintptr_t ptr_lights; + uintptr_t unused2; +}; + +struct n64_room { + uint32_t ptr_gfxdata; + uint32_t pos[3]; + uint8_t br_light_min; + uint8_t br_light_max; +}; + +struct host_room { + uintptr_t ptr_gfxdata; + uint32_t pos[3]; + uint8_t br_light_min; + uint8_t br_light_max; +}; + +struct portal { + uint16_t verticesoffset; + int16_t roomnum1; + int16_t roomnum2; + uint8_t flags; +}; + +struct portalvertices { + uint8_t count; + uint32_t vertices[1][3]; +}; + +struct bgcmd { + uint8_t type; + uint8_t len; + int32_t param; +}; + +struct light { + uint16_t roomnum; + uint16_t colour; + uint8_t brightness; + uint8_t sparkable : 1; + uint8_t healthy : 1; + uint8_t on : 1; + uint8_t sparking : 1; + uint8_t vulnerable : 1; + uint8_t brightnessmult; + int8_t dirx; + int8_t diry; + int8_t dirz; + int16_t bbox[4][3]; +}; + +int m_NumRooms; + +uint16_t m_AllocSizes[512]; + +static void convert_primary_rooms(uint8_t *dst, uint32_t *dstpos, uint8_t *src, uint32_t *srcpos) +{ + struct n64_room *n64_rooms = (struct n64_room *) &src[*srcpos]; + struct host_room *host_rooms = (struct host_room *) &dst[*dstpos]; + + m_NumRooms = 0; + + for (int i = 1; n64_rooms[i].ptr_gfxdata != 0; i++) { + m_NumRooms++; + } + + for (int i = 0; i < m_NumRooms + 1; i++) { + host_rooms[i].ptr_gfxdata = 0; // Not known at this point + host_rooms[i].pos[0] = srctodst32(n64_rooms[i].pos[0]); + host_rooms[i].pos[1] = srctodst32(n64_rooms[i].pos[1]); + host_rooms[i].pos[2] = srctodst32(n64_rooms[i].pos[2]); + host_rooms[i].br_light_min = n64_rooms[i].br_light_min; + host_rooms[i].br_light_max = n64_rooms[i].br_light_max; + } + + *srcpos += sizeof(*n64_rooms) * (m_NumRooms + 1); + *dstpos += sizeof(*host_rooms) * (m_NumRooms + 1); +} + +static void convert_primary_portals(uint8_t *dst, uint32_t *dstpos, uint8_t *src, uint32_t *srcpos) +{ + struct portal *n64_portals = (struct portal *) &src[*srcpos]; + struct portal *host_portals = (struct portal *) &dst[*dstpos]; + + // Count portals + int numportals = 0; + + for (int i = 0; n64_portals[i].verticesoffset != 0; i++) { + numportals++; + } + + // Convert portals + for (int i = 0; i < numportals; i++) { + host_portals[i].verticesoffset = srctodst16(n64_portals[i].verticesoffset); + host_portals[i].roomnum1 = srctodst16(n64_portals[i].roomnum1); + host_portals[i].roomnum2 = srctodst16(n64_portals[i].roomnum2); + host_portals[i].flags = n64_portals[i].flags; + } + + *srcpos += sizeof(*n64_portals) * (numportals + 1); + *dstpos += sizeof(*host_portals) * (numportals + 1); + + // Convert portal vertices + uint8_t *n64_vtxdata = &src[*srcpos]; + uint8_t *host_vtxdata = &dst[*dstpos]; + + for (int i = 0; i < numportals; i++) { + struct portalvertices *n64_pvertices = (struct portalvertices*) &n64_vtxdata[*srcpos]; + struct portalvertices *host_pvertices = (struct portalvertices*) &host_vtxdata[*dstpos]; + + host_pvertices->count = n64_pvertices->count; + + for (int j = 0; j < host_pvertices->count; j++) { + host_pvertices->vertices[j][0] = srctodst32(n64_pvertices->vertices[j][0]); + host_pvertices->vertices[j][1] = srctodst32(n64_pvertices->vertices[j][1]); + host_pvertices->vertices[j][2] = srctodst32(n64_pvertices->vertices[j][2]); + } + + *srcpos += 4 + host_pvertices->count * 12; + *dstpos += 4 + host_pvertices->count * 12; + } +} + +static void convert_primary_bgcmds(uint8_t *dst, uint32_t *dstpos, uint8_t *src, uint32_t *srcpos) +{ + struct bgcmd *n64_cmds = (struct bgcmd *) &src[*srcpos]; + struct bgcmd *host_cmds = (struct bgcmd *) &dst[*dstpos]; + int num_cmds = 0; + + for (int i = 0; n64_cmds[i].type != 0; i++) { + num_cmds++; + } + + num_cmds++; + + for (int i = 0; i < num_cmds; i++) { + host_cmds[i].type = n64_cmds[i].type; + host_cmds[i].len = n64_cmds[i].len; + host_cmds[i].param = srctodst32(n64_cmds[i].param); + } + + *srcpos += sizeof(*n64_cmds) * num_cmds; + *dstpos += sizeof(*host_cmds) * num_cmds; +} + +static void convert_primary_lights(uint8_t *dst, uint32_t *dstpos, uint8_t *src, uint32_t *srcpos, uint32_t end) +{ + struct light *n64_lights = (struct light *) &src[*srcpos]; + struct light *host_lights = (struct light *) &dst[*dstpos]; + int num_lights = (end - *srcpos) / sizeof(struct light); + + for (int i = 0; i < num_lights; i++) { + host_lights[i].roomnum = srctodst16(n64_lights[i].roomnum); + host_lights[i].colour = srctodst16(n64_lights[i].colour); + host_lights[i].brightness = n64_lights[i].brightness; + host_lights[i].sparkable = n64_lights[i].sparkable; + host_lights[i].healthy = n64_lights[i].healthy; + host_lights[i].on = n64_lights[i].on; + host_lights[i].sparking = n64_lights[i].sparking; + host_lights[i].vulnerable = n64_lights[i].vulnerable; + host_lights[i].brightnessmult = n64_lights[i].brightnessmult; + host_lights[i].dirx = n64_lights[i].dirx; + host_lights[i].diry = n64_lights[i].diry; + host_lights[i].dirz = n64_lights[i].dirz; + + for (int j = 0; j < 4; j++) { + host_lights[i].bbox[j][0] = srctodst16(n64_lights[i].bbox[j][0]); + host_lights[i].bbox[j][1] = srctodst16(n64_lights[i].bbox[j][1]); + host_lights[i].bbox[j][2] = srctodst16(n64_lights[i].bbox[j][2]); + } + } + + *srcpos += sizeof(*n64_lights) * num_lights; + *dstpos += sizeof(*host_lights) * num_lights; +} + +static uint32_t convert_section1_roomgfxdata(uint8_t *dst, uint32_t dstpos, uint8_t *src, uint32_t srcpos) +{ + return dstpos; +} + +static size_t sum(uint8_t *ptr, uint8_t *end) +{ + size_t sum = 0; + + while (ptr < end) { + sum = (sum + *ptr) & 0xffffffff; + ptr++; + } + + return sum; +} + +static uint32_t convert_section1(uint8_t *dst, uint32_t dstpos, uint8_t *src, uint32_t srcpos, struct fileheader *n64_header) +{ + struct fileheader *host_header = (struct fileheader *) &dst[dstpos]; + dstpos += sizeof(*host_header); + + // Unzip primary + size_t infsize = srctoh32(n64_header->primary_infsize); + uint8_t *srcbin = calloc(1, infsize); + uint8_t *dstbin = calloc(1, infsize * 2); + uint32_t srcbinpos = 0; + uint32_t dstbinpos = 0; + + int ret = rzip_inflate(srcbin, infsize, &src[srcpos], srctoh32(n64_header->primary_cmpsize)); + + if (ret < 0) { + fprintf(stderr, "Unable to inflate BG primary data: %d\n", ret); + exit(EXIT_FAILURE); + } + + // Convert primary + struct host_primaryheader *host_primary_header = (struct host_primaryheader *) &dstbin[dstbinpos]; + srcbinpos += sizeof(struct n64_primaryheader); + dstbinpos += sizeof(*host_primary_header); + + host_primary_header->unused1 = 0; + host_primary_header->unused2 = 0; + + host_primary_header->ptr_rooms = dstbinpos; + convert_primary_rooms(dstbin, &dstbinpos, srcbin, &srcbinpos); + + host_primary_header->ptr_portals = dstbinpos; + convert_primary_portals(dstbin, &dstbinpos, srcbin, &srcbinpos); + + host_primary_header->ptr_bgcmds = dstbinpos; + convert_primary_bgcmds(dstbin, &dstbinpos, srcbin, &srcbinpos); + + host_primary_header->ptr_lights = dstbinpos; + convert_primary_lights(dstbin, &dstbinpos, srcbin, &srcbinpos, infsize); + + // Convert room gfxdata + uint32_t n64_primary_diff = n64_header->primary_infsize - n64_header->primary_cmpsize; + struct n64_room *n64_rooms = (struct n64_room *) &src[sizeof(*n64_header)]; + struct host_room *host_rooms = (struct host_room *) &dst[dstbinpos]; + + uint8_t *roomgfxbuf = calloc(1, 1024 * 1024); + uint8_t *allcmp = calloc(1, 1024 * 1024); + int roomgfxbufpos = 0; + int cmppos = 0; + + //for (int i = 0; i < m_NumRooms; i++) { + // host_rooms[i].ptr_gfxdata = dstbinpos + cmppos; + + // srcpos = srctoh32(n64_rooms[i].ptr_gfxdata) - n64_primary_diff; + // roomgfxbufpos = convert_section1_roomgfxdata(roomgfxbuf, 0, src, srcpos); + + // size_t ziplen = 0; + // ret = rzip_deflate(&allcmp[cmppos], &ziplen, roomgfxbuf, roomgfxbufpos); + + // if (ret < 0) { + // fprintf(stderr, "Unable to compress BG roomgfxdata for room 0x%x: %d\n", i, ret); + // exit(EXIT_FAILURE); + // } + + // ziplen = ALIGN16(ziplen); + // cmppos += ziplen; + //} + + // Zip primary + size_t ziplen = 0; + + printf("dstbin:%d = %p\n", __LINE__, dstbin); + printf("dstpos:%d = %d\n", __LINE__, dstpos); + printf("dstbinpos:%d = %d\n", __LINE__, dstbinpos); + ret = rzip_deflate(&dst[dstpos], &ziplen, dstbin, dstbinpos); + + if (ret < 0) { + fprintf(stderr, "Unable to compress BG primary data: %d\n", ret); + exit(EXIT_FAILURE); + } + + printf("ziplen:%d = %d\n", __LINE__, ziplen); + ziplen = ALIGN16(ziplen); + dstpos += ziplen; + + // Paste compressed roomgfxdata after it + memcpy(&dst[dstpos], allcmp, cmppos); + dstpos += cmppos; + + free(roomgfxbuf); + free(allcmp); + free(srcbin); + free(dstbin); + + host_header->primary_infsize = dstbinpos; + host_header->section1_cmpsize = ziplen + cmppos; + host_header->primary_cmpsize = ziplen; + + return dstpos; +} + +static void convert_section2_texturenums(uint8_t *dst, uint32_t *dstpos, uint8_t *src, uint32_t *srcpos, uint32_t srclen) +{ + uint16_t *src_ids = (uint16_t *) &src[*srcpos]; + uint16_t *dst_ids = (uint16_t *) &dst[*dstpos]; + int count = srclen / sizeof(uint16_t); + + for (int i = 0; i < count; i++) { + dst_ids[i] = srctodst16(src_ids[i]); + } + + *srcpos += srclen; + *dstpos += srclen; +} + +static void convert_section3_bboxes(uint8_t *dst, uint32_t *dstpos, uint8_t *src, uint32_t *srcpos) +{ + int16_t *src_bboxes = (int16_t *) &src[*srcpos]; + int16_t *dst_bboxes = (int16_t *) &dst[*dstpos]; + + for (int i = 0; i < m_NumRooms; i++) { + dst_bboxes[i * 6 + 0] = srctodst16(src_bboxes[i * 6 + 0]); + dst_bboxes[i * 6 + 1] = srctodst16(src_bboxes[i * 6 + 1]); + dst_bboxes[i * 6 + 2] = srctodst16(src_bboxes[i * 6 + 2]); + dst_bboxes[i * 6 + 3] = srctodst16(src_bboxes[i * 6 + 3]); + dst_bboxes[i * 6 + 4] = srctodst16(src_bboxes[i * 6 + 4]); + dst_bboxes[i * 6 + 5] = srctodst16(src_bboxes[i * 6 + 5]); + } + + *srcpos += sizeof(int16_t) * 6 * (m_NumRooms - 1); + *dstpos += sizeof(int16_t) * 6 * (m_NumRooms - 1); +} + +static void convert_section3_allocsizes(uint8_t *dst, uint32_t *dstpos, uint8_t *src, uint32_t *srcpos) +{ + uint16_t *dst_sizes = (uint16_t *) &dst[*dstpos]; + + for (int i = 0; i < m_NumRooms; i++) { + dst_sizes[i] = m_AllocSizes[i]; + } + + *srcpos += sizeof(uint16_t) * (m_NumRooms - 1); + *dstpos += sizeof(uint16_t) * (m_NumRooms - 1); +} + +static void convert_section3_lightcounts(uint8_t *dst, uint32_t *dstpos, uint8_t *src, uint32_t *srcpos) +{ + memcpy(&dst[*dstpos], &src[*srcpos], m_NumRooms); + + *srcpos += (m_NumRooms - 1); + *dstpos += (m_NumRooms - 1); +} + +static uint32_t convert_zipped_section(int section_num, uint8_t *dst, uint32_t dstpos, uint8_t *src, uint32_t srcpos, struct sectionheader *n64_header) +{ + struct sectionheader *host_header = (struct sectionheader *) &dst[dstpos]; + dstpos += sizeof(*host_header); + + // Unzip + size_t infsize = rzip_get_infsize(&src[srcpos]); + uint8_t *srcbin = calloc(1, infsize); + uint8_t *dstbin = calloc(1, infsize); + uint32_t srcbinpos = 0; + uint32_t dstbinpos = 0; + + int ret = rzip_inflate(srcbin, infsize, &src[srcpos], srctoh16(n64_header->cmpsize)); + + if (ret < 0) { + fprintf(stderr, "Unable to inflate BG section %d: %d\n", section_num, ret); + exit(EXIT_FAILURE); + } + + // Convert + if (section_num == 2) { + convert_section2_texturenums(dstbin, &dstbinpos, srcbin, &srcbinpos, infsize); + } else if (section_num == 3) { + convert_section3_bboxes(dstbin, &dstbinpos, srcbin, &srcbinpos); + convert_section3_allocsizes(dstbin, &dstbinpos, srcbin, &srcbinpos); + convert_section3_lightcounts(dstbin, &dstbinpos, srcbin, &srcbinpos); + } + + // Zip + size_t ziplen = 0; + + ret = rzip_deflate(&dst[dstpos], &ziplen, dstbin, dstbinpos); + + if (ret < 0) { + fprintf(stderr, "Unable to compress BG section %d: %d\n", section_num, ret); + exit(EXIT_FAILURE); + } + + ziplen = ALIGN16(ziplen); + + host_header->infsize = dstbinpos; + host_header->cmpsize = ziplen; + + dstpos += ziplen; + + free(srcbin); + free(dstbin); + + return dstpos; +} + +void extract_file_bg(char *filename, uint32_t romoffset, size_t len) +{ + if (0) { + if (strcmp(filename, "bgdata/bg_mp5.seg") != 0) { + return; + } + } + return; + + size_t dstlen = len * 2; + uint8_t *dst = calloc(1, dstlen); + uint32_t dstpos = 0; + + printf("--------------------------------------------------------------------------------\n"); + printf("-- %s\n", filename); + + uint8_t *src = &g_Rom[romoffset]; + struct fileheader *n64_fileheader = (struct fileheader *) src; + uint32_t n64_section2_start = sizeof(*n64_fileheader) + srctoh32(n64_fileheader->section1_cmpsize); + struct sectionheader *n64_section2header = (struct sectionheader *) &src[n64_section2_start]; + uint32_t n64_section3_start = n64_section2_start + sizeof(*n64_section2header) + (srctoh16(n64_section2header->cmpsize) & 0x7fff); + struct sectionheader *n64_section3header = (struct sectionheader *) &src[n64_section3_start]; + + printf("section2_start 0x%x\n", n64_section2_start); + printf("section3_start 0x%x\n", n64_section3_start); + + dstpos = convert_section1(dst, dstpos, src, sizeof(*n64_fileheader), n64_fileheader); + dstpos = convert_zipped_section(2, dst, dstpos, src, n64_section2_start + sizeof(*n64_section2header), n64_section2header); + dstpos = convert_zipped_section(3, dst, dstpos, src, n64_section3_start + sizeof(*n64_section3header), n64_section3header); + dstpos = ALIGN16(dstpos); + + char outfilename[1024]; + sprintf(outfilename, "%s/files/%s", g_OutPath, filename); + + FILE *fp = openfile(outfilename); + fwrite(dst, dstpos, 1, fp); + fclose(fp); + + free(dst); +} diff --git a/port/pdextract/ext_file_lang.c b/port/pdextract/ext_file_lang.c new file mode 100644 index 000000000..471cba49e --- /dev/null +++ b/port/pdextract/ext_file_lang.c @@ -0,0 +1,110 @@ +#include +#include +#include +#include "common.h" + +static int get_next_nonzero(uint8_t *src, uint32_t offset, size_t len) +{ + uint32_t *ptr = (uint32_t *) &src[offset]; + uint32_t *end = (uint32_t *) &src[len]; + + while (ptr < end) { + if (*ptr != 0) { + return srctoh32(*ptr); + } + + ptr++; + } + + return 0; +} + +static int get_num_strings(uint8_t *src, size_t len) +{ + uint32_t ptr_table_len = get_next_nonzero(src, 0, len); + + if (ptr_table_len) { + return ptr_table_len / sizeof(uint32_t); + } + + return 1; +} + +void extract_file_lang(char *filename, uint32_t romoffset, size_t srclen) +{ + // Unzip it + size_t infsize = rzip_get_infsize(&g_Rom[romoffset]); + uint8_t *src = malloc(infsize); + + int ret = rzip_inflate(src, infsize, &g_Rom[romoffset], srclen); + + if (ret < 0) { + fprintf(stderr, "%s: Unable to inflate file: %d\n", filename, ret); + exit(EXIT_FAILURE); + } + + // Convert it + uint32_t *src_offsets = (uint32_t *) src; + size_t src_ptr_table_len = srctoh32(src_offsets[0]); + size_t src_str_table_len = infsize - src_ptr_table_len; + int num_strings = get_num_strings(src, srclen); + size_t dst_ptr_table_len = num_strings * sizeof(uintptr_t); + size_t dst_str_table_len = src_str_table_len; + + uint8_t *dst = calloc(1, dst_ptr_table_len + dst_str_table_len + 0x20); + int cur_dst_offset = dst_ptr_table_len; + + uintptr_t *dst_offsets = (uintptr_t *) dst; + + for (int i = 0; i < num_strings; i++) { + uint32_t src_offset = srctoh32(src_offsets[i]); + + if (src_offset) { + // Write pointer + dst_offsets[i] = htodst32(cur_dst_offset); + + // Write string + uint32_t end = get_next_nonzero(src, (i + 1) * 4, num_strings * 4); + + if (!end) { + end = infsize; + } + + size_t len = end - src_offset; + len = ALIGN4(len); + memcpy(&dst[cur_dst_offset], &src[src_offset], len); + + cur_dst_offset += len; + } else { + // Write pointer + dst_offsets[i] = 0; + } + } + + cur_dst_offset = ALIGN16(cur_dst_offset); + + // Zip it + uint8_t *zipped = calloc(1, cur_dst_offset); + size_t ziplen = cur_dst_offset; + + ret = rzip_deflate(zipped, &ziplen, dst, cur_dst_offset); + + if (ret < 0) { + fprintf(stderr, "%s: Unable to compress file: %d\n", filename, ret); + exit(EXIT_FAILURE); + } + + ziplen = ALIGN16(ziplen); + + // Write it + char outfilename[1024]; + sprintf(outfilename, "%s/files/%s", g_OutPath, filename); + + FILE *fp = openfile(outfilename); + fwrite(zipped, ziplen, 1, fp); + fclose(fp); + + free(zipped); + free(dst); + free(src); +} diff --git a/port/pdextract/ext_file_model.c b/port/pdextract/ext_file_model.c new file mode 100644 index 000000000..aef347484 --- /dev/null +++ b/port/pdextract/ext_file_model.c @@ -0,0 +1,952 @@ +#include +#include +#include +#include "common.h" + +enum contenttype { + /* 0*/ CT_MODELDEF, + /* 1*/ CT_NODE, + /* 2*/ CT_TEXCONFIG, + /* 3*/ CT_TEXDATA, + /* 4*/ CT_PARTS, + /* 5*/ CT_VTXCOL, + /* 6*/ CT_GDL, + /* 7*/ CT_RODATA_CHRINFO, + /* 8*/ CT_RODATA_POSITION, + /* 9*/ CT_RODATA_GUNDL, + /*10*/ CT_RODATA_DISTANCE, + /*11*/ CT_RODATA_REORDER, + /*12*/ CT_RODATA_BBOX, + /*13*/ CT_RODATA_CHRGUNFIRE, + /*14*/ CT_RODATA_11, + /*15*/ CT_RODATA_TOGGLE, + /*16*/ CT_RODATA_POSITIONHELD, + /*17*/ CT_RODATA_STARGUNFIRE, + /*18*/ CT_RODATA_HEADSPOT, + /*19*/ CT_RODATA_DL, + /*20*/ CT_RODATA_19, +}; + +struct marker { + uint32_t src_offset; + uint32_t dst_offset; + uint32_t parent_src_offset; + enum contenttype type; +}; + +struct alignconfig { + int before; + int after; +}; + +struct alignconfig m_AlignConfigs[] = { + /* 0*/ { 16, 4 }, + /* 1*/ { 4, 4 }, + /* 2*/ { 4, 4 }, + /* 3*/ { 8, 8 }, + /* 4*/ { 4, 4 }, + /* 5*/ { 4, 8 }, + /* 6*/ { 8, 8 }, + /* 7*/ { 4, 4 }, + /* 8*/ { 4, 4 }, + /* 9*/ { 8, 4 }, + /*10*/ { 4, 8 }, + /*11*/ { 4, 4 }, + /*12*/ { 4, 4 }, + /*13*/ { 4, 4 }, + /*14*/ { 4, 4 }, + /*15*/ { 4, 4 }, + /*16*/ { 4, 4 }, + /*17*/ { 8, 8 }, + /*18*/ { 4, 4 }, + /*19*/ { 8, 8 }, + /*20*/ { 4, 4 }, +}; + +struct marker m_Markers[1024]; +int m_NumMarkers; + +#define MODELNODETYPE_CHRINFO 0x01 +#define MODELNODETYPE_POSITION 0x02 +#define MODELNODETYPE_GUNDL 0x04 +#define MODELNODETYPE_05 0x05 +#define MODELNODETYPE_DISTANCE 0x08 +#define MODELNODETYPE_REORDER 0x09 +#define MODELNODETYPE_BBOX 0x0a +#define MODELNODETYPE_0B 0x0b +#define MODELNODETYPE_CHRGUNFIRE 0x0c +#define MODELNODETYPE_0D 0x0d +#define MODELNODETYPE_0E 0x0e +#define MODELNODETYPE_0F 0x0f +#define MODELNODETYPE_11 0x11 +#define MODELNODETYPE_TOGGLE 0x12 +#define MODELNODETYPE_POSITIONHELD 0x15 +#define MODELNODETYPE_STARGUNFIRE 0x16 +#define MODELNODETYPE_HEADSPOT 0x17 +#define MODELNODETYPE_DL 0x18 +#define MODELNODETYPE_19 0x19 +#define MODELNODETYPE_0100 0x0100 +#define MODELNODETYPE_0200 0x0200 + +struct src_modeldef { + uint32_t ptr_rootnode; + uint32_t ptr_skel; + uint32_t ptr_parts; + int16_t numparts; + int16_t nummatrices; + uint32_t scale; + uint16_t rwdatalen; + uint16_t numtexconfigs; + uint32_t ptr_texconfigs; +}; + +struct dst_modeldef { + uintptr_t ptr_rootnode; + uintptr_t ptr_skel; + uintptr_t ptr_parts; + int16_t numparts; + int16_t nummatrices; + uint32_t scale; + uint16_t rwdatalen; + uint16_t numtexconfigs; + uintptr_t ptr_texconfigs; +}; + +struct src_modelnode { + uint16_t type; + uint32_t ptr_rodata; + uint32_t ptr_parent; + uint32_t ptr_next; + uint32_t ptr_prev; + uint32_t ptr_child; +}; + +struct dst_modelnode { + uint16_t type; + uintptr_t ptr_rodata; + uintptr_t ptr_parent; + uintptr_t ptr_next; + uintptr_t ptr_prev; + uintptr_t ptr_child; +}; + +struct generic_rodata_chrinfo { + uint16_t animpart; + int16_t mtxindex; + uint32_t unk04; + uint16_t rwdataindex; +}; + +struct generic_rodata_position { + uint32_t pos[3]; + uint16_t part; + int16_t mtxindexes[3]; + uint32_t drawdist; +}; + +struct src_rodata_gundl { + uint32_t ptr_opagdl; + uint32_t ptr_xlugdl; + uint32_t ptr_baseaddr; + uint32_t ptr_vertices; + int16_t numvertices; + int16_t unk12; +}; + +struct dst_rodata_gundl { + uintptr_t ptr_opagdl; + uintptr_t ptr_xlugdl; + uintptr_t ptr_baseaddr; + uintptr_t ptr_vertices; + int16_t numvertices; + int16_t unk12; +}; + +struct src_rodata_distance { + uint32_t near; + uint32_t far; + uint32_t ptr_target; + uint16_t rwdataindex; +}; + +struct dst_rodata_distance { + uint32_t near; + uint32_t far; + uintptr_t ptr_target; + uint16_t rwdataindex; +}; + +struct src_rodata_reorder { + uint32_t unk00; + uint32_t unk04; + uint32_t unk08; + uint32_t unk0c[3]; + uint32_t ptr_node_unk18; + uint32_t ptr_node_unk1c; + int16_t side; + uint16_t rwdataindex; +}; + +struct dst_rodata_reorder { + uint32_t unk00; + uint32_t unk04; + uint32_t unk08; + uint32_t unk0c[3]; + uintptr_t ptr_node_unk18; + uintptr_t ptr_node_unk1c; + int16_t side; + uint16_t rwdataindex; +}; + +struct generic_rodata_bbox { + int32_t hitpart; + uint32_t bbox[6]; +}; + +struct src_rodata_chrgunfire { + uint32_t pos[3]; + uint32_t dim[3]; + uint32_t ptr_texture; + uint32_t unk1c; + uint16_t rwdataindex; + uint32_t ptr_baseaddr; +}; + +struct dst_rodata_chrgunfire { + uint32_t pos[3]; + uint32_t dim[3]; + uintptr_t ptr_texture; + uint32_t unk1c; + uint16_t rwdataindex; + uintptr_t ptr_baseaddr; +}; + +struct src_rodata_type11 { + uint32_t unk00; + uint32_t unk04; + uint32_t unk08; + uint32_t unk0c; + uint32_t unk10; + uint32_t ptr_unk14; +}; + +struct dst_rodata_type11 { + uint32_t unk00; + uint32_t unk04; + uint32_t unk08; + uint32_t unk0c; + uint32_t unk10; + uintptr_t ptr_unk14; +}; + +struct src_rodata_toggle { + uint32_t ptr_target; + uint16_t rwdataindex; +}; + +struct dst_rodata_toggle { + uintptr_t ptr_target; + uint16_t rwdataindex; +}; + +struct generic_rodata_positionheld { + uint32_t pos[3]; + int16_t mtxindex; + uint32_t unk10; +}; + +struct src_rodata_stargunfire { + uint32_t unk00; + uint32_t ptr_vertices; + uint32_t ptr_gdl; + uint32_t ptr_baseaddr; +}; + +struct dst_rodata_stargunfire { + uint32_t unk00; + uintptr_t ptr_vertices; + uintptr_t ptr_gdl; + uintptr_t ptr_baseaddr; +}; + +struct generic_rodata_headspot { + uint16_t rwdataindex; +}; + +struct src_rodata_dl { + uint32_t ptr_opagdl; + uint32_t ptr_xlugdl; + uint32_t ptr_colours; + uint32_t ptr_vertices; // colours follow this array + int16_t numvertices; + int16_t mcount; + uint16_t rwdataindex; + uint16_t numcolours; +}; + +struct dst_rodata_dl { + uintptr_t ptr_opagdl; + uintptr_t ptr_xlugdl; + uintptr_t ptr_colours; + uintptr_t ptr_vertices; // colours follow this array + int16_t numvertices; + int16_t mcount; + uint16_t rwdataindex; + uint16_t numcolours; +}; + +struct generic_rodata_type19 { + uint32_t numvertices; + uint32_t vertices[3]; +}; + +struct src_texconfig { + uint32_t ptr; + uint8_t width; + uint8_t height; + uint8_t level; + uint8_t format; + uint8_t depth; + uint8_t s; + uint8_t t; + uint8_t unk0b; +}; + +struct dst_texconfig { + uintptr_t ptr; + uint8_t width; + uint8_t height; + uint8_t level; + uint8_t format; + uint8_t depth; + uint8_t s; + uint8_t t; + uint8_t unk0b; +}; + +static struct marker *find_marker(uint32_t src_offset) +{ + for (int i = 0; i < m_NumMarkers; i++) { + if (m_Markers[i].src_offset == src_offset) { + return &m_Markers[i]; + } + } + + return NULL; +} + +static void set_marker(uint32_t src_offset, enum contenttype type, uint32_t parent_src_offset) +{ + if (src_offset == 0) { + return; + } + + src_offset &= 0x00ffffff; + + if (find_marker(src_offset)) { + return; + } + + if (m_NumMarkers >= ARRAYCOUNT(m_Markers)) { + fprintf(stderr, "Marker limit exceeded\n"); + exit(EXIT_FAILURE); + } + + m_Markers[m_NumMarkers].src_offset = src_offset; + m_Markers[m_NumMarkers].type = type; + m_Markers[m_NumMarkers].parent_src_offset = parent_src_offset; + m_NumMarkers++; +} + +enum contenttype m_NodeTypeToContentType[] = { + /*0x00*/ -1, + /*0x01*/ CT_RODATA_CHRINFO, + /*0x02*/ CT_RODATA_POSITION, + /*0x03*/ -1, + /*0x04*/ CT_RODATA_GUNDL, + /*0x05*/ -1, + /*0x06*/ -1, + /*0x07*/ -1, + /*0x08*/ CT_RODATA_DISTANCE, + /*0x09*/ CT_RODATA_REORDER, + /*0x0a*/ CT_RODATA_BBOX, + /*0x0b*/ -1, + /*0x0c*/ CT_RODATA_CHRGUNFIRE, + /*0x0d*/ -1, + /*0x0e*/ -1, + /*0x0f*/ -1, + /*0x10*/ -1, + /*0x11*/ CT_RODATA_11, + /*0x12*/ CT_RODATA_TOGGLE, + /*0x13*/ -1, + /*0x14*/ -1, + /*0x15*/ CT_RODATA_POSITIONHELD, + /*0x16*/ CT_RODATA_STARGUNFIRE, + /*0x17*/ CT_RODATA_HEADSPOT, + /*0x18*/ CT_RODATA_DL, + /*0x19*/ CT_RODATA_19, +}; + +static void populate_markers(uint8_t *src) +{ + m_NumMarkers = 0; + + set_marker(0x05000000, CT_MODELDEF, 0); + + for (int i = 0; i < m_NumMarkers; i++) { + struct marker *marker = &m_Markers[i]; + void *src_thing = &src[marker->src_offset]; + + switch (marker->type) { + case CT_MODELDEF: + struct src_modeldef *src_modeldef = src_thing; + int num_texconfigs = srctoh16(src_modeldef->numtexconfigs); + uint32_t texconfigpos = srctoh32(src_modeldef->ptr_texconfigs); + set_marker(srctoh32(src_modeldef->ptr_rootnode), CT_NODE, marker->src_offset); + set_marker(srctoh32(src_modeldef->ptr_parts), CT_PARTS, marker->src_offset); + + for (int i = 0; i < num_texconfigs; i++) { + set_marker(texconfigpos + sizeof(struct src_texconfig) * i, CT_TEXCONFIG, marker->src_offset); + } + break; + case CT_NODE: + struct src_modelnode *src_node = src_thing; + uint32_t node_type = srctoh16(src_node->type) & 0xff; + set_marker(srctoh32(src_node->ptr_rodata), m_NodeTypeToContentType[node_type], marker->src_offset); + set_marker(srctoh32(src_node->ptr_parent), CT_NODE, marker->src_offset); + set_marker(srctoh32(src_node->ptr_next), CT_NODE, marker->src_offset); + set_marker(srctoh32(src_node->ptr_prev), CT_NODE, marker->src_offset); + set_marker(srctoh32(src_node->ptr_child), CT_NODE, marker->src_offset); + break; + case CT_TEXCONFIG: + struct src_texconfig *src_texconfig = src_thing; + if ((srctoh32(src_texconfig->ptr) & 0xff000000) == 0x05000000) { + set_marker(srctoh32(src_texconfig->ptr), CT_TEXDATA, marker->src_offset); + } + break; + case CT_PARTS: + struct src_modeldef *src_modeldef2 = (struct src_modeldef *) src; + uint32_t *src_parts = (uint32_t *) src_thing; + int num_parts = srctoh16(src_modeldef2->numparts); + + for (int i = 0; i < num_parts; i++) { + set_marker(srctoh32(src_parts[i]), CT_NODE, marker->src_offset); + } + break; + case CT_RODATA_CHRINFO: + break; + case CT_RODATA_POSITION: + break; + case CT_RODATA_GUNDL: + struct src_rodata_gundl *src_gundl = src_thing; + set_marker(srctoh32(src_gundl->ptr_opagdl), CT_GDL, marker->src_offset); + set_marker(srctoh32(src_gundl->ptr_xlugdl), CT_GDL, marker->src_offset); + set_marker(srctoh32(src_gundl->ptr_vertices), CT_VTXCOL, marker->src_offset); + break; + case CT_RODATA_DISTANCE: + struct src_rodata_distance *src_dist = src_thing; + set_marker(srctoh32(src_dist->ptr_target), CT_NODE, marker->src_offset); + break; + case CT_RODATA_REORDER: + struct src_rodata_reorder *src_reorder = src_thing; + set_marker(srctoh32(src_reorder->ptr_node_unk18), CT_NODE, marker->src_offset); + set_marker(srctoh32(src_reorder->ptr_node_unk1c), CT_NODE, marker->src_offset); + break; + case CT_RODATA_CHRGUNFIRE: + struct src_rodata_chrgunfire *src_chrgunfire = src_thing; + set_marker(srctoh32(src_chrgunfire->ptr_texture), CT_TEXCONFIG, marker->src_offset); + break; + case CT_RODATA_TOGGLE: + struct src_rodata_toggle *src_toggle = src_thing; + set_marker(srctoh32(src_toggle->ptr_target), CT_NODE, marker->src_offset); + break; + case CT_RODATA_STARGUNFIRE: + struct src_rodata_stargunfire *src_stargunfire = src_thing; + set_marker(srctoh32(src_stargunfire->ptr_vertices), CT_VTXCOL, marker->src_offset); + set_marker(srctoh32(src_stargunfire->ptr_gdl), CT_GDL, marker->src_offset); + break; + case CT_RODATA_DL: + struct src_rodata_dl *src_dl = src_thing; + set_marker(srctoh32(src_dl->ptr_opagdl), CT_GDL, marker->src_offset); + set_marker(srctoh32(src_dl->ptr_xlugdl), CT_GDL, marker->src_offset); + set_marker(srctoh32(src_dl->ptr_colours), CT_VTXCOL, marker->src_offset); + set_marker(srctoh32(src_dl->ptr_vertices), CT_VTXCOL, marker->src_offset); + break; + case CT_TEXDATA: + case CT_VTXCOL: + case CT_GDL: + case CT_RODATA_BBOX: + case CT_RODATA_11: + case CT_RODATA_POSITIONHELD: + case CT_RODATA_HEADSPOT: + case CT_RODATA_19: + break; + } + } +} + +static void sort_markers(void) +{ + for (int i = 0; i < m_NumMarkers - 1; i++) { + uint32_t min_offset = 0xffffffff; + int min_index = -1; + + for (int j = i + 1; j < m_NumMarkers; j++) { + if (m_Markers[j].src_offset < min_offset) { + min_offset = m_Markers[j].src_offset; + min_index = j; + } + } + + if (min_index >= 0 && m_Markers[min_index].src_offset < m_Markers[i].src_offset) { + struct marker tmp = m_Markers[i]; + m_Markers[i] = m_Markers[min_index]; + m_Markers[min_index] = tmp; + } + } +} + +static uint32_t convert_content(uint8_t *dst, uint8_t *src, uint32_t src_file_len) +{ + uint32_t dstpos = 0; + + for (int i = 0; i < m_NumMarkers; i++) { + struct marker *marker = &m_Markers[i]; + void *src_thing = &src[marker->src_offset]; + uint32_t src_end = i < m_NumMarkers - 1 ? m_Markers[i + 1].src_offset : src_file_len; + uint32_t src_len = src_end - marker->src_offset; + + dstpos = ALIGN(dstpos, m_AlignConfigs[marker->type].before); + + marker->dst_offset = dstpos; + void *dst_thing = &dst[dstpos]; + + switch (marker->type) { + case CT_MODELDEF: + struct src_modeldef *src_modeldef = src_thing; + struct dst_modeldef *dst_modeldef = dst_thing; + dst_modeldef->ptr_skel = srctodst32(src_modeldef->ptr_skel); + dst_modeldef->numparts = srctodst16(src_modeldef->numparts); + dst_modeldef->nummatrices = srctodst16(src_modeldef->nummatrices); + dst_modeldef->scale = srctodst32(src_modeldef->scale); + dst_modeldef->rwdatalen = srctodst16(src_modeldef->rwdatalen); + dst_modeldef->numtexconfigs = srctodst16(src_modeldef->numtexconfigs); + dstpos += sizeof(*dst_modeldef); + break; + case CT_NODE: + struct src_modelnode *src_node = src_thing; + struct dst_modelnode *dst_node = dst_thing; + dst_node->type = srctodst16(src_node->type); + dstpos += sizeof(*dst_node); + break; + case CT_TEXCONFIG: + struct src_texconfig *src_texconfig = src_thing; + struct dst_texconfig *dst_texconfig = dst_thing; + + while (src_len >= sizeof(*src_texconfig)) { + if ((srctoh32(src_texconfig->ptr) & 0xff000000) != 0x05000000) { + dst_texconfig->ptr = srctodst32(src_texconfig->ptr); + } + + dst_texconfig->width = src_texconfig->width; + dst_texconfig->height = src_texconfig->height; + dst_texconfig->level = src_texconfig->level; + dst_texconfig->format = src_texconfig->format; + dst_texconfig->depth = src_texconfig->depth; + dst_texconfig->s = src_texconfig->s; + dst_texconfig->t = src_texconfig->t; + dst_texconfig->unk0b = src_texconfig->unk0b; + + dstpos += sizeof(*dst_texconfig); + src_len -= sizeof(*src_texconfig); + src_texconfig++; + dst_texconfig++; + } + break; + case CT_TEXDATA: + memcpy(dst_thing, src_thing, src_len); + dstpos += src_len; + break; + case CT_PARTS: + struct src_modeldef *src_modeldef2 = (struct src_modeldef *) src; + uint32_t *src_parts = (uint32_t *) src_thing; + uintptr_t *dst_parts = (uintptr_t *) dst_thing; + int num_parts = srctoh16(src_modeldef2->numparts); + uint16_t *src_nums = (uint16_t *) &src_parts[num_parts]; + uint16_t *dst_nums = (uint16_t *) &dst_parts[num_parts]; + + for (int i = 0; i < num_parts; i++) { + dst_nums[i] = srctodst16(src_nums[i]); + } + dstpos += num_parts * sizeof(uintptr_t) + num_parts * sizeof(uint16_t); + if (num_parts) { + dstpos = ALIGN8(dstpos); + } + break; + case CT_VTXCOL: + memcpy(dst_thing, src_thing, src_len); + dstpos += src_len; + break; + case CT_GDL: + struct marker *parent = find_marker(marker->parent_src_offset); + uint32_t src_vtx; + uint32_t dst_vtx; + + if (parent->type == CT_RODATA_GUNDL) { + struct src_rodata_gundl *src_rodata = (struct src_rodata_gundl *) &src[parent->src_offset]; + struct dst_rodata_gundl *dst_rodata = (struct dst_rodata_gundl *) &dst[parent->dst_offset]; + src_vtx = srctoh32(src_rodata->ptr_vertices) & 0x00ffffff; + dst_vtx = dsttoh32(dst_rodata->ptr_vertices) & 0x00ffffff; + } else if (parent->type == CT_RODATA_STARGUNFIRE) { + struct src_rodata_stargunfire *src_rodata = (struct src_rodata_stargunfire *) &src[parent->src_offset]; + struct dst_rodata_stargunfire *dst_rodata = (struct dst_rodata_stargunfire *) &dst[parent->dst_offset]; + src_vtx = srctoh32(src_rodata->ptr_vertices) & 0x00ffffff; + dst_vtx = dsttoh32(dst_rodata->ptr_vertices) & 0x00ffffff; + } else if (parent->type == CT_RODATA_DL) { + struct src_rodata_dl *src_rodata = (struct src_rodata_dl *) &src[parent->src_offset]; + struct dst_rodata_dl *dst_rodata = (struct dst_rodata_dl *) &dst[parent->dst_offset]; + src_vtx = srctoh32(src_rodata->ptr_vertices) & 0x00ffffff; + dst_vtx = dsttoh32(dst_rodata->ptr_vertices) & 0x00ffffff; + } + + gbi_set_vtx(src_vtx, dst_vtx); + gbi_set_segment(0x04, dst_vtx); + gbi_set_segment(0x05, 0); + dstpos = gbi_convert_gdl(dst, dstpos, src, marker->src_offset); + break; + case CT_RODATA_CHRINFO: + struct generic_rodata_chrinfo *src_chrinfo = src_thing; + struct generic_rodata_chrinfo *dst_chrinfo = dst_thing; + dst_chrinfo->animpart = srctodst16(src_chrinfo->animpart); + dst_chrinfo->mtxindex = srctodst16(src_chrinfo->mtxindex); + dst_chrinfo->unk04 = srctodst32(src_chrinfo->unk04); + dst_chrinfo->rwdataindex = srctodst16(src_chrinfo->rwdataindex); + dstpos += sizeof(*dst_chrinfo); + break; + case CT_RODATA_POSITION: + struct generic_rodata_position *src_position = src_thing; + struct generic_rodata_position *dst_position = dst_thing; + dst_position->pos[0] = srctodst32(src_position->pos[0]); + dst_position->pos[1] = srctodst32(src_position->pos[1]); + dst_position->pos[2] = srctodst32(src_position->pos[2]); + dst_position->part = srctodst16(src_position->part); + dst_position->mtxindexes[0] = srctodst16(src_position->mtxindexes[0]); + dst_position->mtxindexes[1] = srctodst16(src_position->mtxindexes[1]); + dst_position->mtxindexes[2] = srctodst16(src_position->mtxindexes[2]); + dst_position->drawdist = srctodst32(src_position->drawdist); + dstpos += sizeof(*dst_position); + break; + case CT_RODATA_GUNDL: + struct src_rodata_gundl *src_gundl = src_thing; + struct dst_rodata_gundl *dst_gundl = dst_thing; + dst_gundl->ptr_vertices = 0; + dst_gundl->numvertices = srctodst16(src_gundl->numvertices); + dst_gundl->unk12 = srctodst16(src_gundl->unk12); + dstpos += sizeof(*dst_gundl); + break; + case CT_RODATA_DISTANCE: + struct src_rodata_distance *src_dist = src_thing; + struct dst_rodata_distance *dst_dist = dst_thing; + dst_dist->near = srctodst32(src_dist->near); + dst_dist->far = srctodst32(src_dist->far); + dst_dist->rwdataindex = srctodst16(src_dist->rwdataindex); + dstpos += sizeof(*dst_dist); + break; + case CT_RODATA_REORDER: + struct src_rodata_reorder *src_reorder = src_thing; + struct dst_rodata_reorder *dst_reorder = dst_thing; + dst_reorder->unk00 = srctodst32(src_reorder->unk00); + dst_reorder->unk04 = srctodst32(src_reorder->unk04); + dst_reorder->unk08 = srctodst32(src_reorder->unk08); + dst_reorder->unk0c[0] = srctodst32(src_reorder->unk0c[0]); + dst_reorder->unk0c[1] = srctodst32(src_reorder->unk0c[1]); + dst_reorder->unk0c[2] = srctodst32(src_reorder->unk0c[2]); + dst_reorder->side = srctodst16(src_reorder->side); + dst_reorder->rwdataindex = srctodst16(src_reorder->rwdataindex); + dstpos += sizeof(*dst_reorder); + break; + case CT_RODATA_BBOX: + struct generic_rodata_bbox *src_bbox = src_thing; + struct generic_rodata_bbox *dst_bbox = dst_thing; + dst_bbox->hitpart = srctodst32(src_bbox->hitpart); + dst_bbox->bbox[0] = srctodst32(src_bbox->bbox[0]); + dst_bbox->bbox[1] = srctodst32(src_bbox->bbox[1]); + dst_bbox->bbox[2] = srctodst32(src_bbox->bbox[2]); + dst_bbox->bbox[3] = srctodst32(src_bbox->bbox[3]); + dst_bbox->bbox[4] = srctodst32(src_bbox->bbox[4]); + dst_bbox->bbox[5] = srctodst32(src_bbox->bbox[5]); + dstpos += sizeof(*dst_bbox); + break; + case CT_RODATA_CHRGUNFIRE: + struct src_rodata_chrgunfire *src_chrgunfire = src_thing; + struct dst_rodata_chrgunfire *dst_chrgunfire = dst_thing; + dst_chrgunfire->pos[0] = srctodst32(src_chrgunfire->pos[0]); + dst_chrgunfire->pos[1] = srctodst32(src_chrgunfire->pos[1]); + dst_chrgunfire->pos[2] = srctodst32(src_chrgunfire->pos[2]); + dst_chrgunfire->dim[0] = srctodst32(src_chrgunfire->dim[0]); + dst_chrgunfire->dim[1] = srctodst32(src_chrgunfire->dim[1]); + dst_chrgunfire->dim[2] = srctodst32(src_chrgunfire->dim[2]); + dst_chrgunfire->unk1c = srctodst32(src_chrgunfire->unk1c); + dst_chrgunfire->rwdataindex = srctodst16(src_chrgunfire->rwdataindex); + dst_chrgunfire->ptr_baseaddr = 0; + dstpos += sizeof(*dst_chrgunfire); + break; + case CT_RODATA_11: + struct src_rodata_type11 *src_type11 = src_thing; + struct dst_rodata_type11 *dst_type11 = dst_thing; + dst_type11->unk00 = srctodst32(src_type11->unk00); + dst_type11->unk04 = srctodst32(src_type11->unk04); + dst_type11->unk08 = srctodst32(src_type11->unk08); + dst_type11->unk0c = srctodst32(src_type11->unk0c); + dst_type11->unk10 = srctodst32(src_type11->unk10); + dst_type11->ptr_unk14 = srctodst32(src_type11->ptr_unk14); // Not read by game engine + dstpos += sizeof(*dst_type11); + break; + case CT_RODATA_TOGGLE: + struct src_rodata_toggle *src_toggle = src_thing; + struct dst_rodata_toggle *dst_toggle = dst_thing; + dst_toggle->rwdataindex = srctodst16(src_toggle->rwdataindex); + dstpos += sizeof(*dst_toggle); + break; + case CT_RODATA_POSITIONHELD: + struct generic_rodata_positionheld *src_posheld = src_thing; + struct generic_rodata_positionheld *dst_posheld = dst_thing; + dst_posheld->pos[0] = srctodst32(src_posheld->pos[0]); + dst_posheld->pos[1] = srctodst32(src_posheld->pos[1]); + dst_posheld->pos[2] = srctodst32(src_posheld->pos[2]); + dst_posheld->mtxindex = srctodst16(src_posheld->mtxindex); + dst_posheld->unk10 = srctodst32(src_posheld->unk10); + dstpos += sizeof(*dst_posheld); + break; + case CT_RODATA_STARGUNFIRE: + struct src_rodata_stargunfire *src_stargunfire = src_thing; + struct dst_rodata_stargunfire *dst_stargunfire = dst_thing; + dst_stargunfire->unk00 = srctodst32(src_stargunfire->unk00); + dstpos += sizeof(*dst_stargunfire); + break; + case CT_RODATA_HEADSPOT: + struct generic_rodata_headspot *src_headspot = src_thing; + struct generic_rodata_headspot *dst_headspot = dst_thing; + dst_headspot->rwdataindex = srctodst16(src_headspot->rwdataindex); + dstpos += sizeof(*dst_headspot); + break; + case CT_RODATA_DL: + struct src_rodata_dl *src_dl = src_thing; + struct dst_rodata_dl *dst_dl = dst_thing; + dst_dl->numvertices = srctodst16(src_dl->numvertices); + dst_dl->mcount = srctodst16(src_dl->mcount); + dst_dl->rwdataindex = srctodst16(src_dl->rwdataindex); + dst_dl->numcolours = srctodst16(src_dl->numcolours); + dstpos += sizeof(*dst_dl); + break; + case CT_RODATA_19: + struct generic_rodata_type19 *src_type19 = src_thing; + struct generic_rodata_type19 *dst_type19 = dst_thing; + uint32_t *src_vertices = src_thing + sizeof(uint32_t); + uint32_t *dst_vertices = dst_thing + sizeof(uint32_t); + int num_vertices = srctoh32(src_type19->numvertices); + + dst_type19->numvertices = htodst32(num_vertices); + dstpos += sizeof(uint32_t); + + for (int i = 0; i < num_vertices; i++) { + dst_vertices[i * 3 + 0] = srctodst32(src_vertices[i * 3 + 0]); + dst_vertices[i * 3 + 1] = srctodst32(src_vertices[i * 3 + 1]); + dst_vertices[i * 3 + 2] = srctodst32(src_vertices[i * 3 + 2]); + dstpos += sizeof(uint32_t) * 3; + } + break; + } + + dstpos = ALIGN(dstpos, m_AlignConfigs[marker->type].after); + } + + return dstpos; +} + +static uint32_t resolve_pointer(uint32_t src_offset) +{ + if (src_offset == 0) { + return 0; + } + + struct marker *marker = find_marker(src_offset & 0x00ffffff); + return marker ? (0x05000000 | marker->dst_offset) : 0; +} + +static void relink_pointers(uint8_t *dst, uint8_t *src) +{ + for (int i = 0; i < m_NumMarkers; i++) { + struct marker *marker = &m_Markers[i]; + void *src_thing = &src[marker->src_offset]; + void *dst_thing = &dst[marker->dst_offset]; + + switch (marker->type) { + case CT_MODELDEF: + struct src_modeldef *src_modeldef = src_thing; + struct dst_modeldef *dst_modeldef = dst_thing; + dst_modeldef->ptr_rootnode = htodst32(resolve_pointer(srctoh32(src_modeldef->ptr_rootnode))); + dst_modeldef->ptr_parts = htodst32(resolve_pointer(srctoh32(src_modeldef->ptr_parts))); + dst_modeldef->ptr_texconfigs = htodst32(resolve_pointer(srctoh32(src_modeldef->ptr_texconfigs))); + break; + case CT_NODE: + struct src_modelnode *src_node = src_thing; + struct dst_modelnode *dst_node = dst_thing; + dst_node->ptr_rodata = htodst32(resolve_pointer(srctoh32(src_node->ptr_rodata))); + dst_node->ptr_parent = htodst32(resolve_pointer(srctoh32(src_node->ptr_parent))); + dst_node->ptr_next = htodst32(resolve_pointer(srctoh32(src_node->ptr_next))); + dst_node->ptr_prev = htodst32(resolve_pointer(srctoh32(src_node->ptr_prev))); + dst_node->ptr_child = htodst32(resolve_pointer(srctoh32(src_node->ptr_child))); + break; + case CT_TEXCONFIG: + struct src_texconfig *src_texconfig = src_thing; + struct dst_texconfig *dst_texconfig = dst_thing; + if ((srctoh32(src_texconfig->ptr) & 0xff000000) == 0x05000000) { + dst_texconfig->ptr = htodst32(resolve_pointer(srctoh32(src_texconfig->ptr))); + } + break; + case CT_PARTS: + struct src_modeldef *src_modeldef2 = (struct src_modeldef *) src; + uint32_t *src_parts = (uint32_t *) src_thing; + uintptr_t *dst_parts = (uintptr_t *) dst_thing; + int num_parts = srctoh16(src_modeldef2->numparts); + + for (int i = 0; i < num_parts; i++) { + dst_parts[i] = htodst32(resolve_pointer(srctoh32(src_parts[i]))); + } + break; + case CT_RODATA_CHRINFO: + break; + case CT_RODATA_POSITION: + break; + case CT_RODATA_GUNDL: + struct src_rodata_gundl *src_gundl = src_thing; + struct dst_rodata_gundl *dst_gundl = dst_thing; + dst_gundl->ptr_opagdl = htodst32(resolve_pointer(srctoh32(src_gundl->ptr_opagdl))); + dst_gundl->ptr_xlugdl = htodst32(resolve_pointer(srctoh32(src_gundl->ptr_xlugdl))); + dst_gundl->ptr_vertices = htodst32(resolve_pointer(srctoh32(src_gundl->ptr_vertices))); + break; + case CT_RODATA_DISTANCE: + struct src_rodata_distance *src_dist = src_thing; + struct dst_rodata_distance *dst_dist = dst_thing; + dst_dist->ptr_target = htodst32(resolve_pointer(srctoh32(src_dist->ptr_target))); + break; + case CT_RODATA_REORDER: + struct src_rodata_reorder *src_reorder = src_thing; + struct dst_rodata_reorder *dst_reorder = dst_thing; + dst_reorder->ptr_node_unk18 = htodst32(resolve_pointer(srctoh32(src_reorder->ptr_node_unk18))); + dst_reorder->ptr_node_unk1c = htodst32(resolve_pointer(srctoh32(src_reorder->ptr_node_unk1c))); + break; + case CT_RODATA_CHRGUNFIRE: + struct src_rodata_chrgunfire *src_chrgunfire = src_thing; + struct dst_rodata_chrgunfire *dst_chrgunfire = dst_thing; + dst_chrgunfire->ptr_texture = htodst32(resolve_pointer(srctoh32(src_chrgunfire->ptr_texture))); + break; + case CT_RODATA_TOGGLE: + struct src_rodata_toggle *src_toggle = src_thing; + struct dst_rodata_toggle *dst_toggle = dst_thing; + dst_toggle->ptr_target = htodst32(resolve_pointer(srctoh32(src_toggle->ptr_target))); + break; + case CT_RODATA_STARGUNFIRE: + struct src_rodata_stargunfire *src_stargunfire = src_thing; + struct dst_rodata_stargunfire *dst_stargunfire = dst_thing; + dst_stargunfire->ptr_vertices = htodst32(resolve_pointer(srctoh32(src_stargunfire->ptr_vertices))); + dst_stargunfire->ptr_gdl = htodst32(resolve_pointer(srctoh32(src_stargunfire->ptr_gdl))); + break; + case CT_RODATA_DL: + struct src_rodata_dl *src_dl = src_thing; + struct dst_rodata_dl *dst_dl = dst_thing; + dst_dl->ptr_opagdl = htodst32(resolve_pointer(srctoh32(src_dl->ptr_opagdl))); + dst_dl->ptr_xlugdl = htodst32(resolve_pointer(srctoh32(src_dl->ptr_xlugdl))); + dst_dl->ptr_colours = htodst32(resolve_pointer(srctoh32(src_dl->ptr_colours))); + dst_dl->ptr_vertices = htodst32(resolve_pointer(srctoh32(src_dl->ptr_vertices))); + break; + case CT_TEXDATA: + case CT_VTXCOL: + case CT_GDL: + case CT_RODATA_BBOX: + case CT_RODATA_11: + case CT_RODATA_POSITIONHELD: + case CT_RODATA_HEADSPOT: + case CT_RODATA_19: + break; + } + } +} + +int calc_align(uint32_t value) +{ + if ((value % 16) == 0) { + return 16; + } else if ((value % 8) == 0) { + return 8; + } else if ((value % 4) == 0) { + return 4; + } else if ((value % 2) == 0) { + return 2; + } else { + return 1; + } +} + +static int convert_model(uint8_t *dst, uint8_t *src, uint32_t srclen) +{ + uint32_t dstpos; + + populate_markers(src); + sort_markers(); + + dstpos = convert_content(dst, src, srclen); + relink_pointers(dst, src); + + return dstpos; +} + +void extract_file_model(char *filename, uint32_t romoffset, size_t len) +{ + // Unzip it + size_t infsize = rzip_get_infsize(&g_Rom[romoffset]); + uint8_t *src = malloc(infsize); + + int ret = rzip_inflate(src, infsize, &g_Rom[romoffset], len); + + if (ret < 0) { + fprintf(stderr, "%s: Unable to inflate file: %d\n", filename, ret); + exit(EXIT_FAILURE); + } + + // Convert it + uint8_t *dst = calloc(1, infsize * 4); + + int dstpos = convert_model(dst, src, infsize); + + if (dstpos > infsize * 2) { + fprintf(stderr, "%s: overflow\n", filename); + exit(EXIT_FAILURE); + } + + // Zip it + uint8_t *zipped = calloc(1, dstpos); + size_t ziplen = dstpos; + + ret = rzip_deflate(zipped, &ziplen, dst, dstpos); + + if (ret < 0) { + fprintf(stderr, "%s: Unable to compress file: %d\n", filename, ret); + exit(EXIT_FAILURE); + } + + ziplen = ALIGN16(ziplen); + + // Write it + char outfilename[1024]; + sprintf(outfilename, "%s/files/%s", g_OutPath, filename); + + FILE *fp = openfile(outfilename); + fwrite(zipped, ziplen, 1, fp); + fclose(fp); + + free(zipped); + free(dst); + free(src); +} diff --git a/port/pdextract/ext_file_pads.c b/port/pdextract/ext_file_pads.c new file mode 100644 index 000000000..bfb77cc1f --- /dev/null +++ b/port/pdextract/ext_file_pads.c @@ -0,0 +1,357 @@ +#include +#include +#include +#include "common.h" + +#define PADFLAG_INTPOS 0x0001 +#define PADFLAG_UPALIGNTOX 0x0002 +#define PADFLAG_UPALIGNTOY 0x0004 +#define PADFLAG_UPALIGNTOZ 0x0008 +#define PADFLAG_UPALIGNINVERT 0x0010 +#define PADFLAG_LOOKALIGNTOX 0x0020 +#define PADFLAG_LOOKALIGNTOY 0x0040 +#define PADFLAG_LOOKALIGNTOZ 0x0080 +#define PADFLAG_LOOKALIGNINVERT 0x0100 +#define PADFLAG_HASBBOXDATA 0x0200 + +struct n64_header { + int32_t num_pads; + int32_t num_covers; + uint32_t ptr_waypoints; + uint32_t ptr_waygroups; + uint32_t ptr_cover; +}; + +struct host_header { + int32_t num_pads; + int32_t num_covers; + uintptr_t ptr_waypoints; + uintptr_t ptr_waygroups; + uintptr_t ptr_cover; +}; + +struct padheader { + uint32_t flags : 18; + uint32_t room : 10; + uint32_t liftnum : 4; +}; + +struct n64_waypoint { + int32_t padnum; + uint32_t ptr_neighbours; + int32_t groupnum; + int32_t step; +}; + +struct host_waypoint { + int32_t padnum; + uintptr_t ptr_neighbours; + int32_t groupnum; + int32_t step; +}; + +struct n64_waygroup { + uint32_t ptr_neighbours; + uint32_t ptr_waypoints; + int32_t step; +}; + +struct host_waygroup { + uintptr_t ptr_neighbours; + uintptr_t ptr_waypoints; + int32_t step; +}; + +struct coverdefinition { + uint32_t pos[3]; + uint32_t dir[3]; + uint16_t flags; + uint16_t unk1a; +}; + +static int convert_pads(uint8_t *dst, int dstpos, uint8_t *src, int srcpos, int num_pads) +{ + uint16_t *src_offsets = (uint16_t *) &src[srcpos]; + uint16_t *dst_offsets = (uint16_t *) &dst[dstpos]; + + dstpos += num_pads * sizeof(uint16_t); + + for (int i = 0; i < num_pads; i++) { + dstpos = ALIGN4(dstpos); + srcpos = srctoh16(src_offsets[i]); + + dst_offsets[i] = htodst16(dstpos); + + // Header + uint32_t n64_padheader = srctoh32(*(uint32_t *) &src[srcpos]); + struct padheader *host_padheader = (struct padheader *) &dst[dstpos]; + uint32_t flags = (n64_padheader >> 14) & 0x3ffff; + +#ifdef FORCE_BE32 + *(uint32_t *) host_padheader = htodst32(n64_padheader); +#else + host_padheader->flags = flags; + host_padheader->room = (n64_padheader >> 4) & 0x3ff; + host_padheader->liftnum = n64_padheader & 0xf; +#endif + + srcpos += sizeof(struct padheader); + dstpos += sizeof(struct padheader); + + // Position + if (flags & PADFLAG_INTPOS) { + int16_t *srcptr = (int16_t *) &src[srcpos]; + int16_t *dstptr = (int16_t *) &dst[dstpos]; + + dstptr[0] = srctodst16(srcptr[0]); + dstptr[1] = srctodst16(srcptr[1]); + dstptr[2] = srctodst16(srcptr[2]); + + srcpos += 8; + dstpos += 8; + } else { + uint32_t *srcptr = (uint32_t *) &src[srcpos]; + uint32_t *dstptr = (uint32_t *) &dst[dstpos]; + + dstptr[0] = srctodst32(srcptr[0]); + dstptr[1] = srctodst32(srcptr[1]); + dstptr[2] = srctodst32(srcptr[2]); + + srcpos += 12; + dstpos += 12; + } + + // Up + if ((flags & (PADFLAG_UPALIGNTOX | PADFLAG_UPALIGNTOY | PADFLAG_UPALIGNTOZ)) == 0) { + uint32_t *srcptr = (uint32_t *) &src[srcpos]; + uint32_t *dstptr = (uint32_t *) &dst[dstpos]; + + dstptr[0] = srctodst32(srcptr[0]); + dstptr[1] = srctodst32(srcptr[1]); + dstptr[2] = srctodst32(srcptr[2]); + + srcpos += 12; + dstpos += 12; + } + + // Look + if ((flags & (PADFLAG_LOOKALIGNTOX | PADFLAG_LOOKALIGNTOY | PADFLAG_LOOKALIGNTOZ)) == 0) { + uint32_t *srcptr = (uint32_t *) &src[srcpos]; + uint32_t *dstptr = (uint32_t *) &dst[dstpos]; + + dstptr[0] = srctodst32(srcptr[0]); + dstptr[1] = srctodst32(srcptr[1]); + dstptr[2] = srctodst32(srcptr[2]); + + srcpos += 12; + dstpos += 12; + } + + // Bbox + if (flags & PADFLAG_HASBBOXDATA) { + uint32_t *srcptr = (uint32_t *) &src[srcpos]; + uint32_t *dstptr = (uint32_t *) &dst[dstpos]; + + dstptr[0] = srctodst32(srcptr[0]); + dstptr[1] = srctodst32(srcptr[1]); + dstptr[2] = srctodst32(srcptr[2]); + dstptr[3] = srctodst32(srcptr[3]); + dstptr[4] = srctodst32(srcptr[4]); + dstptr[5] = srctodst32(srcptr[5]); + + srcpos += 4 * 6; + dstpos += 4 * 6; + } + } + + return dstpos; +} + +static int convert_waypoints(uint8_t *dst, int dstpos, uint8_t *src, int srcpos) +{ + struct n64_waypoint *n64_waypoints = (struct n64_waypoint *) &src[srcpos]; + struct host_waypoint *host_waypoints = (struct host_waypoint *) &dst[dstpos]; + int num_waypoints; + + for (num_waypoints = 0; n64_waypoints[num_waypoints].padnum != -1; num_waypoints++); + + dstpos += (num_waypoints + 1) * sizeof(struct host_waypoint); + + uint32_t *host_neighbours = (uint32_t *) &dst[dstpos]; + int n = 0; + + for (int i = 0; i < num_waypoints; i++) { + host_waypoints[i].padnum = srctodst32(n64_waypoints[i].padnum); + host_waypoints[i].ptr_neighbours = htodst32(dstpos); + host_waypoints[i].groupnum = srctodst32(n64_waypoints[i].groupnum); + host_waypoints[i].step = 0; + + uint32_t *n64_neighbours = (uint32_t *) &src[srctoh32(n64_waypoints[i].ptr_neighbours)]; + + for (int j = 0; n64_neighbours[j] != 0xffffffff; j++) { + host_neighbours[n++] = srctodst32(n64_neighbours[j]); + dstpos += 4; + } + + host_neighbours[n++] = 0xffffffff; + dstpos += 4; + } + + // Terminator + host_waypoints[num_waypoints].padnum = 0xffffffff; + host_waypoints[num_waypoints].ptr_neighbours = 0; + host_waypoints[num_waypoints].groupnum = 0; + host_waypoints[num_waypoints].step = 0; + + return dstpos; +} + +static int convert_waygroups(uint8_t *dst, int dstpos, uint8_t *src, int srcpos) +{ + struct n64_waygroup *n64_waygroups = (struct n64_waygroup *) &src[srcpos]; + struct host_waygroup *host_waygroups = (struct host_waygroup *) &dst[dstpos]; + int num_waygroups; + + for (num_waygroups = 0; n64_waygroups[num_waygroups].ptr_neighbours != 0; num_waygroups++); + + dstpos += (num_waygroups + 1) * sizeof(struct host_waygroup); + + // Waygroups and child waypoints + uint32_t *host_waypoints = (uint32_t *) &dst[dstpos]; + int n = 0; + + for (int i = 0; i < num_waygroups; i++) { + host_waygroups[i].ptr_waypoints = htodst32(dstpos); + host_waygroups[i].step = 0; + + uint32_t *n64_waypoints = (uint32_t *) &src[srctoh32(n64_waygroups[i].ptr_waypoints)]; + + for (int j = 0; n64_waypoints[j] != 0xffffffff; j++) { + host_waypoints[n++] = srctodst32(n64_waypoints[j]); + dstpos += 4; + } + + host_waypoints[n++] = 0xffffffff; + dstpos += 4; + } + + // Terminator + host_waygroups[num_waygroups].ptr_neighbours = 0; + host_waygroups[num_waygroups].ptr_waypoints = 0; + host_waygroups[num_waygroups].step = 0; + + // Waygroup neighbours + uint32_t *host_neighbours = (uint32_t *) &dst[dstpos]; + n = 0; + + for (int i = 0; i < num_waygroups; i++) { + host_waygroups[i].ptr_neighbours = htodst32(dstpos); + + uint32_t *n64_neighbours = (uint32_t *) &src[srctoh32(n64_waygroups[i].ptr_neighbours)]; + + for (int j = 0; n64_neighbours[j] != 0xffffffff; j++) { + host_neighbours[n++] = srctodst32(n64_neighbours[j]); + dstpos += 4; + } + + host_neighbours[n++] = 0xffffffff; + dstpos += 4; + } + + return dstpos; +} + +static int convert_cover(uint8_t *dst, int dstpos, uint8_t *src, int srcpos, int num_covers) +{ + struct coverdefinition *n64_covers = (struct coverdefinition *) &src[srcpos]; + struct coverdefinition *host_covers = (struct coverdefinition *) &dst[dstpos]; + + for (int i = 0; i < num_covers; i++) { + host_covers[i].pos[0] = srctodst32(n64_covers[i].pos[0]); + host_covers[i].pos[1] = srctodst32(n64_covers[i].pos[1]); + host_covers[i].pos[2] = srctodst32(n64_covers[i].pos[2]); + host_covers[i].dir[0] = srctodst32(n64_covers[i].dir[0]); + host_covers[i].dir[1] = srctodst32(n64_covers[i].dir[1]); + host_covers[i].dir[2] = srctodst32(n64_covers[i].dir[2]); + host_covers[i].flags = srctodst16(n64_covers[i].flags); + host_covers[i].unk1a = srctodst16(n64_covers[i].unk1a); + } + + dstpos += num_covers * sizeof(struct coverdefinition); + + return dstpos; +} + +static int convert_binary(uint8_t *dst, uint8_t *src) +{ + int dstpos = 0; + struct n64_header *n64_header = (struct n64_header *) src; + struct host_header *host_header = (struct host_header *) dst; + + int num_pads = srctoh32(n64_header->num_pads); + int num_covers = srctoh32(n64_header->num_covers); + host_header->num_pads = htodst32(num_pads); + host_header->num_covers = htodst32(num_covers); + + dstpos += sizeof(struct host_header); + + // Pads + dstpos = convert_pads(dst, dstpos, src, sizeof(struct n64_header), num_pads); + + // Waypoints + host_header->ptr_waypoints = htodst32(dstpos); + dstpos = convert_waypoints(dst, dstpos, src, srctoh32(n64_header->ptr_waypoints)); + + // Waygroups + host_header->ptr_waygroups = htodst32(dstpos); + dstpos = convert_waygroups(dst, dstpos, src, srctoh32(n64_header->ptr_waygroups)); + + // Cover + host_header->ptr_cover = htodst32(dstpos); + dstpos = convert_cover(dst, dstpos, src, srctoh32(n64_header->ptr_cover), num_covers); + + return dstpos; +} + +void extract_file_pads(char *filename, uint32_t romoffset, size_t len) +{ + // Unzip it + size_t infsize = rzip_get_infsize(&g_Rom[romoffset]); + uint8_t *src = malloc(infsize); + + int ret = rzip_inflate(src, infsize, &g_Rom[romoffset], len); + + if (ret < 0) { + fprintf(stderr, "%s: Unable to inflate file: %d\n", filename, ret); + exit(EXIT_FAILURE); + } + + // Convert it + uint8_t *dst = calloc(1, infsize * 2); + int dstpos = convert_binary(dst, src); + + dstpos = ALIGN16(dstpos); + + // Zip it + uint8_t *zipped = calloc(1, dstpos); + size_t ziplen = dstpos; + + ret = rzip_deflate(zipped, &ziplen, dst, dstpos); + + if (ret < 0) { + fprintf(stderr, "%s: Unable to compress file: %d\n", filename, ret); + exit(EXIT_FAILURE); + } + + // Write it + char outfilename[1024]; + sprintf(outfilename, "%s/files/%s", g_OutPath, filename); + + FILE *fp = openfile(outfilename); + fwrite(zipped, ALIGN16(ziplen), 1, fp); + fclose(fp); + + free(src); + free(dst); + free(zipped); +} diff --git a/port/pdextract/ext_file_tiles.c b/port/pdextract/ext_file_tiles.c new file mode 100644 index 000000000..f074aa731 --- /dev/null +++ b/port/pdextract/ext_file_tiles.c @@ -0,0 +1,122 @@ +#include +#include +#include +#include "common.h" + +struct tile { + uint8_t type; + uint8_t numvertices; + uint16_t flags; + uint16_t floortype; + uint8_t xmin; + uint8_t ymin; + uint8_t zmin; + uint8_t xmax; + uint8_t ymax; + uint8_t zmax; + uint16_t floorcol; +}; + +void extract_file_tiles(char *filename, uint32_t romoffset, size_t len) +{ + // Unzip it + size_t infsize = rzip_get_infsize(&g_Rom[romoffset]); + uint8_t *src = malloc(infsize); + + int ret = rzip_inflate(src, infsize, &g_Rom[romoffset], len); + + if (ret < 0) { + fprintf(stderr, "%s: Unable to inflate file: %d\n", filename, ret); + exit(EXIT_FAILURE); + } + + int num_rooms = srctoh32(*(uint32_t *) src); + + size_t src_ptr_table_len = (num_rooms + 1) * 4; + size_t dst_ptr_table_len = (num_rooms + 1) * sizeof(uintptr_t); + + uint32_t *src_offsets = (uint32_t *) &src[4]; + + size_t data_len = infsize - src_ptr_table_len - 4; + + uint8_t *dst = calloc(1, dst_ptr_table_len + data_len + 0x20); + + *(uint32_t *) dst = htodst32(num_rooms); + + uintptr_t *dst_offsets = (uintptr_t *) (dst + ALIGN(4, sizeof(uintptr_t))); + uint32_t cur_dst_offset = ALIGN(4, sizeof(uintptr_t)) + dst_ptr_table_len; + + uint32_t cur_src_offset = srctoh32(src_offsets[0]); + uint32_t end_src_offset = srctoh32(src_offsets[num_rooms]); + int room = 0; + + while (1) { + // Check if this is a new room and write the pointer offset if so + while (room < (num_rooms + 1) && srctoh32(src_offsets[room]) == cur_src_offset) { + dst_offsets[room] = htodst32(cur_dst_offset); + room++; + } + + if (cur_src_offset >= end_src_offset) { + break; + } + + // Write tile data + struct tile *n64tile = (struct tile *) &src[cur_src_offset]; + struct tile hosttile; + + hosttile.type = n64tile->type; + hosttile.numvertices = n64tile->numvertices; + hosttile.flags = srctodst16(n64tile->flags); + hosttile.floortype = srctodst16(n64tile->floortype); + hosttile.xmin = n64tile->xmin; + hosttile.ymin = n64tile->ymin; + hosttile.zmin = n64tile->zmin; + hosttile.xmax = n64tile->xmax; + hosttile.ymax = n64tile->ymax; + hosttile.zmax = n64tile->zmax; + hosttile.floorcol = srctodst16(n64tile->floorcol); + + memcpy(&dst[cur_dst_offset], &hosttile, sizeof(struct tile)); + + cur_dst_offset += sizeof(struct tile); + cur_src_offset += sizeof(struct tile); + + // Write tile vertices + for (int i = 0; i < hosttile.numvertices; i++) { + *(int16_t *) &dst[cur_dst_offset + 0] = srctodst16(*(int16_t *) &src[cur_src_offset + 0]); + *(int16_t *) &dst[cur_dst_offset + 2] = srctodst16(*(int16_t *) &src[cur_src_offset + 2]); + *(int16_t *) &dst[cur_dst_offset + 4] = srctodst16(*(int16_t *) &src[cur_src_offset + 4]); + cur_dst_offset += 6; + cur_src_offset += 6; + } + } + + cur_dst_offset = ALIGN16(cur_dst_offset); + + // Zip it + uint8_t *zipped = calloc(1, cur_dst_offset); + size_t ziplen = cur_dst_offset; + + ret = rzip_deflate(zipped, &ziplen, dst, cur_dst_offset); + + if (ret < 0) { + fprintf(stderr, "%s: Unable to compress file: %d\n", filename, ret); + exit(EXIT_FAILURE); + } + + ziplen = ALIGN16(ziplen); + + // Write it + char outfilename[1024]; + + sprintf(outfilename, "%s/files/%s", g_OutPath, filename); + + FILE *fp = openfile(outfilename); + fwrite(zipped, ziplen, 1, fp); + fclose(fp); + + free(zipped); + free(dst); + free(src); +} diff --git a/port/pdextract/ext_files.c b/port/pdextract/ext_files.c new file mode 100644 index 000000000..9f64e5031 --- /dev/null +++ b/port/pdextract/ext_files.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include "common.h" + +void extract_file_audio(char *filename, uint32_t romoffset, size_t len); +void extract_file_bg(char *filename, uint32_t romoffset, size_t len); +void extract_file_lang(char *filename, uint32_t romoffset, size_t len); +void extract_file_model(char *filename, uint32_t romoffset, size_t len); +void extract_file_pads(char *filename, uint32_t romoffset, size_t len); +void extract_file_tiles(char *filename, uint32_t romoffset, size_t len); + +static void extract_file(int filenum, uint32_t romoffset, size_t len) +{ + uint32_t name_uint32_table = 0; + + switch (g_RomVersion) { + case ROMVERSION_NTSC10: + case ROMVERSION_NTSCFINAL: + name_uint32_table = 0x1d5ca00; + break; + case ROMVERSION_PALFINAL: + name_uint32_table = 0x1d534e0; + break; + case ROMVERSION_JPNFINAL: + name_uint32_table = 0x1d58a20; + break; + } + + uint32_t name_offset = name_uint32_table + srctoh32(*(uint32_t *) &g_Rom[name_uint32_table + filenum * 4]); + + char *filename = (char *) &g_Rom[name_offset]; + + if (strstr(filename, ".seg")) { + extract_file_bg(filename, romoffset, len); + } else if (strstr(filename, "padsZ")) { + extract_file_pads(filename, romoffset, len); + } else if (strstr(filename, "tilesZ")) { + extract_file_tiles(filename, romoffset, len); + } else if (filename[0] == 'A') { + extract_file_audio(filename, romoffset, len); + } else if (filename[0] == 'C' || filename[0] == 'G' || filename[0] == 'P') { + extract_file_model(filename, romoffset, len); + } else if (filename[0] == 'L') { + extract_file_lang(filename, romoffset, len); + } else if (filename[0] == 'U') { + // Setup file - don't extract + } else { + fprintf(stderr, "Unrecognised file type: '%s'\n", filename); + exit(EXIT_FAILURE); + } +} + +void extract_files(void) +{ + size_t infsize = rzip_get_infsize(&g_Rom[0x39850]); + uint8_t *data = malloc(infsize); + + int ret = rzip_inflate(data, infsize, &g_Rom[0x39850], infsize); + + if (ret < 0) { + fprintf(stderr, "Unable to inflate data segment: %d\n", ret); + exit(EXIT_FAILURE); + } + + uint32_t offset = 0; + + switch (g_RomVersion) { + case ROMVERSION_NTSC10: + case ROMVERSION_NTSCFINAL: + offset = 0x28080; + break; + case ROMVERSION_PALFINAL: + offset = 0x28910; + break; + case ROMVERSION_JPNFINAL: + offset = 0x28800; + break; + } + + uint32_t *offsets = (uint32_t *) &data[offset]; + int i = 0; + + while (1) { + uint32_t curr = srctoh32(offsets[i]); + uint32_t next = srctoh32(offsets[i + 1]); + + if (next == 0) { + break; + } + + if (curr) { + extract_file(i, curr, next - curr); + } + + i++; + } + + free(data); +} diff --git a/port/pdextract/ext_fonts.c b/port/pdextract/ext_fonts.c new file mode 100644 index 000000000..3ff07b494 --- /dev/null +++ b/port/pdextract/ext_fonts.c @@ -0,0 +1,157 @@ +#include +#include +#include +#include +#include +#include "common.h" + +struct n64fontchar { + uint8_t index; + int8_t baseline; + uint8_t height; + uint8_t width; + int32_t kerningindex; + uint32_t pixeldata; +}; + +struct hostfontchar { + uint8_t index; + int8_t baseline; + uint8_t height; + uint8_t width; + int32_t kerningindex; + uintptr_t pixeldata; +}; + +struct n64fontcharjpn { + uint16_t index; + int8_t baseline; + uint8_t height; + uint8_t width; + int16_t kerningindex; + uint32_t pixeldata; +}; + +struct hostfontcharjpn { + uint16_t index; + int8_t baseline; + uint8_t height; + uint8_t width; + int16_t kerningindex; + uintptr_t pixeldata; +}; + +static void extract_font(const char *filename, uint32_t romoffset, size_t srclen, int num_chars) +{ + size_t dstlen = srclen - (num_chars * sizeof(struct n64fontchar)) + (num_chars * sizeof(struct hostfontchar)) + 0x20; + uint8_t *src = &g_Rom[romoffset]; + uint8_t *dst = calloc(1, dstlen); + + // Kerning table + int32_t *src_kerning_table = (int32_t *) src; + int32_t *dst_kerning_table = (int32_t *) dst; + + for (int i = 0; i < 13 * 13; i++) { + dst_kerning_table[i] = srctodst32(src_kerning_table[i]); + } + + uint32_t src_offset = ALIGN(13 * 13 * 4, sizeof(uint32_t)); + uint32_t dst_offset = ALIGN(13 * 13 * 4, sizeof(uintptr_t)); + + // Character table + if (g_RomVersion == ROMVERSION_JPNFINAL) { + struct n64fontcharjpn *src_char_table = (struct n64fontcharjpn *) &src[src_offset]; + struct hostfontcharjpn *dst_char_table = (struct hostfontcharjpn *) &dst[dst_offset]; + uint32_t diff = (dst_offset + num_chars * sizeof(struct hostfontcharjpn)) - (src_offset + num_chars * sizeof(struct n64fontcharjpn)); + + for (int i = 0; i < num_chars; i++) { + dst_char_table[i].index = srctodst16(src_char_table[i].index); + dst_char_table[i].baseline = src_char_table[i].baseline; + dst_char_table[i].height = src_char_table[i].height; + dst_char_table[i].width = src_char_table[i].width; + dst_char_table[i].kerningindex = srctodst16(src_char_table[i].kerningindex); + dst_char_table[i].pixeldata = src_char_table[i].pixeldata ? srctodst32(src_char_table[i].pixeldata) + diff : 0; + } + + src_offset += num_chars * sizeof(struct n64fontcharjpn); + dst_offset += num_chars * sizeof(struct hostfontcharjpn); + } else { + struct n64fontchar *src_char_table = (struct n64fontchar *) &src[src_offset]; + struct hostfontchar *dst_char_table = (struct hostfontchar *) &dst[dst_offset]; + uint32_t diff = (dst_offset + num_chars * sizeof(struct hostfontchar)) - (src_offset + num_chars * sizeof(struct n64fontchar)); + + for (int i = 0; i < num_chars; i++) { + dst_char_table[i].index = src_char_table[i].index; + dst_char_table[i].baseline = src_char_table[i].baseline; + dst_char_table[i].height = src_char_table[i].height; + dst_char_table[i].width = src_char_table[i].width; + dst_char_table[i].kerningindex = srctodst32(src_char_table[i].kerningindex); + dst_char_table[i].pixeldata = src_char_table[i].pixeldata ? srctodst32(src_char_table[i].pixeldata) + diff : 0; + } + + src_offset += num_chars * sizeof(struct n64fontchar); + dst_offset += num_chars * sizeof(struct hostfontchar); + } + + // Pixel data + size_t len = srclen - src_offset; + + memcpy(&dst[dst_offset], &src[src_offset], len); + + dst_offset = ALIGN16(dst_offset + len); + + // Write it + char outfilename[1024]; + sprintf(outfilename, "%s/fonts/%s.bin", g_OutPath, filename); + + FILE *fp = openfile(outfilename); + fwrite(dst, dst_offset, 1, fp); + fclose(fp); + + free(dst); +} + +struct fontdef { + const char *name; + uint32_t offsets[3]; + int pal_extra_chars; +}; + +void extract_fonts(void) +{ + struct fontdef defs[] = { + // ntsc pal jpn + {"bankgothic", {0x7f2390, 0x7ddb90, 0x7e1a20}, 0}, + {"zurich", {0x7f4930, 0x7e0130, 0x7e3fc0}, 0}, + {"tahoma", {0x7f7860, 0x7e3060, 0x7e6ef0}, 0}, + {"numeric", {0x7f8b20, 0x7e4320, 0x7e81b0}, 0}, + {"handelgothicsm", {0x7f9d30, 0x7e5530, 0x7e93c0}, 1}, + {"handelgothicxs", {0x7fbfb0, 0x7e87b0, 0x7ec640}, 1}, + {"handelgothicmd", {0x7fdd80, 0x7eae20, 0x7eecb0}, 1}, + {"handelgothiclg", {0x8008e0, 0x7eee70, 0x7f2d00}, 0}, + {"ocramd", {0x803da0, 0x7f2330, 0x7f61c0}, 0}, + {"ocralg", {0x806ac0, 0x7f5050, 0x7f8ee0}, 0}, + {"end", {0x80a250, 0x7f87e0, 0x7fc670}, 0}, + }; + + int index = 0; + + switch (g_RomVersion) { + case ROMVERSION_NTSC10: + case ROMVERSION_NTSCFINAL: + index = 0; + break; + case ROMVERSION_PALFINAL: + index = 1; + break; + case ROMVERSION_JPNFINAL: + index = 2; + break; + } + + for (int i = 0; i < ARRAYCOUNT(defs) - 1; i++) { + int num_chars = g_RomVersion == ROMVERSION_PALFINAL && defs[i].pal_extra_chars ? 135 : 94; + size_t len = defs[i + 1].offsets[index] - defs[i].offsets[index]; + extract_font(defs[i].name, defs[i].offsets[index], len, num_chars); + } +} diff --git a/port/pdextract/ext_jpnfonts.c b/port/pdextract/ext_jpnfonts.c new file mode 100644 index 000000000..ea68b0d70 --- /dev/null +++ b/port/pdextract/ext_jpnfonts.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include "common.h" + +static void extract_jpnfont(const char *filename, uint32_t romoffset, size_t len) +{ + char outfilename[1024]; + sprintf(outfilename, "%s/%s.bin", g_OutPath, filename); + + FILE *fp = openfile(outfilename); + fwrite(&g_Rom[romoffset], len, 1, fp); + fclose(fp); +} + +void extract_jpnfonts(void) +{ + switch (g_RomVersion) { + case ROMVERSION_NTSC10: + case ROMVERSION_NTSCFINAL: + extract_jpnfont("fontjpnsingle", 0x194440, 0xb020); + extract_jpnfont("fontjpnmulti", 0x19fb40, 0x1a80); + break; + case ROMVERSION_PALFINAL: + extract_jpnfont("fontjpnsingle", 0x17fc40, 0xb010); + extract_jpnfont("fontjpnmulti", 0x18b340, 0x1a80); + break; + case ROMVERSION_JPNFINAL: + extract_jpnfont("fontjpn", 0x178c40, 0x17920); + break; + } +} diff --git a/port/pdextract/ext_textures.c b/port/pdextract/ext_textures.c new file mode 100644 index 000000000..74e126163 --- /dev/null +++ b/port/pdextract/ext_textures.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include "common.h" + +struct texture { + uint32_t soundsurfacetype : 4; + uint32_t surfacetype : 4; + uint32_t dataoffset : 24; + uint32_t unk04; +}; + +static void extract_textures_data(uint32_t romoffset, size_t len) +{ + char outfilename[1024]; + sprintf(outfilename, "%s/textures_data.bin", g_OutPath); + + FILE *fp = openfile(outfilename); + fwrite(&g_Rom[romoffset], len, 1, fp); + fclose(fp); +} + +static void extract_textures_table(uint32_t romoffset, size_t len) +{ + int num_textures = len / sizeof(struct texture); + uint8_t *dst = calloc(1, len); + + struct texture *n64texes = (struct texture *) &g_Rom[romoffset]; + struct texture *hosttexes = (struct texture *) dst; + + for (int i = 0; i < num_textures; i++) { + hosttexes[i].soundsurfacetype = n64texes[i].soundsurfacetype; + hosttexes[i].surfacetype = n64texes[i].surfacetype; + hosttexes[i].dataoffset = srctodst32(n64texes[i].dataoffset); + hosttexes[i].unk04 = 0; + } + + // Write it + char outfilename[1024]; + sprintf(outfilename, "%s/textures_table.bin", g_OutPath); + + FILE *fp = openfile(outfilename); + fwrite(dst, len, 1, fp); + fclose(fp); + + free(dst); +} + +void extract_textures(void) +{ + uint32_t data_offset = 0; + uint32_t table_offset = 0; + uint32_t end = 0; + + switch (g_RomVersion) { + case ROMVERSION_NTSC10: + case ROMVERSION_NTSCFINAL: + data_offset = 0x1d65f40; + table_offset = 0x1ff7ca0; + end = 0x1ffea20; + break; + case ROMVERSION_PALFINAL: + data_offset = 0x1d5ca20; + table_offset = 0x1fee780; + end = 0x1ff5500; + break; + case ROMVERSION_JPNFINAL: + data_offset = 0x1d61f90; + table_offset = 0x1ff68f0; + end = 0x1ffd6b0; + break; + } + + extract_textures_data(data_offset, table_offset - data_offset); + extract_textures_table(table_offset, end - table_offset); +} diff --git a/port/pdextract/gbi.c b/port/pdextract/gbi.c new file mode 100644 index 000000000..a59f77871 --- /dev/null +++ b/port/pdextract/gbi.c @@ -0,0 +1,189 @@ +#include +#include +#include +#include "common.h" + +#ifdef FORCE_BE32 +#define HOST_DWORDS_PER_CMD 1 +#elif UINTPTR_MAX == 0xFFFFFFFFFFFFFFFFu +#define HOST_DWORDS_PER_CMD 2 +#else +#define HOST_DWORDS_PER_CMD 1 +#endif + +struct vtx { + int16_t x; + int16_t y; + int16_t z; + uint8_t flags; + uint8_t colour; + int16_t s; + int16_t t; +}; + +uint32_t m_Segments[16]; +uint8_t m_Seen[1024]; +uint32_t m_SrcVtxOffset; +uint32_t m_DstVtxOffset; + +void gbi_reset(void) +{ + for (int i = 0; i < ARRAYCOUNT(m_Segments); i++) { + m_Segments[i] = 0; + } + + for (int i = 0; i < ARRAYCOUNT(m_Seen); i++) { + m_Seen[i] = 0; + } + + m_SrcVtxOffset = 0; + m_DstVtxOffset = 0; +} + +void gbi_set_segment(int segment, uint32_t offset) +{ + m_Segments[segment] = offset; +} + +void gbi_set_vtx(uint32_t src_offset, uint32_t dst_offset) +{ + m_SrcVtxOffset = src_offset; + m_DstVtxOffset = dst_offset; +} + +static void gbi_convert_col(uint8_t *dst, uint32_t dstpos, int count) +{ + for (int i = 0; i < count; i++) { + int index = dstpos / 4; + + if (!m_Seen[index]) { + uint32_t *col = (uint32_t *) &dst[dstpos]; + + *col = srctodst32(*col); + + m_Seen[index] = 1; + } + + dstpos += sizeof(uint32_t); + } +} + +static void gbi_convert_vtx(uint8_t *dst, uint32_t dstpos, int count) +{ + for (int i = 0; i < count; i++) { + int index = dstpos / 4; + + if (!m_Seen[index]) { + struct vtx *vtx = (struct vtx *) &dst[dstpos]; + + vtx->x = srctodst16(vtx->x); + vtx->y = srctodst16(vtx->y); + vtx->z = srctodst16(vtx->z); + vtx->s = srctodst16(vtx->s); + vtx->t = srctodst16(vtx->t); + + m_Seen[index] = 1; + } + + dstpos += 12; + } +} + +#define CMD_IS_VTX(cmd) ((cmd & 0xff00000000000000) == 0x0400000000000000) +#define CMD_IS_DL(cmd) ((cmd & 0xff00000000000000) == 0x0600000000000000) +#define CMD_IS_COL(cmd) ((cmd & 0xff00000000000000) == 0x0700000000000000) +#define CMD_IS_ENDDL(cmd) ((cmd & 0xff00000000000000) == 0xb800000000000000) +#define CMD_IS_MOVEWORD(cmd) ((cmd & 0xff00000000000000) == 0xbc00000000000000) + +#define CMD_HAS_ADDR(cmd) CMD_IS_VTX(cmd) \ + || CMD_IS_COL(cmd) \ + || CMD_IS_MOVEWORD(cmd) + +static void gbi_convert_vtx_by_cmd(uint64_t cmd, uint8_t *dst) +{ + uint8_t segment = cmd & 0xff000000; + uint8_t offset = cmd & 0x00ffffff; + uint32_t num_bytes = (cmd >> 32) & 0xffff; + int num_vertices = num_bytes / 12; + + if (segment == 5) { + uint32_t dst_offset = offset - m_SrcVtxOffset + m_DstVtxOffset; + gbi_convert_vtx(dst, dst_offset, num_vertices); + } else { + gbi_convert_vtx(dst, m_Segments[segment] + offset, num_vertices); + } +} + +static void gbi_convert_col_by_cmd(uint64_t cmd, uint8_t *dst) +{ + uint8_t segment = cmd & 0xff000000; + uint8_t offset = cmd & 0x00ffffff; + uint32_t num_bytes = (cmd >> 32) & 0xffff; + int num_colours = num_bytes / 4; + + if (segment == 5) { + uint32_t dst_offset = offset - m_SrcVtxOffset + m_DstVtxOffset; + gbi_convert_col(dst, dst_offset, num_colours); + } else { + gbi_convert_col(dst, m_Segments[segment] + offset, num_colours); + } +} + +/** + * Segment 5 is the start of the model file. The data in these files shifts + * depending on the pointer size, so this function adjusts the offset accordingly. + */ +static uint64_t gbi_rewrite_addr(uint64_t cmd) +{ + uint8_t segment = cmd & 0xff000000; + uint8_t offset = cmd & 0x00ffffff; + + if (segment == 5) { + if (offset < m_SrcVtxOffset) { + printf("Tried to load data from offset 0x%x but segment starts at 0x%x\n", offset, m_SrcVtxOffset); + exit(EXIT_FAILURE); + } + + offset = offset - m_SrcVtxOffset + m_DstVtxOffset; + } + + return (cmd & 0xffffffffff000000) | offset; +} + +uint32_t gbi_convert_gdl(uint8_t *dst, uint32_t dstpos, uint8_t *src, uint32_t srcpos) +{ + dstpos = ALIGN8(dstpos); + + uint64_t *n64_cmd = (uint64_t *) &src[srcpos]; + uint64_t *host_cmd = (uint64_t *) &dst[dstpos]; + uint64_t cmd; + + do { + cmd = srctoh64(*n64_cmd); + +#if HOST_DWORDS_PER_CMD == 2 + if (CMD_HAS_ADDR(cmd)) { + cmd = gbi_rewrite_addr(cmd); + host_cmd[0] = htodst64(cmd & 0xffffffff00000000); + host_cmd[1] = htodst64(cmd & 0x00000000ffffffff); + } else { + host_cmd[0] = htodst64(cmd); + host_cmd[1] = 0; + } +#else + host_cmd[0] = htodst64(cmd); +#endif + dstpos += sizeof(*host_cmd) * HOST_DWORDS_PER_CMD; + + if (CMD_IS_VTX(cmd)) { + gbi_convert_vtx_by_cmd(cmd, dst); + } else if (CMD_IS_COL(cmd)) { + gbi_convert_col_by_cmd(cmd, dst); + } + + host_cmd += HOST_DWORDS_PER_CMD; + n64_cmd++; + } while (!CMD_IS_ENDDL(cmd)); + + return dstpos; +} diff --git a/port/pdextract/main.c b/port/pdextract/main.c new file mode 100644 index 000000000..c5230fe16 --- /dev/null +++ b/port/pdextract/main.c @@ -0,0 +1,173 @@ +#include +#include +#include +#include +#include "common.h" + +#define ROM_SIZE (1024 * 1024 * 32) + +uint8_t *g_Rom = NULL; +enum romversion g_RomVersion = 0; +char g_OutPath[1024] = {'\0'}; + +void extract_anims(void); +void extract_audio(void); +void extract_banners(void); +void extract_files(void); +void extract_fonts(void); +void extract_jpnfonts(void); +void extract_textures(void); + +/** + * We allow modded ROMs to be used, so we can't simply compare the ROM checksum. + */ +static enum romversion identify_rom_version(uint8_t *rom) +{ + char game_code[5]; + game_code[0] = rom[0x3b]; + game_code[1] = rom[0x3c]; + game_code[2] = rom[0x3d]; + game_code[3] = rom[0x3e]; + game_code[4] = '\0'; + + char version_byte = rom[0x3f]; + + if (strncmp((char *) &rom[0x20], "Perfect Dark DBGNTSC", 20) == 0) { + return ROMVERSION_NTSCBETA; + } + + if (strcmp(game_code, "NPDJ") == 0) { + return ROMVERSION_JPNFINAL; + } + + if (strcmp(game_code, "NPDE") == 0) { + if (version_byte == 1) { + return ROMVERSION_NTSCFINAL; + } + + if (version_byte == 0) { + return ROMVERSION_NTSC10; + } + } + + if (strcmp(game_code, "NPDP") == 0) { + if (rom[0x100f] == 0xe0) { + return ROMVERSION_PALBETA; + } + + if (rom[0x100f] == 0xf0) { + return ROMVERSION_PALFINAL; + } + } + + return ROMVERSION_UNKNOWN; +} + +static void flip_pairs(uint8_t *rom) +{ + uint16_t *ptr = (uint16_t *) rom; + + for (int i = 0; i < ROM_SIZE / 2; i++) { + ptr[i] = __bswap_16(ptr[i]); + } +} + +static void flip_words(uint8_t *rom) +{ + uint32_t *ptr = (uint32_t *) rom; + + for (int i = 0; i < ROM_SIZE / 4; i++) { + ptr[i] = __bswap_32(ptr[i]); + } +} + +static void extract_rom(char *romfile) +{ + FILE *fp = fopen(romfile, "rb"); + + if (fp == NULL) { + fprintf(stderr, "Unable to open '%s' for reading.\n", romfile); + exit(EXIT_FAILURE); + } + + fseek(fp, 0, SEEK_END); + + if (ftell(fp) != ROM_SIZE) { + fprintf(stderr, "The ROM size is not 32MB. Is this a Perfect Dark ROM?\n"); + exit(EXIT_FAILURE); + } + + fseek(fp, 0, SEEK_SET); + + g_Rom = malloc(ROM_SIZE); + fread(g_Rom, 1, ROM_SIZE, fp); + fclose(fp); + + uint32_t magic = (g_Rom[0] << 24) | (g_Rom[1] << 16) | (g_Rom[2] << 8) | g_Rom[3]; + + switch (magic) { + case 0x80371240: + break; + case 0x37804012: + flip_pairs(g_Rom); + break; + case 0x40123780: + flip_words(g_Rom); + break; + default: + fprintf(stderr, "Unable to detect ROM header. Is this an N64 ROM?\n"); + exit(EXIT_FAILURE); + break; + } + + g_RomVersion = identify_rom_version(g_Rom); + + if (g_RomVersion == ROMVERSION_NTSCBETA || g_RomVersion == ROMVERSION_PALBETA) { + fprintf(stderr, "The beta versions are not supported.\n"); + exit(EXIT_FAILURE); + } + + if (g_RomVersion == ROMVERSION_UNKNOWN) { + fprintf(stderr, "Unable to determine your Perfect Dark version. Is this a Perfect Dark ROM?\n"); + exit(EXIT_FAILURE); + } + + extract_anims(); + extract_audio(); + extract_files(); + extract_fonts(); + extract_jpnfonts(); + extract_textures(); + extract_banners(); + + free(g_Rom); + g_Rom = NULL; +} + +int main(int argc, char **argv) +{ + char *romfile = NULL; + + if (argc < 2) { + fprintf(stderr, "Usage: pd-extract [PATH]\n"); + fprintf(stderr, "Read ROMFILE, writing assets to PATH.\n"); + fprintf(stderr, "With no PATH, assume \"extracted/\".\n"); + return EXIT_FAILURE; + } + + romfile = argv[1]; + + if (argc > 2) { + strcpy(g_OutPath, argv[2]); + } else { + strcpy(g_OutPath, "extracted"); + } + + if (g_OutPath[strlen(g_OutPath) - 1] == '/') { + g_OutPath[strlen(g_OutPath) - 1] = '\0'; + } + + extract_rom(romfile); + + return EXIT_SUCCESS; +} diff --git a/port/pdextract/util.c b/port/pdextract/util.c new file mode 100644 index 000000000..8cdcb58f3 --- /dev/null +++ b/port/pdextract/util.c @@ -0,0 +1,103 @@ +#include +#include +#include +#include +#include +#include +#include + +FILE *openfile(char *filename) +{ + char path[1024]; + struct stat status; + + memcpy(path, filename, strlen(filename)); + dirname(path); + + while (stat(path, &status) == -1) { +// while (mkdir(path, 0755) == -1) { + while (mkdir(path) == -1) { + dirname(path); + } + + memcpy(path, filename, strlen(filename)); + dirname(path); + } + + FILE *fp = fopen(filename, "wb"); + + if (fp == NULL) { + fprintf(stderr, "Unable to open '%s' for writing\n", filename); + exit(EXIT_FAILURE); + } + + return fp; +} + +size_t rzip_get_infsize(uint8_t *src) +{ + if (src[0] != 0x11 || src[1] != 0x73) { + fprintf(stderr, "rzip_get_infsize: 1173 not found\n"); + exit(EXIT_FAILURE); + } + + return src[2] << 16 | (src[3] << 8) | src[4]; +} + +int rzip_inflate(uint8_t *dst, size_t dstlen, uint8_t *src, size_t srclen) +{ + if (src[0] != 0x11 || src[1] != 0x73) { + fprintf(stderr, "rzip_inflate: 1173 not found\n"); + + for (int i = 0; i < 16; i++) { + fprintf(stderr, "%02x ", src[i]); + } + + fprintf(stderr, "\n"); + + exit(EXIT_FAILURE); + } + + z_stream stream; + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.opaque = Z_NULL; + stream.avail_in = srclen - 5; + stream.next_in = &src[5]; + stream.avail_out = dstlen; + stream.next_out = dst; + + inflateInit2(&stream, -15); + int ret = inflate(&stream, Z_FINISH); + inflateEnd(&stream); + + return ret; +} + +int rzip_deflate(uint8_t *dst, size_t *dstlen, uint8_t *src, size_t srclen) +{ + dst[0] = 0x11; + dst[1] = 0x73; + dst[2] = (srclen >> 16) & 0xff; + dst[3] = (srclen >> 8) & 0xff; + dst[4] = srclen & 0xff; + + *dstlen = *dstlen - 5; + + z_stream stream; + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.opaque = Z_NULL; + stream.avail_in = srclen; + stream.next_in = src; + stream.avail_out = *dstlen; + stream.next_out = &dst[5]; + + deflateInit2(&stream, 9, Z_DEFLATED, -15, 9, Z_DEFAULT_STRATEGY); + int ret = deflate(&stream, Z_FINISH); + deflateEnd(&stream); + + *dstlen = stream.next_out - dst; + + return ret; +}