1459 lines
39 KiB
C
1459 lines
39 KiB
C
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <PR/ultratypes.h>
|
|
#include <PR/gbi.h>
|
|
#include <PR/libaudio.h>
|
|
#include "platform.h"
|
|
#include "data.h"
|
|
#include "bss.h"
|
|
#include "preprocess.h"
|
|
#include "romdata.h"
|
|
#include "game/setuputils.h"
|
|
|
|
static inline f32 swapF32(f32 x) { *(u32 *)&x = PD_BE32(*(u32 *)&x); return x; }
|
|
static inline u32 swapU32(u32 x) { return PD_BE32(x); }
|
|
static inline s32 swapS32(s32 x) { return PD_BE32(x); }
|
|
static inline u16 swapU16(u16 x) { return PD_BE16(x); }
|
|
static inline s16 swapS16(s16 x) { return PD_BE16(x); }
|
|
static inline void *swapPtr(void **x) { return (void *)PD_BEPTR((uintptr_t)x); }
|
|
static inline struct coord swapCrd(struct coord crd) { crd.x = swapF32(crd.x); crd.y = swapF32(crd.y); crd.z = swapF32(crd.z); return crd; }
|
|
static inline u32 swapUnk(u32 x) { assert(0 && "unknown type"); return x; }
|
|
|
|
#define PD_SWAP_VAL(x) x = _Generic((x), \
|
|
f32: swapF32, \
|
|
u32: swapU32, \
|
|
s32: swapS32, \
|
|
u16: swapU16, \
|
|
s16: swapS16, \
|
|
struct coord: swapCrd, \
|
|
default: swapUnk \
|
|
)(x)
|
|
|
|
#define PD_SWAP_PTR(x) x = swapPtr((void *)(x))
|
|
|
|
#define PD_PTR_BASE(x, b) (void *)((u8 *)b + (u32)x)
|
|
#define PD_PTR_BASEOFS(x, b, d) (void *)((u8 *)b - d + (u32)x)
|
|
|
|
// HACK: to prevent double-swapping stuff, flag swapped offsets in a bitmap
|
|
|
|
static u8 swapmap[0x40000 >> 3];
|
|
|
|
static inline u32 alreadySwapped(const intptr_t addr) {
|
|
const u32 mask = (1 << (addr & 3));
|
|
const u32 old = swapmap[addr >> 3] & mask;
|
|
if (!old) {
|
|
swapmap[addr >> 3] |= mask;
|
|
}
|
|
return old;
|
|
}
|
|
|
|
static inline void preprocessALWaveTable(ALWaveTable *tbl, u8 *bankBase)
|
|
{
|
|
if (alreadySwapped((u8 *)tbl - bankBase)) {
|
|
return;
|
|
}
|
|
|
|
PD_SWAP_VAL(tbl->len);
|
|
PD_SWAP_PTR(tbl->base);
|
|
|
|
if (tbl->type == AL_ADPCM_WAVE) {
|
|
if (tbl->waveInfo.adpcmWave.loop ) {
|
|
PD_SWAP_PTR(tbl->waveInfo.adpcmWave.loop);
|
|
ALADPCMloop *loop = PD_PTR_BASE(tbl->waveInfo.adpcmWave.loop, bankBase);
|
|
PD_SWAP_VAL(loop->count);
|
|
PD_SWAP_VAL(loop->start);
|
|
PD_SWAP_VAL(loop->end);
|
|
for (s32 i = 0; i < 16; ++i) {
|
|
PD_SWAP_VAL(loop->state[i]);
|
|
}
|
|
}
|
|
if (tbl->waveInfo.adpcmWave.book) {
|
|
PD_SWAP_PTR(tbl->waveInfo.adpcmWave.book);
|
|
ALADPCMBook *book = PD_PTR_BASE(tbl->waveInfo.adpcmWave.book, bankBase);
|
|
PD_SWAP_VAL(book->npredictors);
|
|
PD_SWAP_VAL(book->order);
|
|
const s32 bookSize = book->order * book->npredictors * ADPCMVSIZE;
|
|
for (s32 i = 0; i < bookSize && i < 128; ++i) {
|
|
PD_SWAP_VAL(book->book[i]);
|
|
}
|
|
}
|
|
} else if (tbl->type == AL_RAW16_WAVE) {
|
|
if (tbl->waveInfo.rawWave.loop) {
|
|
PD_SWAP_PTR(tbl->waveInfo.rawWave.loop);
|
|
ALRawLoop *loop = PD_PTR_BASE(tbl->waveInfo.rawWave.loop, bankBase);
|
|
PD_SWAP_VAL(loop->count);
|
|
PD_SWAP_VAL(loop->start);
|
|
PD_SWAP_VAL(loop->end);
|
|
}
|
|
}
|
|
}
|
|
|
|
static inline void preprocessALSound(ALSound *snd, u8 *bankBase)
|
|
{
|
|
if (alreadySwapped((u8 *)snd - bankBase)) {
|
|
return;
|
|
}
|
|
|
|
if (snd->envelope) {
|
|
PD_SWAP_PTR(snd->envelope);
|
|
if (!alreadySwapped((intptr_t)snd->envelope)) {
|
|
ALEnvelope *env = PD_PTR_BASE(snd->envelope, bankBase);
|
|
PD_SWAP_VAL(env->attackTime);
|
|
PD_SWAP_VAL(env->releaseTime);
|
|
PD_SWAP_VAL(env->decayTime);
|
|
}
|
|
}
|
|
|
|
if (snd->keyMap) {
|
|
PD_SWAP_PTR(snd->keyMap);
|
|
}
|
|
|
|
if (snd->wavetable) {
|
|
PD_SWAP_PTR(snd->wavetable);
|
|
preprocessALWaveTable(PD_PTR_BASE(snd->wavetable, bankBase), bankBase);
|
|
}
|
|
}
|
|
|
|
static inline void preprocessALInstrument(ALInstrument *inst, u8 *bankBase)
|
|
{
|
|
if (alreadySwapped((u8 *)inst - bankBase)) {
|
|
return;
|
|
}
|
|
|
|
PD_SWAP_VAL(inst->bendRange);
|
|
PD_SWAP_VAL(inst->soundCount);
|
|
|
|
for (s16 i = 0; i < inst->soundCount; ++i) {
|
|
PD_SWAP_PTR(inst->soundArray[i]);
|
|
preprocessALSound(PD_PTR_BASE(inst->soundArray[i], bankBase), bankBase);
|
|
}
|
|
}
|
|
|
|
static inline void preprocessALBank(ALBank *bank, u8 *bankBase)
|
|
{
|
|
if (alreadySwapped((u8 *)bank - bankBase)) {
|
|
return;
|
|
}
|
|
|
|
PD_SWAP_VAL(bank->sampleRate);
|
|
PD_SWAP_VAL(bank->instCount);
|
|
|
|
if (bank->percussion) {
|
|
PD_SWAP_PTR(bank->percussion);
|
|
preprocessALInstrument(PD_PTR_BASE(bank->percussion, bankBase), bankBase);
|
|
}
|
|
|
|
for (s16 i = 0; i < bank->instCount; ++i) {
|
|
PD_SWAP_PTR(bank->instArray[i]);
|
|
preprocessALInstrument(PD_PTR_BASE(bank->instArray[i], bankBase), bankBase);
|
|
}
|
|
}
|
|
|
|
static inline void preprocessGfx(Gfx *gdl, u8 *base, uintptr_t ofs)
|
|
{
|
|
while (gdl) {
|
|
const s8 opcode = (s8)gdl->bytes[0];
|
|
PD_SWAP_VAL(gdl->words.w0);
|
|
PD_SWAP_VAL(gdl->words.w1);
|
|
if (opcode == (s8)G_ENDDL) {
|
|
break;
|
|
}
|
|
|
|
// mark all addresses in the DL as segmented
|
|
switch (opcode) {
|
|
case (s8)G_SETTIMG:
|
|
case (s8)G_SETCIMG:
|
|
case (s8)G_SETZIMG:
|
|
case G_MOVEMEM:
|
|
case G_MTX:
|
|
case G_VTX:
|
|
case G_COL:
|
|
case G_DL:
|
|
gdl->words.w1 |= 1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
++gdl;
|
|
}
|
|
}
|
|
|
|
static inline void preprocessVtx(Vtx *vtx)
|
|
{
|
|
PD_SWAP_VAL(vtx->x);
|
|
PD_SWAP_VAL(vtx->y);
|
|
PD_SWAP_VAL(vtx->z);
|
|
PD_SWAP_VAL(vtx->s);
|
|
PD_SWAP_VAL(vtx->t);
|
|
}
|
|
|
|
static void preprocessModelGunDL(struct modelrodata_gundl *gundl, u8 *base, u32 ofs)
|
|
{
|
|
PD_SWAP_PTR(gundl->baseaddr);
|
|
PD_SWAP_PTR(gundl->vertices);
|
|
PD_SWAP_VAL(gundl->numvertices);
|
|
PD_SWAP_VAL(gundl->unk12);
|
|
|
|
Vtx *vtx = PD_PTR_BASEOFS(gundl->vertices, base, ofs);
|
|
for (s16 i = 0; i < gundl->numvertices; ++i, ++vtx) {
|
|
preprocessVtx(vtx);
|
|
}
|
|
|
|
if (gundl->opagdl) {
|
|
PD_SWAP_PTR(gundl->opagdl);
|
|
preprocessGfx(PD_PTR_BASEOFS(gundl->opagdl, base, ofs), base, ofs);
|
|
gundl->opagdl = SEGADDR(gundl->opagdl);
|
|
}
|
|
if (gundl->xlugdl) {
|
|
PD_SWAP_PTR(gundl->xlugdl);
|
|
preprocessGfx(PD_PTR_BASEOFS(gundl->xlugdl, base, ofs), base, ofs);
|
|
gundl->xlugdl = SEGADDR(gundl->xlugdl);
|
|
}
|
|
}
|
|
|
|
static void preprocessModelDL(struct modelrodata_dl *dl, u8 *base, u32 ofs)
|
|
{
|
|
PD_SWAP_PTR(dl->colours);
|
|
PD_SWAP_PTR(dl->vertices);
|
|
|
|
PD_SWAP_VAL(dl->numvertices);
|
|
PD_SWAP_VAL(dl->numcolours);
|
|
PD_SWAP_VAL(dl->mcount);
|
|
PD_SWAP_VAL(dl->rwdataindex);
|
|
|
|
Vtx *vtx = PD_PTR_BASEOFS(dl->vertices, base, ofs);
|
|
for (s16 i = 0; i < dl->numvertices; ++i, ++vtx) {
|
|
preprocessVtx(vtx);
|
|
}
|
|
|
|
if (dl->opagdl) {
|
|
PD_SWAP_PTR(dl->opagdl);
|
|
preprocessGfx(PD_PTR_BASEOFS(dl->opagdl, base, ofs), base, ofs);
|
|
dl->opagdl = SEGADDR(dl->opagdl);
|
|
}
|
|
if (dl->xlugdl) {
|
|
PD_SWAP_PTR(dl->xlugdl);
|
|
preprocessGfx(PD_PTR_BASEOFS(dl->xlugdl, base, ofs), base, ofs);
|
|
dl->xlugdl = SEGADDR(dl->xlugdl);
|
|
}
|
|
}
|
|
|
|
static void preprocessModelNode(struct modelnode *node, u8 *base, u32 ofs)
|
|
{
|
|
while (node) {
|
|
PD_SWAP_VAL(node->type);
|
|
PD_SWAP_PTR(node->child);
|
|
PD_SWAP_PTR(node->next);
|
|
PD_SWAP_PTR(node->parent);
|
|
PD_SWAP_PTR(node->rodata);
|
|
|
|
if (node->rodata) {
|
|
union modelrodata* ro = PD_PTR_BASEOFS(node->rodata, base, ofs);
|
|
|
|
switch (node->type & 0xff) {
|
|
case MODELNODETYPE_CHRINFO:
|
|
PD_SWAP_VAL(ro->chrinfo.animpart);
|
|
PD_SWAP_VAL(ro->chrinfo.mtxindex);
|
|
PD_SWAP_VAL(ro->chrinfo.rwdataindex);
|
|
PD_SWAP_VAL(ro->chrinfo.unk04);
|
|
break;
|
|
case MODELNODETYPE_POSITION:
|
|
PD_SWAP_VAL(ro->position.drawdist);
|
|
PD_SWAP_VAL(ro->position.pos);
|
|
PD_SWAP_VAL(ro->position.part);
|
|
PD_SWAP_VAL(ro->position.mtxindex0);
|
|
PD_SWAP_VAL(ro->position.mtxindex1);
|
|
PD_SWAP_VAL(ro->position.mtxindex2);
|
|
break;
|
|
case MODELNODETYPE_GUNDL:
|
|
preprocessModelGunDL(&ro->gundl, base, ofs);
|
|
break;
|
|
case MODELNODETYPE_05:
|
|
break;
|
|
case MODELNODETYPE_DISTANCE:
|
|
PD_SWAP_VAL(ro->distance.near);
|
|
PD_SWAP_VAL(ro->distance.far);
|
|
PD_SWAP_VAL(ro->distance.rwdataindex);
|
|
PD_SWAP_PTR(ro->distance.target);
|
|
// TODO: assuming target points to one of the nodes we'll swap by following node->next
|
|
break;
|
|
case MODELNODETYPE_REORDER:
|
|
PD_SWAP_VAL(ro->reorder.unk00);
|
|
PD_SWAP_VAL(ro->reorder.unk04);
|
|
PD_SWAP_VAL(ro->reorder.unk08);
|
|
PD_SWAP_VAL(ro->reorder.unk0c[0]);
|
|
PD_SWAP_VAL(ro->reorder.unk0c[1]);
|
|
PD_SWAP_VAL(ro->reorder.unk0c[2]);
|
|
PD_SWAP_VAL(ro->reorder.rwdataindex);
|
|
PD_SWAP_VAL(ro->reorder.side);
|
|
PD_SWAP_PTR(ro->reorder.unk18);
|
|
PD_SWAP_PTR(ro->reorder.unk1c);
|
|
break;
|
|
case MODELNODETYPE_BBOX:
|
|
PD_SWAP_VAL(ro->bbox.xmin);
|
|
PD_SWAP_VAL(ro->bbox.xmax);
|
|
PD_SWAP_VAL(ro->bbox.ymin);
|
|
PD_SWAP_VAL(ro->bbox.ymax);
|
|
PD_SWAP_VAL(ro->bbox.zmin);
|
|
PD_SWAP_VAL(ro->bbox.zmax);
|
|
PD_SWAP_VAL(ro->bbox.hitpart);
|
|
break;
|
|
case MODELNODETYPE_0B:
|
|
PD_SWAP_PTR(ro->type0b.baseaddr);
|
|
PD_SWAP_VAL(ro->type0b.rwdataindex);
|
|
PD_SWAP_VAL(ro->type0b.unk00);
|
|
PD_SWAP_PTR(ro->type0b.unk3c);
|
|
// TODO: do we need to swap the rest of the words?
|
|
break;
|
|
case MODELNODETYPE_CHRGUNFIRE:
|
|
PD_SWAP_PTR(ro->chrgunfire.baseaddr);
|
|
PD_SWAP_PTR(ro->chrgunfire.texture);
|
|
PD_SWAP_VAL(ro->chrgunfire.rwdataindex);
|
|
PD_SWAP_VAL(ro->chrgunfire.pos);
|
|
PD_SWAP_VAL(ro->chrgunfire.dim);
|
|
PD_SWAP_VAL(ro->chrgunfire.unk1c);
|
|
// TODO: do we swap contents of *texture or is it part of mdl->textureconfigs[]?
|
|
break;
|
|
case MODELNODETYPE_0D:
|
|
PD_SWAP_PTR(ro->type0d.baseaddr);
|
|
PD_SWAP_PTR(ro->type0d.unk10);
|
|
PD_SWAP_PTR(ro->type0d.unk14);
|
|
// TODO: do we need to swap the rest of the words?
|
|
break;
|
|
case MODELNODETYPE_0E:
|
|
case MODELNODETYPE_0F:
|
|
break;
|
|
case MODELNODETYPE_11:
|
|
PD_SWAP_PTR(ro->type11.unk14);
|
|
// TODO: do we need to swap the rest of the words?
|
|
break;
|
|
case MODELNODETYPE_TOGGLE:
|
|
PD_SWAP_VAL(ro->toggle.rwdataindex);
|
|
PD_SWAP_PTR(ro->toggle.target);
|
|
// TODO: assuming target points to one of the nodes we'll swap by following node->next
|
|
break;
|
|
case MODELNODETYPE_POSITIONHELD:
|
|
PD_SWAP_VAL(ro->positionheld.mtxindex);
|
|
PD_SWAP_VAL(ro->positionheld.pos);
|
|
break;
|
|
case MODELNODETYPE_STARGUNFIRE:
|
|
PD_SWAP_VAL(ro->stargunfire.unk00);
|
|
PD_SWAP_PTR(ro->stargunfire.vertices);
|
|
PD_SWAP_PTR(ro->stargunfire.baseaddr);
|
|
if (ro->stargunfire.gdl) {
|
|
PD_SWAP_PTR(ro->stargunfire.gdl);
|
|
preprocessGfx(PD_PTR_BASEOFS(ro->stargunfire.gdl, base, ofs), base, ofs);
|
|
ro->stargunfire.gdl = SEGADDR(ro->stargunfire.gdl);
|
|
}
|
|
break;
|
|
case MODELNODETYPE_HEADSPOT:
|
|
PD_SWAP_VAL(ro->headspot.rwdataindex);
|
|
break;
|
|
case MODELNODETYPE_DL:
|
|
preprocessModelDL(&ro->dl, base, ofs);
|
|
break;
|
|
case 0x19:
|
|
PD_SWAP_VAL(ro->type19.numvertices);
|
|
for (s32 i = 0; i < ARRAYCOUNT(ro->type19.vertices); ++i) {
|
|
PD_SWAP_VAL(ro->type19.vertices[i]);
|
|
}
|
|
break;
|
|
default:
|
|
fprintf(stderr, "preprocessModelNode: node at %p: unknown node->type: 0x%02x\n", node, node->type & 0xff);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (node->child) {
|
|
node = PD_PTR_BASEOFS(node->child, base, ofs);
|
|
} else {
|
|
while (node) {
|
|
if (node->next) {
|
|
node = PD_PTR_BASEOFS(node->next, base, ofs);
|
|
break;
|
|
}
|
|
if (node->parent) {
|
|
node = PD_PTR_BASEOFS(node->parent, base, ofs);
|
|
} else {
|
|
node = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static inline void preprocessPadData(u8 *ptr)
|
|
{
|
|
// for some insane reason pads are packed
|
|
// header is always 1 word, the rest of the fields depends on the flags
|
|
u32 *header = (u32 *) ptr;
|
|
PD_SWAP_VAL(header[0]);
|
|
|
|
const u32 flags = header[0] >> 14;
|
|
|
|
ptr += 4;
|
|
|
|
if (flags & PADFLAG_INTPOS) {
|
|
// position is 3x s16
|
|
s16 *sbuffer = (s16 *) ptr;
|
|
PD_SWAP_VAL(sbuffer[0]);
|
|
PD_SWAP_VAL(sbuffer[1]);
|
|
PD_SWAP_VAL(sbuffer[2]);
|
|
ptr += 8;
|
|
} else {
|
|
// position is 3x f32
|
|
f32 *fbuffer = (f32 *) ptr;
|
|
PD_SWAP_VAL(fbuffer[0]);
|
|
PD_SWAP_VAL(fbuffer[1]);
|
|
PD_SWAP_VAL(fbuffer[2]);
|
|
ptr += 12;
|
|
}
|
|
|
|
if (!(flags & (PADFLAG_UPALIGNTOX | PADFLAG_UPALIGNTOY | PADFLAG_UPALIGNTOZ))) {
|
|
// up vector, 3x f32
|
|
f32 *fbuffer = (f32 *) ptr;
|
|
PD_SWAP_VAL(fbuffer[0]);
|
|
PD_SWAP_VAL(fbuffer[1]);
|
|
PD_SWAP_VAL(fbuffer[2]);
|
|
ptr += 12;
|
|
}
|
|
|
|
if (!(flags & (PADFLAG_LOOKALIGNTOX | PADFLAG_LOOKALIGNTOY | PADFLAG_LOOKALIGNTOZ))) {
|
|
// look vector, 3x f32
|
|
f32 *fbuffer = (f32 *) ptr;
|
|
PD_SWAP_VAL(fbuffer[0]);
|
|
PD_SWAP_VAL(fbuffer[1]);
|
|
PD_SWAP_VAL(fbuffer[2]);
|
|
ptr += 12;
|
|
}
|
|
|
|
if (flags & PADFLAG_HASBBOXDATA) {
|
|
// bbox, 3x f32 mins + 3x f32 maxs
|
|
f32 *fbuffer = (f32 *) ptr;
|
|
PD_SWAP_VAL(fbuffer[0]);
|
|
PD_SWAP_VAL(fbuffer[1]);
|
|
PD_SWAP_VAL(fbuffer[2]);
|
|
PD_SWAP_VAL(fbuffer[3]);
|
|
PD_SWAP_VAL(fbuffer[4]);
|
|
PD_SWAP_VAL(fbuffer[5]);
|
|
}
|
|
}
|
|
|
|
static inline void preprocessDefaultPropObj(struct defaultobj *obj)
|
|
{
|
|
PD_SWAP_PTR(obj->projectile);
|
|
PD_SWAP_PTR(obj->geoblock);
|
|
PD_SWAP_PTR(obj->prop);
|
|
PD_SWAP_PTR(obj->model);
|
|
PD_SWAP_VAL(obj->flags);
|
|
PD_SWAP_VAL(obj->flags2);
|
|
PD_SWAP_VAL(obj->flags3);
|
|
PD_SWAP_VAL(obj->hidden);
|
|
PD_SWAP_VAL(obj->damage);
|
|
PD_SWAP_VAL(obj->maxdamage);
|
|
PD_SWAP_VAL(obj->extrascale);
|
|
PD_SWAP_VAL(obj->floorcol);
|
|
PD_SWAP_VAL(obj->modelnum);
|
|
PD_SWAP_VAL(obj->pad);
|
|
for (s32 i = 0; i < 3; ++i) {
|
|
for (s32 j = 0; j < 3; ++j) {
|
|
PD_SWAP_VAL(obj->realrot[i][j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
static inline void preprocessDefaultPropObjHdr(struct defaultobj *obj)
|
|
{
|
|
// don't touch the other fields
|
|
PD_SWAP_VAL(obj->extrascale);
|
|
}
|
|
|
|
static inline void preprocessTvScreenPropObj(struct tvscreen *scr)
|
|
{
|
|
PD_SWAP_PTR(scr->cmdlist);
|
|
PD_SWAP_PTR(scr->tconfig);
|
|
PD_SWAP_VAL(scr->offset);
|
|
PD_SWAP_VAL(scr->pause60);
|
|
PD_SWAP_VAL(scr->rot);
|
|
PD_SWAP_VAL(scr->xscale);
|
|
PD_SWAP_VAL(scr->xscalefrac);
|
|
PD_SWAP_VAL(scr->xscaleinc);
|
|
PD_SWAP_VAL(scr->xscaleold);
|
|
PD_SWAP_VAL(scr->xscalenew);
|
|
PD_SWAP_VAL(scr->yscale);
|
|
PD_SWAP_VAL(scr->yscalefrac);
|
|
PD_SWAP_VAL(scr->yscaleinc);
|
|
PD_SWAP_VAL(scr->yscaleold);
|
|
PD_SWAP_VAL(scr->yscalenew);
|
|
PD_SWAP_VAL(scr->xmid);
|
|
PD_SWAP_VAL(scr->xmidfrac);
|
|
PD_SWAP_VAL(scr->xmidinc);
|
|
PD_SWAP_VAL(scr->xmidold);
|
|
PD_SWAP_VAL(scr->xmidnew);
|
|
PD_SWAP_VAL(scr->ymid);
|
|
PD_SWAP_VAL(scr->ymidfrac);
|
|
PD_SWAP_VAL(scr->ymidinc);
|
|
PD_SWAP_VAL(scr->ymidold);
|
|
PD_SWAP_VAL(scr->ymidnew);
|
|
PD_SWAP_VAL(scr->colfrac);
|
|
PD_SWAP_VAL(scr->colinc);
|
|
}
|
|
|
|
static inline void preprocessHovPropObj(struct hov *hov)
|
|
{
|
|
// don't think anything actually has to be swapped here
|
|
}
|
|
|
|
static void preprocessPropObj(struct defaultobj *obj)
|
|
{
|
|
// TODO: help me jesus
|
|
switch (obj->type) {
|
|
case OBJTYPE_GRENADEPROB:
|
|
struct grenadeprobobj *grenadeprob = (struct grenadeprobobj *)obj;
|
|
preprocessDefaultPropObjHdr(obj);
|
|
PD_SWAP_VAL(grenadeprob->chrnum);
|
|
PD_SWAP_VAL(grenadeprob->probability);
|
|
break;
|
|
case OBJTYPE_CHR:
|
|
struct packedchr *chr = (struct packedchr *)obj;
|
|
PD_SWAP_VAL(chr->chrindex);
|
|
PD_SWAP_VAL(chr->spawnflags);
|
|
PD_SWAP_VAL(chr->chrnum);
|
|
PD_SWAP_VAL(chr->padnum);
|
|
PD_SWAP_VAL(chr->ailistnum);
|
|
PD_SWAP_VAL(chr->padpreset);
|
|
PD_SWAP_VAL(chr->chrpreset);
|
|
PD_SWAP_VAL(chr->hearscale);
|
|
PD_SWAP_VAL(chr->viewdist);
|
|
PD_SWAP_VAL(chr->flags);
|
|
PD_SWAP_VAL(chr->flags2);
|
|
PD_SWAP_VAL(chr->chair);
|
|
PD_SWAP_VAL(chr->convtalk);
|
|
break;
|
|
case OBJTYPE_DOOR:
|
|
struct doorobj *door = (struct doorobj *)obj;
|
|
preprocessDefaultPropObj(obj);
|
|
PD_SWAP_PTR(door->sibling);
|
|
PD_SWAP_VAL(door->maxfrac);
|
|
PD_SWAP_VAL(door->perimfrac);
|
|
PD_SWAP_VAL(door->accel);
|
|
PD_SWAP_VAL(door->decel);
|
|
PD_SWAP_VAL(door->maxspeed);
|
|
PD_SWAP_VAL(door->frac);
|
|
PD_SWAP_VAL(door->fracspeed);
|
|
PD_SWAP_VAL(door->startpos);
|
|
PD_SWAP_VAL(door->keyflags);
|
|
PD_SWAP_VAL(door->autoclosetime);
|
|
PD_SWAP_VAL(door->doorflags);
|
|
PD_SWAP_VAL(door->doortype);
|
|
PD_SWAP_VAL(door->fadealpha);
|
|
PD_SWAP_VAL(door->xludist);
|
|
PD_SWAP_VAL(door->opadist);
|
|
break;
|
|
case OBJTYPE_DOORSCALE:
|
|
struct doorscaleobj *doorsc = (struct doorscaleobj *)obj;
|
|
preprocessDefaultPropObjHdr(obj);
|
|
PD_SWAP_VAL(doorsc->scale);
|
|
break;
|
|
case OBJTYPE_WEAPON:
|
|
struct weaponobj *wpn = (struct weaponobj *)obj;
|
|
preprocessDefaultPropObj(obj);
|
|
PD_SWAP_PTR(wpn->dualweapon);
|
|
PD_SWAP_VAL(wpn->team);
|
|
break;
|
|
case OBJTYPE_KEY:
|
|
struct keyobj *key = (struct keyobj *)obj;
|
|
preprocessDefaultPropObj(obj);
|
|
PD_SWAP_VAL(key->keyflags);
|
|
break;
|
|
case OBJTYPE_CCTV:
|
|
struct cctvobj *cctv = (struct cctvobj *)obj;
|
|
preprocessDefaultPropObj(obj);
|
|
PD_SWAP_VAL(cctv->yzero);
|
|
PD_SWAP_VAL(cctv->yrot);
|
|
PD_SWAP_VAL(cctv->yleft);
|
|
PD_SWAP_VAL(cctv->yright);
|
|
PD_SWAP_VAL(cctv->yspeed);
|
|
PD_SWAP_VAL(cctv->ymaxspeed);
|
|
PD_SWAP_VAL(cctv->maxdist);
|
|
PD_SWAP_VAL(cctv->xzero);
|
|
PD_SWAP_VAL(cctv->seebondtime60);
|
|
PD_SWAP_VAL(cctv->lookatpadnum);
|
|
PD_SWAP_VAL(cctv->toleft);
|
|
break;
|
|
case OBJTYPE_AUTOGUN:
|
|
struct autogunobj *agun = (struct autogunobj *)obj;
|
|
preprocessDefaultPropObj(obj);
|
|
PD_SWAP_VAL(agun->targetpad);
|
|
PD_SWAP_VAL(agun->yzero);
|
|
PD_SWAP_VAL(agun->ymaxleft);
|
|
PD_SWAP_VAL(agun->ymaxright);
|
|
PD_SWAP_VAL(agun->yrot);
|
|
PD_SWAP_VAL(agun->yspeed);
|
|
PD_SWAP_VAL(agun->xzero);
|
|
PD_SWAP_VAL(agun->xrot);
|
|
PD_SWAP_VAL(agun->xspeed);
|
|
PD_SWAP_VAL(agun->maxspeed);
|
|
PD_SWAP_VAL(agun->aimdist);
|
|
PD_SWAP_VAL(agun->barrelspeed);
|
|
PD_SWAP_VAL(agun->barrelrot);
|
|
PD_SWAP_VAL(agun->allowsoundframe);
|
|
PD_SWAP_PTR(agun->target);
|
|
break;
|
|
case OBJTYPE_SINGLEMONITOR:
|
|
struct singlemonitorobj *mon = (struct singlemonitorobj *)obj;
|
|
preprocessDefaultPropObj(obj);
|
|
preprocessTvScreenPropObj((struct tvscreen *)&mon->screen);
|
|
PD_SWAP_VAL(mon->owneroffset);
|
|
break;
|
|
case OBJTYPE_MULTIMONITOR:
|
|
struct multimonitorobj *mmon = (struct multimonitorobj *)obj;
|
|
preprocessDefaultPropObj(obj);
|
|
preprocessTvScreenPropObj((struct tvscreen *)&mmon->screens[0]);
|
|
preprocessTvScreenPropObj((struct tvscreen *)&mmon->screens[1]);
|
|
preprocessTvScreenPropObj((struct tvscreen *)&mmon->screens[2]);
|
|
preprocessTvScreenPropObj((struct tvscreen *)&mmon->screens[3]);
|
|
break;
|
|
case OBJTYPE_SHIELD:
|
|
struct shieldobj *shld = (struct shieldobj *)obj;
|
|
preprocessDefaultPropObj(obj);
|
|
PD_SWAP_VAL(shld->initialamount);
|
|
PD_SWAP_VAL(shld->amount);
|
|
break;
|
|
case OBJTYPE_TINTEDGLASS:
|
|
struct tintedglassobj *tgls = (struct tintedglassobj *)obj;
|
|
preprocessDefaultPropObj(obj);
|
|
PD_SWAP_VAL(tgls->xludist);
|
|
PD_SWAP_VAL(tgls->opadist);
|
|
PD_SWAP_VAL(tgls->opacity);
|
|
PD_SWAP_VAL(tgls->portalnum);
|
|
PD_SWAP_VAL(tgls->unk64);
|
|
break;
|
|
case OBJTYPE_LIFT:
|
|
struct liftobj *lift = (struct liftobj *)obj;
|
|
preprocessDefaultPropObj(obj);
|
|
PD_SWAP_PTR(lift->doors[0]);
|
|
PD_SWAP_PTR(lift->doors[1]);
|
|
PD_SWAP_PTR(lift->doors[2]);
|
|
PD_SWAP_PTR(lift->doors[3]);
|
|
PD_SWAP_VAL(lift->pads[0]);
|
|
PD_SWAP_VAL(lift->pads[1]);
|
|
PD_SWAP_VAL(lift->pads[2]);
|
|
PD_SWAP_VAL(lift->pads[3]);
|
|
PD_SWAP_VAL(lift->dist);
|
|
PD_SWAP_VAL(lift->speed);
|
|
PD_SWAP_VAL(lift->accel);
|
|
PD_SWAP_VAL(lift->maxspeed);
|
|
break;
|
|
case OBJTYPE_HOVERPROP:
|
|
struct hoverpropobj *hprop = (struct hoverpropobj *)obj;
|
|
preprocessDefaultPropObj(obj);
|
|
preprocessHovPropObj(&hprop->hov);
|
|
break;
|
|
case OBJTYPE_HOVERBIKE:
|
|
struct hoverbikeobj *hbike = (struct hoverbikeobj *)obj;
|
|
preprocessDefaultPropObj(obj);
|
|
preprocessHovPropObj(&hbike->hov);
|
|
break;
|
|
case OBJTYPE_FAN:
|
|
struct fanobj *fan = (struct fanobj *)obj;
|
|
preprocessDefaultPropObj(obj);
|
|
PD_SWAP_VAL(fan->yrot);
|
|
PD_SWAP_VAL(fan->yrotprev);
|
|
PD_SWAP_VAL(fan->ymaxspeed);
|
|
PD_SWAP_VAL(fan->yspeed);
|
|
PD_SWAP_VAL(fan->yaccel);
|
|
break;
|
|
case OBJTYPE_GLASS:
|
|
struct glassobj *gls = (struct glassobj *)obj;
|
|
preprocessDefaultPropObj(obj);
|
|
PD_SWAP_VAL(gls->portalnum);
|
|
break;
|
|
case OBJTYPE_AMMOCRATE:
|
|
struct ammocrateobj *ammo = (struct ammocrateobj *)obj;
|
|
preprocessDefaultPropObj(obj);
|
|
PD_SWAP_VAL(ammo->ammotype);
|
|
break;
|
|
case OBJTYPE_MULTIAMMOCRATE:
|
|
struct multiammocrateobj *mammo = (struct multiammocrateobj *)obj;
|
|
preprocessDefaultPropObj(obj);
|
|
for (s32 i = 0; i < ARRAYCOUNT(mammo->slots); ++i) {
|
|
PD_SWAP_VAL(mammo->slots[i].modelnum);
|
|
PD_SWAP_VAL(mammo->slots[i].quantity);
|
|
}
|
|
break;
|
|
case OBJTYPE_TRUCK:
|
|
struct truckobj *truck = (struct truckobj *)obj;
|
|
preprocessDefaultPropObj(obj);
|
|
PD_SWAP_PTR(truck->ailist);
|
|
break;
|
|
case OBJTYPE_HOVERCAR:
|
|
struct hovercarobj *car = (struct hovercarobj *)obj;
|
|
preprocessDefaultPropObj(obj);
|
|
PD_SWAP_PTR(car->ailist);
|
|
break;
|
|
case OBJTYPE_CHOPPER:
|
|
struct chopperobj *chop = (struct chopperobj *)obj;
|
|
preprocessDefaultPropObj(obj);
|
|
PD_SWAP_PTR(chop->ailist);
|
|
break;
|
|
case OBJTYPE_HELI:
|
|
struct heliobj *heli = (struct heliobj *)obj;
|
|
preprocessDefaultPropObj(obj);
|
|
PD_SWAP_PTR(heli->ailist);
|
|
break;
|
|
case OBJTYPE_TAG:
|
|
struct tag *tag = (struct tag *)obj;
|
|
PD_SWAP_PTR(tag->next);
|
|
PD_SWAP_PTR(tag->obj);
|
|
PD_SWAP_VAL(tag->cmdoffset);
|
|
PD_SWAP_VAL(tag->tagnum);
|
|
break;
|
|
case OBJTYPE_RENAMEOBJ:
|
|
struct textoverride *over = (struct textoverride *)obj;
|
|
preprocessDefaultPropObjHdr(obj);
|
|
PD_SWAP_PTR(over->next);
|
|
PD_SWAP_PTR(over->obj);
|
|
PD_SWAP_VAL(over->objoffset);
|
|
PD_SWAP_VAL(over->weapon);
|
|
PD_SWAP_VAL(over->obtaintext);
|
|
PD_SWAP_VAL(over->ownertext);
|
|
PD_SWAP_VAL(over->inventorytext);
|
|
PD_SWAP_VAL(over->inventory2text);
|
|
PD_SWAP_VAL(over->pickuptext);
|
|
break;
|
|
case OBJTYPE_BRIEFING:
|
|
struct briefingobj *brief = (struct briefingobj *)obj;
|
|
preprocessDefaultPropObjHdr(obj);
|
|
PD_SWAP_PTR(brief->next);
|
|
PD_SWAP_VAL(brief->type);
|
|
PD_SWAP_VAL(brief->text);
|
|
break;
|
|
case OBJTYPE_CAMERAPOS:
|
|
struct cameraposobj *campos = (struct cameraposobj *)obj;
|
|
preprocessDefaultPropObjHdr(obj);
|
|
PD_SWAP_VAL(campos->x);
|
|
PD_SWAP_VAL(campos->y);
|
|
PD_SWAP_VAL(campos->z);
|
|
PD_SWAP_VAL(campos->theta);
|
|
PD_SWAP_VAL(campos->verta);
|
|
PD_SWAP_VAL(campos->pad);
|
|
break;
|
|
case OBJTYPE_BEGINOBJECTIVE:
|
|
struct objective *objective = (struct objective *)obj;
|
|
preprocessDefaultPropObjHdr(obj);
|
|
PD_SWAP_VAL(objective->index);
|
|
PD_SWAP_VAL(objective->text);
|
|
PD_SWAP_VAL(objective->unk0c);
|
|
break;
|
|
case OBJTYPE_ENDOBJECTIVE:
|
|
break;
|
|
case OBJTYPE_PADEFFECT:
|
|
struct padeffectobj *padeff = (struct padeffectobj *)obj;
|
|
preprocessDefaultPropObjHdr(obj);
|
|
PD_SWAP_VAL(padeff->pad);
|
|
PD_SWAP_VAL(padeff->effect);
|
|
break;
|
|
case OBJTYPE_LINKGUNS:
|
|
struct linkgunsobj *linkg = (struct linkgunsobj *)obj;
|
|
preprocessDefaultPropObjHdr(obj);
|
|
PD_SWAP_VAL(linkg->offset1);
|
|
PD_SWAP_VAL(linkg->offset2);
|
|
break;
|
|
case OBJTYPE_LINKLIFTDOOR:
|
|
struct linkliftdoorobj *linkd = (struct linkliftdoorobj *)obj;
|
|
preprocessDefaultPropObjHdr(obj);
|
|
PD_SWAP_PTR(linkd->door);
|
|
PD_SWAP_PTR(linkd->lift);
|
|
PD_SWAP_PTR(linkd->next);
|
|
PD_SWAP_VAL(linkd->stopnum);
|
|
break;
|
|
case OBJTYPE_SAFEITEM:
|
|
struct safeitemobj *linki = (struct safeitemobj *)obj;
|
|
preprocessDefaultPropObjHdr(obj);
|
|
PD_SWAP_PTR(linki->item);
|
|
PD_SWAP_PTR(linki->safe);
|
|
PD_SWAP_PTR(linki->door);
|
|
PD_SWAP_PTR(linki->next);
|
|
break;
|
|
case OBJTYPE_PADLOCKEDDOOR:
|
|
struct padlockeddoorobj *linkp = (struct padlockeddoorobj *)obj;
|
|
preprocessDefaultPropObjHdr(obj);
|
|
PD_SWAP_PTR(linkp->door);
|
|
PD_SWAP_PTR(linkp->lock);
|
|
PD_SWAP_PTR(linkp->next);
|
|
break;
|
|
case OBJTYPE_CONDITIONALSCENERY:
|
|
struct linksceneryobj *links = (struct linksceneryobj *)obj;
|
|
preprocessDefaultPropObjHdr(obj);
|
|
PD_SWAP_PTR(links->trigger);
|
|
PD_SWAP_PTR(links->unexp);
|
|
PD_SWAP_PTR(links->exp);
|
|
PD_SWAP_PTR(links->next);
|
|
break;
|
|
case OBJTYPE_BLOCKEDPATH:
|
|
struct blockedpathobj *blkp = (struct blockedpathobj *)obj;
|
|
preprocessDefaultPropObjHdr(obj);
|
|
PD_SWAP_PTR(blkp->blocker);
|
|
PD_SWAP_PTR(blkp->next);
|
|
PD_SWAP_VAL(blkp->waypoint1);
|
|
PD_SWAP_VAL(blkp->waypoint2);
|
|
break;
|
|
case OBJTYPE_MINE:
|
|
case OBJTYPE_ESCASTEP:
|
|
case OBJTYPE_HANGINGMONITORS:
|
|
case OBJTYPE_BASIC:
|
|
case OBJTYPE_ALARM:
|
|
case OBJTYPE_DEBRIS:
|
|
case OBJTYPE_GASBOTTLE:
|
|
case OBJTYPE_29:
|
|
case OBJTYPE_SAFE:
|
|
case OBJTYPE_HAT:
|
|
preprocessDefaultPropObj(obj);
|
|
break;
|
|
case OBJECTIVETYPE_ENTERROOM:
|
|
struct criteria_roomentered *obte = (struct criteria_roomentered *)obj;
|
|
preprocessDefaultPropObjHdr(obj);
|
|
PD_SWAP_PTR(obte->next);
|
|
PD_SWAP_VAL(obte->pad);
|
|
PD_SWAP_VAL(obte->status);
|
|
break;
|
|
case OBJECTIVETYPE_THROWINROOM:
|
|
struct criteria_throwinroom *obtt = (struct criteria_throwinroom *)obj;
|
|
preprocessDefaultPropObjHdr(obj);
|
|
PD_SWAP_PTR(obtt->next);
|
|
PD_SWAP_VAL(obtt->unk04);
|
|
PD_SWAP_VAL(obtt->pad);
|
|
PD_SWAP_VAL(obtt->status);
|
|
break;
|
|
case OBJECTIVETYPE_HOLOGRAPH:
|
|
struct criteria_holograph *obth = (struct criteria_holograph *)obj;
|
|
preprocessDefaultPropObjHdr(obj);
|
|
PD_SWAP_PTR(obth->next);
|
|
PD_SWAP_VAL(obth->obj);
|
|
PD_SWAP_VAL(obth->status);
|
|
break;
|
|
case OBJECTIVETYPE_DESTROYOBJ:
|
|
case OBJECTIVETYPE_COMPFLAGS:
|
|
case OBJECTIVETYPE_FAILFLAGS:
|
|
case OBJECTIVETYPE_COLLECTOBJ:
|
|
case OBJECTIVETYPE_THROWOBJ:
|
|
u32 *cmd = (u32 *)obj;
|
|
PD_SWAP_VAL(cmd[1]);
|
|
break;
|
|
default:
|
|
fprintf(stderr, "unknown objtype: %02x @ %p\n", obj->type, obj);
|
|
fflush(stderr);
|
|
__builtin_trap();
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void preprocessIntroScript(s32 *cmd)
|
|
{
|
|
while (cmd[0] != PD_BE32(INTROCMD_END)) {
|
|
PD_SWAP_VAL(cmd[0]);
|
|
switch (cmd[0]) {
|
|
case INTROCMD_HILL:
|
|
case INTROCMD_OUTFIT:
|
|
case INTROCMD_CREDITOFFSET:
|
|
case INTROCMD_4:
|
|
PD_SWAP_VAL(cmd[1]);
|
|
cmd += 2;
|
|
break;
|
|
case INTROCMD_SPAWN:
|
|
case INTROCMD_CASE:
|
|
case INTROCMD_CASERESPAWN:
|
|
case INTROCMD_WATCHTIME:
|
|
PD_SWAP_VAL(cmd[1]);
|
|
PD_SWAP_VAL(cmd[2]);
|
|
cmd += 3;
|
|
break;
|
|
case INTROCMD_AMMO:
|
|
case INTROCMD_WEAPON:
|
|
PD_SWAP_VAL(cmd[1]);
|
|
PD_SWAP_VAL(cmd[2]);
|
|
PD_SWAP_VAL(cmd[3]);
|
|
cmd += 4;
|
|
break;
|
|
case INTROCMD_3:
|
|
PD_SWAP_VAL(cmd[1]);
|
|
PD_SWAP_VAL(cmd[2]);
|
|
PD_SWAP_VAL(cmd[3]);
|
|
PD_SWAP_VAL(cmd[4]);
|
|
PD_SWAP_VAL(cmd[5]);
|
|
PD_SWAP_VAL(cmd[6]);
|
|
PD_SWAP_VAL(cmd[7]);
|
|
cmd += 8;
|
|
break;
|
|
case INTROCMD_6:
|
|
PD_SWAP_VAL(cmd[1]);
|
|
PD_SWAP_VAL(cmd[2]);
|
|
PD_SWAP_VAL(cmd[3]);
|
|
PD_SWAP_VAL(cmd[4]);
|
|
PD_SWAP_VAL(cmd[5]);
|
|
PD_SWAP_VAL(cmd[6]);
|
|
PD_SWAP_VAL(cmd[7]);
|
|
PD_SWAP_VAL(cmd[8]);
|
|
PD_SWAP_VAL(cmd[9]);
|
|
cmd += 10;
|
|
break;
|
|
default:
|
|
cmd += 1;
|
|
break;
|
|
}
|
|
}
|
|
PD_SWAP_VAL(cmd[0]);
|
|
}
|
|
|
|
void preprocessAnimations(u8 *data, u32 size)
|
|
{
|
|
// set the anim table pointers as well
|
|
extern u8 *_animationsTableRomStart;
|
|
extern u8 *_animationsTableRomEnd;
|
|
// the animation table is at the end of the segment
|
|
u32 *animtbl = (void *)(data + size - 0x38a0);
|
|
_animationsTableRomStart = (u8 *)animtbl;
|
|
_animationsTableRomEnd = data + size;
|
|
PD_SWAP_VAL(*animtbl);
|
|
const u32 count = *animtbl++;
|
|
struct animtableentry *anim = (struct animtableentry *)animtbl;
|
|
for (u32 i = 0; i < count; ++i, ++anim) {
|
|
PD_SWAP_VAL(anim->numframes);
|
|
PD_SWAP_VAL(anim->bytesperframe);
|
|
PD_SWAP_VAL(anim->headerlen);
|
|
PD_SWAP_VAL(anim->data);
|
|
}
|
|
}
|
|
|
|
void preprocessMpConfigs(u8 *data, u32 size)
|
|
{
|
|
const u32 count = size / sizeof(struct mpconfig);
|
|
struct mpconfig *cfg = (struct mpconfig *)data;
|
|
for (u32 i = 0; i < count; ++i, ++cfg) {
|
|
PD_SWAP_VAL(cfg->setup.options);
|
|
PD_SWAP_VAL(cfg->setup.teamscorelimit);
|
|
PD_SWAP_VAL(cfg->setup.chrslots);
|
|
// TODO: are these required or are they always 0?
|
|
PD_SWAP_VAL(cfg->setup.fileguid.deviceserial);
|
|
PD_SWAP_VAL(cfg->setup.fileguid.fileid);
|
|
}
|
|
}
|
|
|
|
void preprocessFont(u8 *data, u32 size)
|
|
{
|
|
struct font *fnt = (struct font *)data;
|
|
|
|
for (s32 i = 0; i < ARRAYCOUNT(fnt->kerning); ++i) {
|
|
PD_SWAP_VAL(fnt->kerning[i]);
|
|
}
|
|
|
|
for (s32 i = 0; i < ARRAYCOUNT(fnt->chars); ++i) {
|
|
PD_SWAP_VAL(fnt->chars[i].kerningindex);
|
|
PD_SWAP_PTR(fnt->chars[i].pixeldata);
|
|
}
|
|
}
|
|
|
|
void preprocessJpnFont(u8 *data, u32 size)
|
|
{
|
|
// ???
|
|
}
|
|
|
|
void preprocessALBankFile(u8 *data, u32 size)
|
|
{
|
|
memset(swapmap, 0, sizeof(swapmap));
|
|
|
|
ALBankFile *bankf = (ALBankFile *)data;
|
|
PD_SWAP_VAL(bankf->revision);
|
|
PD_SWAP_VAL(bankf->bankCount);
|
|
|
|
for (s16 i = 0; i < bankf->bankCount; ++i) {
|
|
PD_SWAP_PTR(bankf->bankArray[i]);
|
|
preprocessALBank(PD_PTR_BASE(bankf->bankArray[i], data), data);
|
|
}
|
|
}
|
|
|
|
void preprocessALCMidiHdr(u8 *data, u32 size)
|
|
{
|
|
ALCMidiHdr *hdr = (ALCMidiHdr *)data;
|
|
PD_SWAP_VAL(hdr->division);
|
|
for (s32 i = 0; i < ARRAYCOUNT(hdr->trackOffset); ++i) {
|
|
PD_SWAP_VAL(hdr->trackOffset[i]);
|
|
}
|
|
}
|
|
|
|
void preprocessSequences(u8 *data, u32 size)
|
|
{
|
|
struct seqtable *seq = (struct seqtable *)data;
|
|
PD_SWAP_VAL(seq->count);
|
|
|
|
for (s16 i = 0; i < seq->count; ++i) {
|
|
PD_SWAP_VAL(seq->entries[i].binlen);
|
|
PD_SWAP_VAL(seq->entries[i].ziplen);
|
|
PD_SWAP_VAL(seq->entries[i].romaddr);
|
|
}
|
|
}
|
|
|
|
void preprocessTexturesList(u8 *data, u32 size)
|
|
{
|
|
struct texture *tex = (struct texture *)data;
|
|
const u32 count = size / sizeof(*tex);
|
|
for (u32 i = 0; i < count; ++i, ++tex) {
|
|
// TODO: it sure looks like none of the fields except soundsurfacetype, surfacetype and dataoffset are set
|
|
// just swap the last 3 bytes of the first word
|
|
const u32 dofs = (u32)tex->dataoffset << 8;
|
|
tex->dataoffset = PD_BE32(dofs);
|
|
}
|
|
}
|
|
|
|
void preprocessModel(u8 *base, u32 ofs)
|
|
{
|
|
struct modeldef *mdl = (struct modeldef *)base;
|
|
|
|
PD_SWAP_VAL(mdl->nummatrices);
|
|
PD_SWAP_VAL(mdl->numparts);
|
|
PD_SWAP_VAL(mdl->numtexconfigs);
|
|
PD_SWAP_VAL(mdl->rwdatalen);
|
|
PD_SWAP_VAL(mdl->scale);
|
|
|
|
if (mdl->skel) {
|
|
PD_SWAP_PTR(mdl->skel);
|
|
if ((u32)mdl->skel >= 0x10000) {
|
|
// skeleton is a pointer instead of an index
|
|
// preprocessSkeleton((struct skeleton *)(base + (u32)mdl->skel)); // TODO
|
|
}
|
|
}
|
|
|
|
if (mdl->parts) {
|
|
PD_SWAP_PTR(mdl->parts);
|
|
struct modelnode **parts = PD_PTR_BASEOFS(mdl->parts, base, ofs);
|
|
for (s16 i = 0; i < mdl->numparts; ++i) {
|
|
PD_SWAP_PTR(parts[i]);
|
|
}
|
|
s16 *partnums = (s16 *)&parts[mdl->numparts];
|
|
for (s16 i = 0; i < mdl->numparts; ++i) {
|
|
PD_SWAP_VAL(partnums[i]);
|
|
}
|
|
}
|
|
|
|
if (mdl->texconfigs) {
|
|
PD_SWAP_PTR(mdl->texconfigs);
|
|
struct textureconfig *texconfigs = PD_PTR_BASEOFS(mdl->texconfigs, base, ofs);
|
|
for (s16 i = 0; i < mdl->numtexconfigs; ++i) {
|
|
PD_SWAP_VAL(texconfigs[i].texturenum);
|
|
}
|
|
}
|
|
|
|
if (mdl->rootnode) {
|
|
PD_SWAP_PTR(mdl->rootnode);
|
|
preprocessModelNode(PD_PTR_BASEOFS(mdl->rootnode, base, ofs), base, ofs);
|
|
}
|
|
}
|
|
|
|
void preprocessLangFile(u8 *data, u32 size)
|
|
{
|
|
// lang banks are just an offset table + text data right after
|
|
// offsets are from the beginning of the bank
|
|
// however we cannot byteswap them in advance because the length of the
|
|
// offset table is unknown, so that's done in lang.c on demand instead
|
|
}
|
|
|
|
void preprocessPadsFile(u8 *data, u32 size)
|
|
{
|
|
struct padsfileheader *hdr = (void *)data;
|
|
|
|
PD_SWAP_VAL(hdr->numpads);
|
|
PD_SWAP_VAL(hdr->numcovers);
|
|
|
|
for (s32 i = 0; i < hdr->numpads; ++i) {
|
|
if (hdr->padoffsets[i]) {
|
|
PD_SWAP_VAL(hdr->padoffsets[i]);
|
|
preprocessPadData(PD_PTR_BASE(hdr->padoffsets[i], hdr));
|
|
}
|
|
}
|
|
|
|
if (hdr->numcovers && hdr->coversoffset) {
|
|
PD_SWAP_VAL(hdr->coversoffset);
|
|
struct coverdefinition *def = PD_PTR_BASE(hdr->coversoffset, hdr);
|
|
for (s32 i = 0; i < hdr->numcovers; ++i, ++def) {
|
|
PD_SWAP_VAL(def->flags);
|
|
PD_SWAP_VAL(def->look);
|
|
PD_SWAP_VAL(def->pos);
|
|
}
|
|
}
|
|
|
|
if (hdr->waypointsoffset) {
|
|
PD_SWAP_VAL(hdr->waypointsoffset);
|
|
struct waypoint *wp = PD_PTR_BASE(hdr->waypointsoffset, hdr);
|
|
// the terminator is 0xFFFFFFFF, same for the s32 lists
|
|
// TODO: the game checks for >= 0, so maybe something's terminated with a random negative number?
|
|
while (wp->padnum != (s32)0xFFFFFFFF) {
|
|
PD_SWAP_VAL(wp->padnum);
|
|
PD_SWAP_VAL(wp->groupnum);
|
|
PD_SWAP_VAL(wp->step);
|
|
if (wp->neighbours) {
|
|
PD_SWAP_PTR(wp->neighbours);
|
|
s32 *nbr = PD_PTR_BASE(wp->neighbours, hdr);
|
|
while (*nbr != (s32)0xFFFFFFFF) {
|
|
PD_SWAP_VAL(*nbr);
|
|
++nbr;
|
|
}
|
|
}
|
|
++wp;
|
|
}
|
|
}
|
|
|
|
if (hdr->waygroupsoffset) {
|
|
PD_SWAP_VAL(hdr->waygroupsoffset);
|
|
struct waygroup *wg = PD_PTR_BASE(hdr->waygroupsoffset, hdr);
|
|
while (wg->neighbours) {
|
|
PD_SWAP_VAL(wg->step);
|
|
if (wg->neighbours) {
|
|
PD_SWAP_PTR(wg->neighbours);
|
|
s32 *nbr = PD_PTR_BASE(wg->neighbours, hdr);
|
|
while (*nbr != (s32)0xFFFFFFFF) {
|
|
PD_SWAP_VAL(*nbr);
|
|
++nbr;
|
|
}
|
|
}
|
|
if (wg->waypoints) {
|
|
PD_SWAP_PTR(wg->waypoints);
|
|
s32 *wgwp = PD_PTR_BASE(wg->waypoints, hdr);
|
|
while (*wgwp != (s32)0xFFFFFFFF) {
|
|
PD_SWAP_VAL(*wgwp);
|
|
++wgwp;
|
|
}
|
|
}
|
|
++wg;
|
|
}
|
|
}
|
|
}
|
|
|
|
void preprocessTilesFile(u8 *data, u32 size)
|
|
{
|
|
u32 *roomTable = (u32 *)data;
|
|
PD_SWAP_VAL(roomTable[0]);
|
|
|
|
const u32 numRooms = roomTable[0];
|
|
++roomTable;
|
|
|
|
u32 *rooms = roomTable;
|
|
// rooms[numRooms] is the end offset
|
|
for (u32 i = 0; i <= numRooms; ++i) {
|
|
PD_SWAP_VAL(rooms[i]);
|
|
}
|
|
|
|
struct geo *geo = (struct geo *)(data + rooms[0]);
|
|
struct geo *end = (struct geo *)(data + rooms[numRooms]);
|
|
|
|
while (geo < end) {
|
|
PD_SWAP_VAL(geo->flags);
|
|
switch (geo->type) {
|
|
case GEOTYPE_TILE_I: {
|
|
struct geotilei *tile = (struct geotilei *)geo;
|
|
PD_SWAP_VAL(tile->floorcol);
|
|
PD_SWAP_VAL(tile->floortype);
|
|
for (u32 i = 0; i < geo->numvertices; ++i) {
|
|
PD_SWAP_VAL(tile->vertices[i][0]);
|
|
PD_SWAP_VAL(tile->vertices[i][1]);
|
|
PD_SWAP_VAL(tile->vertices[i][2]);
|
|
}
|
|
geo = (struct geo *)((u8 *)geo + (uintptr_t)(geo->numvertices - 0x40) * 6 + 0x18e);
|
|
break;
|
|
}
|
|
case GEOTYPE_TILE_F: {
|
|
struct geotilef *tile = (struct geotilef *)geo;
|
|
PD_SWAP_VAL(tile->floorcol);
|
|
PD_SWAP_VAL(tile->floortype);
|
|
for (u32 i = 0; i < geo->numvertices; ++i) {
|
|
PD_SWAP_VAL(tile->vertices[i].x);
|
|
PD_SWAP_VAL(tile->vertices[i].y);
|
|
PD_SWAP_VAL(tile->vertices[i].z);
|
|
}
|
|
geo = (struct geo *)((u8 *)geo + (uintptr_t)(geo->numvertices - 0x40) * 12 + 0x310);
|
|
break;
|
|
}
|
|
case GEOTYPE_BLOCK: {
|
|
struct geoblock *blk = (struct geoblock *)geo;
|
|
PD_SWAP_VAL(blk->ymin);
|
|
PD_SWAP_VAL(blk->ymax);
|
|
for (u32 i = 0; i < geo->numvertices; ++i) {
|
|
PD_SWAP_VAL(blk->vertices[i][0]);
|
|
PD_SWAP_VAL(blk->vertices[i][1]);
|
|
}
|
|
geo = (struct geo *)((u8 *)geo + sizeof(struct geoblock));
|
|
break;
|
|
}
|
|
case GEOTYPE_CYL: {
|
|
struct geocyl *cyl = (struct geocyl *)geo;
|
|
PD_SWAP_VAL(cyl->x);
|
|
PD_SWAP_VAL(cyl->z);
|
|
PD_SWAP_VAL(cyl->radius);
|
|
PD_SWAP_VAL(cyl->ymin);
|
|
PD_SWAP_VAL(cyl->ymax);
|
|
geo = (struct geo *)((u8 *)geo + sizeof(struct geocyl));
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void preprocessSetupFile(u8 *data, u32 size)
|
|
{
|
|
struct stagesetup *set = (void *)data;
|
|
|
|
if (set->intro) {
|
|
// intro commands are made up of a command id + up to 3 args, which can have any value, even 0x0c (end marker)
|
|
// so we have to swap each type by hand here as well
|
|
PD_SWAP_PTR(set->intro);
|
|
preprocessIntroScript(PD_PTR_BASE(set->intro, set));
|
|
}
|
|
|
|
if (set->props) {
|
|
PD_SWAP_PTR(set->props);
|
|
// commands are casted to non-trivial structs elsewhere, so we'll have to parse the fucking list
|
|
// and swap each type by hand
|
|
struct defaultobj *obj = PD_PTR_BASE(set->props, set);
|
|
while (obj->type != OBJTYPE_END) {
|
|
preprocessPropObj(obj);
|
|
obj = (struct defaultobj *)((u32 *)obj + setupGetCmdLength((u32 *)obj));
|
|
}
|
|
}
|
|
|
|
if (set->paths) {
|
|
PD_SWAP_PTR(set->paths);
|
|
struct path *p = PD_PTR_BASE(set->paths, set);
|
|
while ((u8 *)p < data + size && p->pads) {
|
|
PD_SWAP_PTR(p->pads);
|
|
s32 *pp = PD_PTR_BASE(p->pads, set);
|
|
while ((u8 *)pp < data + size) {
|
|
PD_SWAP_VAL(*pp);
|
|
if (*pp < 0) {
|
|
break;
|
|
}
|
|
++pp;
|
|
}
|
|
++p;
|
|
}
|
|
}
|
|
|
|
if (set->ailists) {
|
|
PD_SWAP_PTR(set->ailists);
|
|
struct ailist *p = PD_PTR_BASE(set->ailists, set);
|
|
while ((u8 *)p < data + size && p->list) {
|
|
PD_SWAP_VAL(p->id);
|
|
PD_SWAP_PTR(p->list);
|
|
// the actual command lists are made up of variable length instructions,
|
|
// but they don't do any wonky word casting, so they should probably work as is
|
|
++p;
|
|
}
|
|
}
|
|
|
|
// the rest of the pointers are set after loading
|
|
}
|
|
|
|
void preprocessModelFile(u8 *data, u32 size)
|
|
{
|
|
preprocessModel(data, 0x5000000);
|
|
}
|
|
|
|
void preprocessGunFile(u8 *data, u32 size)
|
|
{
|
|
preprocessModel(data, 0x5000000);
|
|
}
|
|
|
|
void preprocessBgSection1Header(u8 *data, u32 size)
|
|
{
|
|
u32 *header = (u32 *)data;
|
|
PD_SWAP_VAL(header[0]); // inflatedsize
|
|
PD_SWAP_VAL(header[1]); // section1size
|
|
PD_SWAP_VAL(header[2]); // primcompsize
|
|
}
|
|
|
|
void preprocessBgSection1(u8 *data, u32 ofs) {
|
|
struct {
|
|
u32 unk00;
|
|
u32 roomsofs;
|
|
u32 portalsofs;
|
|
u32 commandsofs;
|
|
u32 lightsofs;
|
|
u32 stanofs;
|
|
} *header = (void *)data;
|
|
|
|
PD_SWAP_VAL(header->unk00);
|
|
PD_SWAP_VAL(header->roomsofs);
|
|
PD_SWAP_VAL(header->portalsofs);
|
|
|
|
struct bgroom *rm = PD_PTR_BASEOFS(header->roomsofs, data, ofs);
|
|
for (++rm; rm->unk00; ++rm) {
|
|
PD_SWAP_VAL(rm->unk00);
|
|
PD_SWAP_VAL(rm->pos);
|
|
}
|
|
|
|
struct bgportal *portals = PD_PTR_BASEOFS(header->portalsofs, data, ofs);
|
|
s32 numportals = 0;
|
|
for (struct bgportal *prt = portals; prt->verticesoffset; ++prt) {
|
|
++numportals;
|
|
}
|
|
|
|
for (s32 i = 0; i < numportals; ++i) {
|
|
PD_SWAP_VAL(portals[i].verticesoffset);
|
|
PD_SWAP_VAL(portals[i].roomnum1);
|
|
PD_SWAP_VAL(portals[i].roomnum2);
|
|
}
|
|
|
|
uintptr_t pvoffset = sizeof(portals[0]) * (numportals + 1);
|
|
for (s32 i = 0; i < numportals; i++) {
|
|
struct portalvertices *pverts = PD_PTR_BASE(pvoffset, portals);
|
|
for (u32 j = 0; j < pverts->count; ++j) {
|
|
PD_SWAP_VAL(pverts->vertices[j]);
|
|
}
|
|
pvoffset += 4 + pverts->count * 12;
|
|
}
|
|
|
|
if (header->commandsofs) {
|
|
PD_SWAP_VAL(header->commandsofs);
|
|
struct bgcmd *cmd = PD_PTR_BASEOFS(header->commandsofs, data, ofs);
|
|
for (; cmd->type != 0x00; cmd++) {
|
|
PD_SWAP_VAL(cmd->param);
|
|
}
|
|
}
|
|
|
|
if (header->lightsofs) {
|
|
PD_SWAP_VAL(header->lightsofs);
|
|
// data swapping done later in preprocessBgLights
|
|
}
|
|
|
|
if (header->stanofs) {
|
|
PD_SWAP_VAL(header->stanofs);
|
|
// unused, so won't swap the contents
|
|
}
|
|
}
|
|
|
|
void preprocessBgSection2Header(u8 *data, u32 size)
|
|
{
|
|
u16 *header = (u16 *)data;
|
|
PD_SWAP_VAL(header[0]); // inflatedsize
|
|
PD_SWAP_VAL(header[1]); // section2compsize
|
|
}
|
|
|
|
void preprocessBgSection2(u8 *data, u32 size)
|
|
{
|
|
// section2 is a texture id list
|
|
u16 *section2 = (u16 *)data;
|
|
for (s32 i = 0; i < size; ++i) {
|
|
PD_SWAP_VAL(section2[i]);
|
|
}
|
|
}
|
|
|
|
void preprocessBgSection3Header(u8 *data, u32 size)
|
|
{
|
|
u16 *header = (u16 *)data;
|
|
PD_SWAP_VAL(header[0]);
|
|
PD_SWAP_VAL(header[1]);
|
|
}
|
|
|
|
void preprocessBgSection3(u8 *data, u32 size)
|
|
{
|
|
// room bounding boxes, 6x s16 per room
|
|
s16 *bbox = (s16 *)data;
|
|
for (s32 i = 1; i < g_Vars.roomcount; ++i) {
|
|
PD_SWAP_VAL(*bbox); ++bbox;
|
|
PD_SWAP_VAL(*bbox); ++bbox;
|
|
PD_SWAP_VAL(*bbox); ++bbox;
|
|
PD_SWAP_VAL(*bbox); ++bbox;
|
|
PD_SWAP_VAL(*bbox); ++bbox;
|
|
PD_SWAP_VAL(*bbox); ++bbox;
|
|
}
|
|
|
|
// gfxdatalen list
|
|
u16 *gfxdatalen = (u16 *)bbox;
|
|
for (s32 i = 1; i < g_Vars.roomcount; ++i) {
|
|
PD_SWAP_VAL(*gfxdatalen); ++gfxdatalen;
|
|
}
|
|
}
|
|
|
|
void preprocessBgRoom(u8 *data, u32 ofs) {
|
|
struct roomgfxdata *rgfx = (void *)data;
|
|
|
|
PD_SWAP_VAL(rgfx->numvertices);
|
|
PD_SWAP_VAL(rgfx->numcolours);
|
|
PD_SWAP_VAL(rgfx->numlights);
|
|
PD_SWAP_VAL(rgfx->lightsindex);
|
|
PD_SWAP_PTR(rgfx->vertices);
|
|
PD_SWAP_PTR(rgfx->opablocks);
|
|
PD_SWAP_PTR(rgfx->xlublocks);
|
|
PD_SWAP_PTR(rgfx->colours);
|
|
|
|
// numvertices is actually 0 in the data because fuck you
|
|
const s32 numverts = ((uintptr_t) rgfx->colours - (uintptr_t) rgfx->vertices) / sizeof(Vtx);
|
|
Vtx *vertices = PD_PTR_BASEOFS(rgfx->vertices, data, ofs);
|
|
Vtx *vtx = vertices;
|
|
for (s32 i = 0; i < numverts; ++i, ++vtx) {
|
|
preprocessVtx(vtx);
|
|
}
|
|
|
|
// here's hoping that xlublocks and opablocks aren't completely separate trees
|
|
|
|
struct roomblock *blk = rgfx->blocks;
|
|
struct roomblock *end = (void *)vertices;
|
|
struct coord *tmp;
|
|
|
|
for (; blk + 1 <= end; blk++) {
|
|
PD_SWAP_PTR(blk->next);
|
|
switch (blk->type) {
|
|
case ROOMBLOCKTYPE_LEAF:
|
|
if (blk->gdl) {
|
|
PD_SWAP_PTR(blk->gdl);
|
|
preprocessGfx(PD_PTR_BASEOFS(blk->gdl, data, ofs), data, ofs);
|
|
}
|
|
PD_SWAP_PTR(blk->vertices);
|
|
PD_SWAP_PTR(blk->colours);
|
|
break;
|
|
case ROOMBLOCKTYPE_PARENT:
|
|
PD_SWAP_PTR(blk->child);
|
|
PD_SWAP_PTR(blk->unk0c);
|
|
tmp = PD_PTR_BASEOFS(blk->unk0c, data, ofs);
|
|
for (s32 i = 0; i < 2; ++i) {
|
|
PD_SWAP_VAL(tmp[i].x);
|
|
PD_SWAP_VAL(tmp[i].y);
|
|
PD_SWAP_VAL(tmp[i].z);
|
|
}
|
|
if ((u8 *)tmp < (u8 *)end) {
|
|
end = (void *)tmp;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void preprocessBgLights(u8 *data, u32 ofs)
|
|
{
|
|
struct light *lbase = (void *)data;
|
|
if (!lbase) {
|
|
return;
|
|
}
|
|
|
|
for (s32 i = 0; i < g_Vars.roomcount; ++i) {
|
|
if (g_Rooms[i].numlights) {
|
|
struct light *lit = &lbase[g_Rooms[i].lightindex];
|
|
for (s32 j = 0; j < g_Rooms[i].numlights; ++j, ++lit) {
|
|
PD_SWAP_VAL(lit->colour);
|
|
PD_SWAP_VAL(lit->roomnum);
|
|
for (s32 k = 0; k < ARRAYCOUNT(lit->bbox); ++k) {
|
|
PD_SWAP_VAL(lit->bbox[k].x);
|
|
PD_SWAP_VAL(lit->bbox[k].y);
|
|
PD_SWAP_VAL(lit->bbox[k].z);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|