mirror of
https://github.com/perfect-dark-pc-port/perfect_dark.git
synced 2026-10-23 15:52:41 +02:00
209 lines
4.5 KiB
C
209 lines
4.5 KiB
C
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <limits.h>
|
|
|
|
#include "preprocess/common.h"
|
|
#include "preprocess/gbi.h"
|
|
|
|
#if UINTPTR_MAX > 0xFFFFFFFFu
|
|
#define HOST_DWORDS_PER_CMD 2
|
|
#else
|
|
#define HOST_DWORDS_PER_CMD 1
|
|
#endif
|
|
|
|
struct vtx {
|
|
s16 x;
|
|
s16 y;
|
|
s16 z;
|
|
u8 flags;
|
|
u8 colour;
|
|
s16 s;
|
|
s16 t;
|
|
};
|
|
|
|
struct texaddr {
|
|
u32 src;
|
|
u32 dst;
|
|
};
|
|
|
|
static u32 gbiSegments[16];
|
|
static u32 srcVtxOffset;
|
|
static u32 dstVtxOffset;
|
|
|
|
static struct texaddr texAddrs[64];
|
|
static int numTexAddrs;
|
|
|
|
void gbiReset(void)
|
|
{
|
|
for (int i = 0; i < ARRAYCOUNT(gbiSegments); i++) {
|
|
gbiSegments[i] = 0;
|
|
}
|
|
|
|
srcVtxOffset = 0;
|
|
dstVtxOffset = 0;
|
|
numTexAddrs = 0;
|
|
}
|
|
|
|
void gbiSetSegment(int segment, u32 offset)
|
|
{
|
|
gbiSegments[segment] = offset & 0x00ffffff;
|
|
}
|
|
|
|
void gbiSetVtx(u32 src_offset, u32 dst_offset)
|
|
{
|
|
srcVtxOffset = src_offset & 0x00ffffff;
|
|
dstVtxOffset = dst_offset & 0x00ffffff;
|
|
}
|
|
|
|
void gbiAddTexAddr(u32 src_offset, u32 dst_offset)
|
|
{
|
|
texAddrs[numTexAddrs].src = src_offset & 0x00ffffff;
|
|
texAddrs[numTexAddrs++].dst = dst_offset & 0x00ffffff;
|
|
}
|
|
|
|
u32 gbiFindTexAddr(u32 src_offset)
|
|
{
|
|
for (int i = 0; i < numTexAddrs; i++) {
|
|
if (texAddrs[i].src == src_offset)
|
|
return texAddrs[i].dst;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void gbiConvertVtx(u8 *dst, u32 offset, int count)
|
|
{
|
|
if (!offset) return;
|
|
struct vtx* vtxs = (struct vtx*)(dst + offset);
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
struct vtx* vtx = &vtxs[i];
|
|
|
|
vtx->x = PD_BE16(vtx->x);
|
|
vtx->y = PD_BE16(vtx->y);
|
|
vtx->z = PD_BE16(vtx->z);
|
|
vtx->s = PD_BE16(vtx->s);
|
|
vtx->t = PD_BE16(vtx->t);
|
|
}
|
|
}
|
|
|
|
#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_IS_MOVEMEM(cmd) ((cmd & 0xff00000000000000) == 0x0300000000000000)
|
|
#define CMD_IS_MTX(cmd) ((cmd & 0xff00000000000000) == 0x0100000000000000)
|
|
#define CMD_IS_SETTIMG(cmd) ((cmd & 0xff00000000000000) == 0xfd00000000000000)
|
|
#define CMD_IS_SETZIMG(cmd) ((cmd & 0xff00000000000000) == 0xfe00000000000000)
|
|
#define CMD_IS_SETCIMG(cmd) ((cmd & 0xff00000000000000) == 0xff00000000000000)
|
|
|
|
#define CMD_HAS_ADDR(cmd) CMD_IS_VTX(cmd) \
|
|
|| CMD_IS_COL(cmd) \
|
|
|| CMD_IS_MOVEWORD(cmd) \
|
|
|| CMD_IS_SETTIMG(cmd)
|
|
|
|
|
|
#define CMD_IS_SEGMENTED(cmd) ( CMD_IS_MOVEMEM(cmd) \
|
|
|| CMD_IS_MTX(cmd) \
|
|
|| CMD_IS_VTX(cmd) \
|
|
|| CMD_IS_COL(cmd) \
|
|
|| CMD_IS_DL(cmd) \
|
|
|| CMD_IS_SETTIMG(cmd) \
|
|
|| CMD_IS_SETCIMG(cmd) \
|
|
|| CMD_IS_SETZIMG(cmd))
|
|
|
|
/**
|
|
* 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 u64 gbiRewriteAddr(u64 cmd, u8 opcode)
|
|
{
|
|
u8 segment = (cmd & 0x0f000000) >> 24;
|
|
u32 offset = cmd & 0x00ffffff;
|
|
|
|
if (segment == 5) {
|
|
if (opcode == 0xfd) {
|
|
offset = gbiFindTexAddr(offset);
|
|
}
|
|
else {
|
|
if (offset < srcVtxOffset) {
|
|
sysFatalError("Tried to load data from offset 0x%x but segment starts at 0x%x\n", offset, srcVtxOffset);
|
|
}
|
|
|
|
offset = offset - srcVtxOffset + dstVtxOffset;
|
|
}
|
|
}
|
|
|
|
return (cmd & 0xffffffffff000000) | offset;
|
|
}
|
|
|
|
void gbiGdlRewriteAddrs(u8 *dst, u32 offset)
|
|
{
|
|
if (!offset) return;
|
|
|
|
u64 *cmds = (u64 *)(dst + (offset & 0x00ffffff));
|
|
if (!cmds) return;
|
|
|
|
u64 cmd;
|
|
|
|
do {
|
|
cmd = *cmds;
|
|
Gfx* gfxcmd = (Gfx *)cmds;
|
|
int idx = 0;
|
|
u8 opcode = (cmd >> 24) & 0xff;
|
|
|
|
#if HOST_DWORDS_PER_CMD == 2
|
|
idx = 1;
|
|
opcode = (cmd >> 24) & 0xff;
|
|
#endif
|
|
cmd = (u64)opcode << 56;
|
|
|
|
if (CMD_HAS_ADDR(cmd)) {
|
|
cmds[idx] = gbiRewriteAddr(cmds[idx], opcode);
|
|
}
|
|
|
|
if (CMD_IS_SEGMENTED(cmd)) {
|
|
gfxcmd->words.w1 |= 1;
|
|
}
|
|
|
|
cmds += HOST_DWORDS_PER_CMD;
|
|
} while (!CMD_IS_ENDDL(cmd));
|
|
}
|
|
|
|
u32 gbiConvertGdl(u8 *dst, u32 dstpos, u8 *src, u32 srcpos, int segment_cmds)
|
|
{
|
|
dstpos = ALIGN8(dstpos);
|
|
|
|
u64 *n64_cmd = (u64*)&src[srcpos];
|
|
u64 *host_cmd = (u64*)&dst[dstpos];
|
|
u64 cmd;
|
|
|
|
do {
|
|
cmd = PD_BE64(*n64_cmd);
|
|
|
|
#if HOST_DWORDS_PER_CMD == 2
|
|
host_cmd[0] = ((cmd & 0xffffffff00000000) >> 32);
|
|
host_cmd[1] = (cmd & 0xffffffff);
|
|
|
|
if (segment_cmds && CMD_IS_SEGMENTED(cmd)) {
|
|
host_cmd[1] |= 1;
|
|
}
|
|
#else
|
|
host_cmd[0] = (cmd >> 32) | ((cmd & 0xffffffff) << 32);
|
|
|
|
if (segment_cmds && CMD_IS_SEGMENTED(cmd)) {
|
|
Gfx* gfxcmd = (Gfx*)host_cmd;
|
|
gfxcmd->words.w1 |= 1;
|
|
}
|
|
#endif
|
|
|
|
dstpos += sizeof(*host_cmd) * HOST_DWORDS_PER_CMD;
|
|
host_cmd += HOST_DWORDS_PER_CMD;
|
|
n64_cmd++;
|
|
} while (!CMD_IS_ENDDL(cmd));
|
|
|
|
return dstpos;
|
|
}
|