#include #include #include #include #include #include #include #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); } } } } }