tp/libs/dolphin/gx/GXTransform.c

334 lines
10 KiB
C

#include "dolphin/gx/GXTransform.h"
#include "dolphin/gx.h"
void __GXSetMatrixIndex();
static void Copy6Floats(register f32 src[6], register f32 dst[6]) {
register f32 ps_0, ps_1, ps_2;
// clang-format off
asm {
psq_l ps_0, 0(src), 0, 0
psq_l ps_1, 8(src), 0, 0
psq_l ps_2, 16(src), 0, 0
psq_st ps_0, 0(dst), 0, 0
psq_st ps_1, 8(dst), 0, 0
psq_st ps_2, 16(dst), 0, 0
}
// clang-format on
}
static void WriteProjPS(const register f32 src[6], register volatile void* dst) {
register f32 ps_0, ps_1, ps_2;
// clang-format off
asm {
psq_l ps_0, 0(src), 0, 0
psq_l ps_1, 8(src), 0, 0
psq_l ps_2, 16(src), 0, 0
psq_st ps_0, 0(dst), 0, 0
psq_st ps_1, 0(dst), 0, 0
psq_st ps_2, 0(dst), 0, 0
}
// clang-format on
}
/* 8035FF60-803600D4 35A8A0 0174+00 0/0 1/1 0/0 .text GXProject */
void GXProject(f32 model_x, f32 model_y, f32 model_z, Mtx model_mtx, f32* proj_mtx, f32* viewpoint,
f32* screen_x, f32* screen_y, f32* screen_z) {
f32 sp10[3];
f32 var_f30;
f32 var_f29;
f32 var_f28;
f32 var_f31;
ASSERT(proj_mtx != NULL && viewpoint != NULL && screen_x != NULL && screen_y != NULL &&
screen_z != NULL,
"GXGet*: invalid null pointer");
sp10[0] = (model_mtx[0][0] * model_x) + (model_mtx[0][1] * model_y) +
(model_mtx[0][2] * model_z) + model_mtx[0][3];
sp10[1] = (model_mtx[1][0] * model_x) + (model_mtx[1][1] * model_y) +
(model_mtx[1][2] * model_z) + model_mtx[1][3];
sp10[2] = (model_mtx[2][0] * model_x) + (model_mtx[2][1] * model_y) +
(model_mtx[2][2] * model_z) + model_mtx[2][3];
if (proj_mtx[0] == 0.0f) {
var_f30 = (sp10[0] * proj_mtx[1]) + (sp10[2] * proj_mtx[2]);
var_f29 = (sp10[1] * proj_mtx[3]) + (sp10[2] * proj_mtx[4]);
var_f28 = proj_mtx[6] + (sp10[2] * proj_mtx[5]);
var_f31 = 1.0f / -sp10[2];
} else {
var_f30 = proj_mtx[2] + (sp10[0] * proj_mtx[1]);
var_f29 = proj_mtx[4] + (sp10[1] * proj_mtx[3]);
var_f28 = proj_mtx[6] + (sp10[2] * proj_mtx[5]);
var_f31 = 1.0f;
}
*screen_x = (viewpoint[2] / 2) + (viewpoint[0] + (var_f31 * (var_f30 * viewpoint[2] / 2)));
*screen_y = (viewpoint[3] / 2) + (viewpoint[1] + (var_f31 * (-var_f29 * viewpoint[3] / 2)));
*screen_z = viewpoint[5] + (var_f31 * (var_f28 * (viewpoint[5] - viewpoint[4])));
}
void __GXSetProjection(void) {
GX_XF_LOAD_REGS(6, GX_XF_REG_PROJECTIONA);
WriteProjPS(__GXData->projMtx, (volatile void*)GXFIFO_ADDR);
GX_WRITE_U32(__GXData->projType);
}
/* 803600D4-80360178 35AA14 00A4+00 0/0 15/15 2/2 .text GXSetProjection */
void GXSetProjection(const Mtx44 proj, GXProjectionType type) {
volatile void* fifo;
__GXData->projType = type;
__GXData->projMtx[0] = proj[0][0];
__GXData->projMtx[2] = proj[1][1];
__GXData->projMtx[4] = proj[2][2];
__GXData->projMtx[5] = proj[2][3];
if (type == GX_ORTHOGRAPHIC) {
__GXData->projMtx[1] = proj[0][3];
__GXData->projMtx[3] = proj[1][3];
} else {
__GXData->projMtx[1] = proj[0][2];
__GXData->projMtx[3] = proj[1][2];
}
__GXSetProjection();
__GXData->bpSentNot = GX_TRUE;
}
/* 80360178-80360204 35AAB8 008C+00 0/0 1/1 1/1 .text GXSetProjectionv */
void GXSetProjectionv(f32* proj) {
__GXData->projType = proj[0] == 0.0f ? GX_PERSPECTIVE : GX_ORTHOGRAPHIC;
Copy6Floats(&proj[1], __GXData->projMtx);
__GXSetProjection();
__GXData->bpSentNot = GX_TRUE;
}
/* 80360204-8036024C 35AB44 0048+00 0/0 1/1 1/1 .text GXGetProjectionv */
void GXGetProjectionv(f32* proj) {
*proj = (u32)__GXData->projType != GX_PERSPECTIVE ? 1.0f : 0.0f;
Copy6Floats(__GXData->projMtx, &proj[1]);
}
static void WriteMTXPS4x3(register volatile void* dst, register const Mtx src) {
register f32 ps_0, ps_1, ps_2, ps_3, ps_4, ps_5;
// clang-format off
asm {
psq_l ps_0, 0(src), 0, 0
psq_l ps_1, 8(src), 0, 0
psq_l ps_2, 16(src), 0, 0
psq_l ps_3, 24(src), 0, 0
psq_l ps_4, 32(src), 0, 0
psq_l ps_5, 40(src), 0, 0
psq_st ps_0, 0(dst), 0, 0
psq_st ps_1, 0(dst), 0, 0
psq_st ps_2, 0(dst), 0, 0
psq_st ps_3, 0(dst), 0, 0
psq_st ps_4, 0(dst), 0, 0
psq_st ps_5, 0(dst), 0, 0
}
// clang-format on
}
/* 8036024C-8036029C 35AB8C 0050+00 0/0 83/83 9/9 .text GXLoadPosMtxImm */
void GXLoadPosMtxImm(Mtx mtx, u32 id) {
GX_XF_LOAD_REGS(4 * 3 - 1, id * 4 + GX_XF_MEM_POSMTX);
WriteMTXPS4x3(&GXWGFifo, mtx);
}
static void WriteMTXPS3x3(register volatile void* dst, register const Mtx src) {
register f32 ps_0, ps_1, ps_2, ps_3, ps_4, ps_5;
// clang-format off
asm {
psq_l ps_0, 0(src), 0, 0
lfs ps_1, 8(src)
psq_l ps_2, 16(src), 0, 0
lfs ps_3, 24(src)
psq_l ps_4, 32(src), 0, 0
lfs ps_5, 40(src)
psq_st ps_0, 0(dst), 0, 0
stfs ps_1, 0(dst)
psq_st ps_2, 0(dst), 0, 0
stfs ps_3, 0(dst)
psq_st ps_4, 0(dst), 0, 0
stfs ps_5, 0(dst)
}
// clang-format on
}
/* 8036029C-803602EC 35ABDC 0050+00 0/0 11/11 7/7 .text GXLoadNrmMtxImm */
void GXLoadNrmMtxImm(Mtx mtx, u32 id) {
GX_XF_LOAD_REGS(3 * 3 - 1, id * 3 + GX_XF_MEM_NRMMTX);
WriteMTXPS3x3(&GXWGFifo, mtx);
}
/* 803602EC-80360320 35AC2C 0034+00 0/0 51/51 2/2 .text GXSetCurrentMtx */
void GXSetCurrentMtx(u32 id) {
GX_SET_REG(__GXData->matIdxA, id, GX_XF_MTXIDX0_GEOM_ST, GX_XF_MTXIDX0_GEOM_END);
__GXSetMatrixIndex(GX_VA_PNMTXIDX);
}
static void WriteMTXPS4x2(register volatile void* dst, register const Mtx src) {
register f32 ps_0, ps_1, ps_2, ps_3;
// clang-format off
asm {
psq_l ps_0, 0(src), 0, 0
psq_l ps_1, 8(src), 0, 0
psq_l ps_2, 16(src), 0, 0
psq_l ps_3, 24(src), 0, 0
psq_st ps_0, 0(dst), 0, 0
psq_st ps_1, 0(dst), 0, 0
psq_st ps_2, 0(dst), 0, 0
psq_st ps_3, 0(dst), 0, 0
}
// clang-format on
}
/* 80360320-803603D4 35AC60 00B4+00 0/0 15/15 0/0 .text GXLoadTexMtxImm */
void GXLoadTexMtxImm(const Mtx mtx, u32 id, GXTexMtxType type) {
u32 addr;
u32 num;
u32 reg;
// Matrix address in XF memory
addr = id >= GX_PTTEXMTX0 ? (id - GX_PTTEXMTX0) * 4 + GX_XF_MEM_DUALTEXMTX :
id * 4 + (u64)GX_XF_MEM_POSMTX;
// Number of elements in matrix
num = type == GX_MTX2x4 ? (u64)(2 * 4) : 3 * 4;
reg = addr | (num - 1) << 16;
GX_XF_LOAD_REG_HDR(reg);
if (type == GX_MTX3x4) {
WriteMTXPS4x3(&GXWGFifo, mtx);
} else {
WriteMTXPS4x2(&GXWGFifo, mtx);
}
}
/* 803603D4-80360464 35AD14 0090+00 1/1 0/0 0/0 .text __GXSetViewport */
void __GXSetViewport(void) {
f32 a, b, c, d, e, f;
f32 near, far;
a = __GXData->vpWd / 2;
b = -__GXData->vpHt / 2;
d = __GXData->vpLeft + (__GXData->vpWd / 2) + 342.0f;
e = __GXData->vpTop + (__GXData->vpHt / 2) + 342.0f;
near = __GXData->vpNearz * __GXData->zScale;
far = __GXData->vpFarz * __GXData->zScale;
c = far - near;
f = far + __GXData->zOffset;
GX_XF_LOAD_REGS(5, GX_XF_REG_SCALEX);
GX_WRITE_F32(a);
GX_WRITE_F32(b);
GX_WRITE_F32(c);
GX_WRITE_F32(d);
GX_WRITE_F32(e);
GX_WRITE_F32(f);
}
/* 80360464-803604AC 35ADA4 0048+00 0/0 10/10 1/1 .text GXSetViewport */
void GXSetViewport(f32 left, f32 top, f32 width, f32 height, f32 nearZ, f32 farZ) {
__GXData->vpLeft = left;
__GXData->vpTop = top;
__GXData->vpWd = width;
__GXData->vpHt = height;
__GXData->vpNearz = nearZ;
__GXData->vpFarz = farZ;
__GXSetViewport();
__GXData->bpSentNot = GX_TRUE;
}
/* 803604AC-803604D0 35ADEC 0024+00 0/0 1/1 1/1 .text GXGetViewportv */
void GXGetViewportv(f32* p) {
Copy6Floats(&__GXData->vpLeft, p);
}
/* 803604D0-80360548 35AE10 0078+00 0/0 11/11 4/4 .text GXSetScissor */
void GXSetScissor(u32 left, u32 top, u32 width, u32 height) {
u32 y1, x1, y2, x2;
u32 reg;
y1 = top + 342;
x1 = left + 342;
GX_SET_REG(__GXData->suScis0, y1, GX_BP_SCISSORTL_TOP_ST, GX_BP_SCISSORTL_TOP_END);
GX_SET_REG(__GXData->suScis0, x1, GX_BP_SCISSORTL_LEFT_ST, GX_BP_SCISSORTL_LEFT_END);
y2 = y1 + height - 1;
x2 = (x1 + width) - 1;
GX_SET_REG(__GXData->suScis1, y2, GX_BP_SCISSORBR_BOT_ST, GX_BP_SCISSORBR_BOT_END);
GX_SET_REG(__GXData->suScis1, x2, GX_BP_SCISSORBR_RIGHT_ST, GX_BP_SCISSORBR_RIGHT_END);
GX_BP_LOAD_REG(__GXData->suScis0);
GX_BP_LOAD_REG(__GXData->suScis1);
__GXData->bpSentNot = FALSE;
}
/* 80360548-80360590 35AE88 0048+00 0/0 6/6 2/2 .text GXGetScissor */
void GXGetScissor(u32* left, u32* top, u32* width, u32* height) {
u32 y1 = (__GXData->suScis0 & 0x0007FF) >> 0;
u32 x1 = (__GXData->suScis0 & 0x7FF000) >> 12;
u32 y2 = (__GXData->suScis1 & 0x0007FF) >> 0;
u32 x2 = (__GXData->suScis1 & 0x7FF000) >> 12;
*left = x1 - 0x156;
*top = y1 - 0x156;
*width = (x2 - x1) + 1;
*height = (y2 - y1) + 1;
}
/* 80360590-803605D0 35AED0 0040+00 0/0 1/1 0/0 .text GXSetScissorBoxOffset */
void GXSetScissorBoxOffset(s32 x, s32 y) {
u32 cmd = 0;
u32 x1;
u32 y1;
x1 = (u32)(x + 342) / 2;
y1 = (u32)(y + 342) / 2;
GX_SET_REG(cmd, x1, GX_BP_SCISSOROFS_OX_ST, GX_BP_SCISSOROFS_OX_END);
GX_SET_REG(cmd, y1, GX_BP_SCISSOROFS_OY_ST, GX_BP_SCISSOROFS_OY_END);
GX_SET_REG(cmd, GX_BP_REG_SCISSOROFFSET, 0, 7);
GX_BP_LOAD_REG(cmd);
__GXData->bpSentNot = GX_FALSE;
}
/* 803605D0-803605F8 35AF10 0028+00 0/0 27/27 2/2 .text GXSetClipMode */
void GXSetClipMode(GXClipMode mode) {
GX_XF_LOAD_REG(GX_XF_REG_CLIPDISABLE, mode);
__GXData->bpSentNot = GX_TRUE;
}
/* 803605F8-8036067C 35AF38 0084+00 1/1 1/1 0/0 .text __GXSetMatrixIndex */
void __GXSetMatrixIndex(GXAttr index) {
// Tex4 and after is stored in XF MatrixIndex1
if (index < GX_VA_TEX4MTXIDX) {
GX_CP_LOAD_REG(GX_CP_REG_MTXIDXA, __GXData->matIdxA);
GX_XF_LOAD_REG(GX_XF_REG_MATRIXINDEX0, __GXData->matIdxA);
} else {
GX_CP_LOAD_REG(GX_CP_REG_MTXIDXB, __GXData->matIdxB);
GX_XF_LOAD_REG(GX_XF_REG_MATRIXINDEX1, __GXData->matIdxB);
}
__GXData->bpSentNot = GX_TRUE;
}