summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLagoLunatic <LagoLunatic@users.noreply.github.com>2024-09-07 17:31:29 -0400
committerLagoLunatic <LagoLunatic@users.noreply.github.com>2024-09-07 17:31:29 -0400
commit3e7ece6ff50f48dbce8b044cfcc0851ce4859789 (patch)
tree6ae26e70f5d6e3ad9c2497538ff54a6dbe82e77f /src
parent340d18c6bcc8d6e0640748273109c55ab058df7b (diff)
Copy dolphin/gx progress from TP
Diffstat (limited to 'src')
-rw-r--r--src/JSystem/J3DGraphBase/J3DGD.cpp2
-rw-r--r--src/JSystem/J3DGraphBase/J3DSys.cpp2
-rw-r--r--src/JSystem/JParticle/JPADraw.cpp16
-rw-r--r--src/d/d_kankyo_data.cpp4
-rw-r--r--src/dolphin/gx/GXAttr.c751
-rw-r--r--src/dolphin/gx/GXBump.c194
-rw-r--r--src/dolphin/gx/GXDisplayList.c21
-rw-r--r--src/dolphin/gx/GXDraw.c71
-rw-r--r--src/dolphin/gx/GXFifo.c337
-rw-r--r--src/dolphin/gx/GXFrameBuf.c638
-rw-r--r--src/dolphin/gx/GXGeometry.c149
-rw-r--r--src/dolphin/gx/GXInit.c561
-rw-r--r--src/dolphin/gx/GXLight.c294
-rw-r--r--src/dolphin/gx/GXMisc.c266
-rw-r--r--src/dolphin/gx/GXPerf.c384
-rw-r--r--src/dolphin/gx/GXPixel.c235
-rw-r--r--src/dolphin/gx/GXTev.c366
-rw-r--r--src/dolphin/gx/GXTexture.c593
-rw-r--r--src/dolphin/gx/GXTransform.c316
-rw-r--r--src/m_Do/m_Do_graphic.cpp4
20 files changed, 5190 insertions, 14 deletions
diff --git a/src/JSystem/J3DGraphBase/J3DGD.cpp b/src/JSystem/J3DGraphBase/J3DGD.cpp
index 95d501a8..555558cf 100644
--- a/src/JSystem/J3DGraphBase/J3DGD.cpp
+++ b/src/JSystem/J3DGraphBase/J3DGD.cpp
@@ -502,7 +502,7 @@ void J3DGDSetFog(GXFogType type, f32 startZ, f32 endZ, f32 nearZ, f32 farZ, GXCo
void J3DGDSetFogRangeAdj(u8 enabled, u16 center, GXFogAdjTable* pFogAdjTable) {
if (enabled) {
for (s32 i = 0; i < 10; i += 2) {
- J3DGDWriteBPCmd((0xe9 + i / 2) << 24 | pFogAdjTable->r[i + 1] << 12 | pFogAdjTable->r[i] << 0);
+ J3DGDWriteBPCmd((0xe9 + i / 2) << 24 | pFogAdjTable->fogVals[i + 1] << 12 | pFogAdjTable->fogVals[i] << 0);
}
}
diff --git a/src/JSystem/J3DGraphBase/J3DSys.cpp b/src/JSystem/J3DGraphBase/J3DSys.cpp
index 3ef85963..8e910641 100644
--- a/src/JSystem/J3DGraphBase/J3DSys.cpp
+++ b/src/JSystem/J3DGraphBase/J3DSys.cpp
@@ -148,7 +148,7 @@ void J3DSys::setTexCacheRegion(GXTexCacheSize size) {
/* 802D8EE0-802D956C .text drawInit__6J3DSysFv */
void J3DSys::drawInit() {
- GXSetMisc(2, 0);
+ GXSetMisc(GX_MT_DL_SAVE_CONTEXT, 0);
GXInvalidateVtxCache();
GXSetCurrentMtx(GX_PNMTX0);
GXSetCullMode(GX_CULL_BACK);
diff --git a/src/JSystem/JParticle/JPADraw.cpp b/src/JSystem/JParticle/JPADraw.cpp
index 5aeea12d..ac9a624a 100644
--- a/src/JSystem/JParticle/JPADraw.cpp
+++ b/src/JSystem/JParticle/JPADraw.cpp
@@ -822,7 +822,7 @@ void JPADraw::drawParticle() {
GXSetCullMode(GX_CULL_NONE);
if (dc.pbsp->isClipOn()) {
GXSetClipMode(GX_CLIP_ENABLE);
- GXSetMisc(1, 8);
+ GXSetMisc(GX_MT_XF_FLUSH, 8);
} else {
GXSetClipMode(GX_CLIP_DISABLE);
}
@@ -845,7 +845,7 @@ void JPADraw::drawParticle() {
}
}
- GXSetMisc(1, 0);
+ GXSetMisc(GX_MT_XF_FLUSH, 0);
}
/* 8026BC2C-8026BF88 .text drawChild__7JPADrawFv */
@@ -871,7 +871,7 @@ void JPADraw::drawChild() {
if (dc.pssp->isClipOn()) {
GXSetClipMode(GX_CLIP_ENABLE);
- GXSetMisc(1, 8);
+ GXSetMisc(GX_MT_XF_FLUSH, 8);
} else {
GXSetClipMode(GX_CLIP_DISABLE);
}
@@ -894,7 +894,7 @@ void JPADraw::drawChild() {
}
}
- GXSetMisc(1, 0);
+ GXSetMisc(GX_MT_XF_FLUSH, 0);
}
/* 8026BF88-8026C024 .text zDraw__7JPADrawFv */
@@ -922,7 +922,7 @@ void JPADraw::zDrawParticle() {
GXSetCullMode(GX_CULL_NONE);
if (dc.pbsp->isClipOn()) {
GXSetClipMode(GX_CLIP_ENABLE);
- GXSetMisc(1, 8);
+ GXSetMisc(GX_MT_XF_FLUSH, 8);
} else {
GXSetClipMode(GX_CLIP_DISABLE);
}
@@ -945,7 +945,7 @@ void JPADraw::zDrawParticle() {
}
}
- GXSetMisc(1, 0);
+ GXSetMisc(GX_MT_XF_FLUSH, 0);
}
/* 8026C24C-8026C4DC .text zDrawChild__7JPADrawFv */
@@ -971,7 +971,7 @@ void JPADraw::zDrawChild() {
if (dc.pssp->isClipOn()) {
GXSetClipMode(GX_CLIP_ENABLE);
- GXSetMisc(1, 8);
+ GXSetMisc(GX_MT_XF_FLUSH, 8);
} else {
GXSetClipMode(GX_CLIP_DISABLE);
}
@@ -994,7 +994,7 @@ void JPADraw::zDrawChild() {
}
}
- GXSetMisc(1, 0);
+ GXSetMisc(GX_MT_XF_FLUSH, 0);
}
/* 8026C4DC-8026C640 .text loadYBBMtx__7JPADrawFPA4_f */
diff --git a/src/d/d_kankyo_data.cpp b/src/d/d_kankyo_data.cpp
index a173a6d8..6107f5fd 100644
--- a/src/d/d_kankyo_data.cpp
+++ b/src/d/d_kankyo_data.cpp
@@ -441,7 +441,7 @@ dKyd_Schedule* dKyd_schejule_menu_getp() {
/* 80086F34-80086F74 .text dKyd_xfog_table_set__FUc */
void dKyd_xfog_table_set(u8 i_idx) {
for (int i = 0; i < 10; i++) {
- u16 fogAdjTableEntry = S_xfog_table_data[i_idx].r[i];
- g_env_light.mFogAdjTable.r[i] = fogAdjTableEntry;
+ u16 fogAdjTableEntry = S_xfog_table_data[i_idx].fogVals[i];
+ g_env_light.mFogAdjTable.fogVals[i] = fogAdjTableEntry;
}
}
diff --git a/src/dolphin/gx/GXAttr.c b/src/dolphin/gx/GXAttr.c
new file mode 100644
index 00000000..724710e9
--- /dev/null
+++ b/src/dolphin/gx/GXAttr.c
@@ -0,0 +1,751 @@
+#include "dolphin/gx/GXAttr.h"
+#include "dolphin/gx/GX.h"
+
+static inline void SETVCDATTR(GXAttr name, GXAttrType type) {
+ switch (name) {
+ case GX_VA_PNMTXIDX:
+ GX_SET_REG(__GXData->vcdLo, type, GX_CP_VCD_LO_POSMTXIDX_ST, GX_CP_VCD_LO_POSMTXIDX_END);
+ break;
+ case GX_VA_TEX0MTXIDX:
+ GX_SET_REG(__GXData->vcdLo, type, GX_CP_VCD_LO_TEX0MTXIDX_ST,
+ GX_CP_VCD_LO_TEX0MTXIDX_END);
+ break;
+ case GX_VA_TEX1MTXIDX:
+ GX_SET_REG(__GXData->vcdLo, type, GX_CP_VCD_LO_TEX1MTXIDX_ST,
+ GX_CP_VCD_LO_TEX1MTXIDX_END);
+ break;
+ case GX_VA_TEX2MTXIDX:
+ GX_SET_REG(__GXData->vcdLo, type, GX_CP_VCD_LO_TEX2MTXIDX_ST,
+ GX_CP_VCD_LO_TEX2MTXIDX_END);
+ break;
+ case GX_VA_TEX3MTXIDX:
+ GX_SET_REG(__GXData->vcdLo, type, GX_CP_VCD_LO_TEX3MTXIDX_ST,
+ GX_CP_VCD_LO_TEX3MTXIDX_END);
+ break;
+ case GX_VA_TEX4MTXIDX:
+ GX_SET_REG(__GXData->vcdLo, type, GX_CP_VCD_LO_TEX4MTXIDX_ST,
+ GX_CP_VCD_LO_TEX4MTXIDX_END);
+ break;
+ case GX_VA_TEX5MTXIDX:
+ GX_SET_REG(__GXData->vcdLo, type, GX_CP_VCD_LO_TEX5MTXIDX_ST,
+ GX_CP_VCD_LO_TEX5MTXIDX_END);
+ break;
+ case GX_VA_TEX6MTXIDX:
+ GX_SET_REG(__GXData->vcdLo, type, GX_CP_VCD_LO_TEX6MTXIDX_ST,
+ GX_CP_VCD_LO_TEX6MTXIDX_END);
+ break;
+ case GX_VA_TEX7MTXIDX:
+ GX_SET_REG(__GXData->vcdLo, type, GX_CP_VCD_LO_TEX7MTXIDX_ST,
+ GX_CP_VCD_LO_TEX7MTXIDX_END);
+ break;
+ case GX_VA_POS:
+ GX_SET_REG(__GXData->vcdLo, type, GX_CP_VCD_LO_POS_ST, GX_CP_VCD_LO_POS_END);
+ break;
+ case GX_VA_NRM:
+ if (type != GX_NONE) {
+ __GXData->hasNrms = TRUE;
+ __GXData->hasBiNrms = FALSE;
+ __GXData->nrmType = type;
+ } else {
+ __GXData->hasNrms = FALSE;
+ }
+ break;
+ case GX_VA_NBT:
+ if (type != GX_NONE) {
+ __GXData->hasBiNrms = TRUE;
+ __GXData->hasNrms = FALSE;
+ __GXData->nrmType = type;
+ } else {
+ __GXData->hasBiNrms = FALSE;
+ }
+ break;
+ case GX_VA_CLR0:
+ GX_SET_REG(__GXData->vcdLo, type, GX_CP_VCD_LO_CLRDIF_ST, GX_CP_VCD_LO_CLRDIF_END);
+ break;
+ case GX_VA_CLR1:
+ GX_SET_REG(__GXData->vcdLo, type, GX_CP_VCD_LO_CLRSPEC_ST, GX_CP_VCD_LO_CLRSPEC_END);
+ break;
+ case GX_VA_TEX0:
+ GX_SET_REG(__GXData->vcdHi, type, GX_CP_VCD_HI_TEX0COORD_ST, GX_CP_VCD_HI_TEX0COORD_END);
+ break;
+ case GX_VA_TEX1:
+ GX_SET_REG(__GXData->vcdHi, type, GX_CP_VCD_HI_TEX1COORD_ST, GX_CP_VCD_HI_TEX1COORD_END);
+ break;
+ case GX_VA_TEX2:
+ GX_SET_REG(__GXData->vcdHi, type, GX_CP_VCD_HI_TEX2COORD_ST, GX_CP_VCD_HI_TEX2COORD_END);
+ break;
+ case GX_VA_TEX3:
+ GX_SET_REG(__GXData->vcdHi, type, GX_CP_VCD_HI_TEX3COORD_ST, GX_CP_VCD_HI_TEX3COORD_END);
+ break;
+ case GX_VA_TEX4:
+ GX_SET_REG(__GXData->vcdHi, type, GX_CP_VCD_HI_TEX4COORD_ST, GX_CP_VCD_HI_TEX4COORD_END);
+ break;
+ case GX_VA_TEX5:
+ GX_SET_REG(__GXData->vcdHi, type, GX_CP_VCD_HI_TEX5COORD_ST, GX_CP_VCD_HI_TEX5COORD_END);
+ break;
+ case GX_VA_TEX6:
+ GX_SET_REG(__GXData->vcdHi, type, GX_CP_VCD_HI_TEX6COORD_ST, GX_CP_VCD_HI_TEX6COORD_END);
+ break;
+ case GX_VA_TEX7:
+ GX_SET_REG(__GXData->vcdHi, type, GX_CP_VCD_HI_TEX7COORD_ST, GX_CP_VCD_HI_TEX7COORD_END);
+ break;
+ }
+}
+
+void GXSetVtxDesc(GXAttr name, GXAttrType type) {
+ SETVCDATTR(name, type);
+
+ // Set normal data type if enabled
+ if (__GXData->hasNrms || __GXData->hasBiNrms) {
+ GX_BITFIELD_SET(__GXData->vcdLo, 19, 2, __GXData->nrmType);
+ } else {
+ GX_BITFIELD_SET(__GXData->vcdLo, 19, 2, 0);
+ }
+
+ __GXData->dirtyState |= GX_DIRTY_VCD;
+}
+
+void GXSetVtxDescv(GXVtxDescList* list) {
+ for (; list->attr != GX_VA_NULL; list++) {
+ SETVCDATTR(list->attr, list->type);
+ }
+
+ // Set normal data type if enabled
+ if (__GXData->hasNrms || __GXData->hasBiNrms) {
+ GX_BITFIELD_SET(__GXData->vcdLo, 19, 2, __GXData->nrmType);
+ } else {
+ GX_BITFIELD_SET(__GXData->vcdLo, 19, 2, 0);
+ }
+
+ __GXData->dirtyState |= GX_DIRTY_VCD;
+}
+
+static void __GXXfVtxSpecs(void) {
+ u32 normCount, colorCount, texCount;
+
+ normCount = __GXData->hasBiNrms ? 2 : (__GXData->hasNrms ? 1 : 0);
+
+ // Both fields in one access
+ colorCount = 33 - __cntlzw((__GXData->vcdLo & (0xf << 0xd)) >> 0xd);
+ colorCount /= 2; // equivalent to /=2 and >>= 1
+
+ // All 16 assigned bits in VCD_Hi
+ texCount = 33 - __cntlzw((__GXData->vcdHi & (0xffff << 0)) >> 0);
+ texCount /= 2; // equivalent to /=2 and >>= 1
+
+ GX_XF_LOAD_REG(GX_XF_REG_INVERTEXSPEC, (colorCount) | (normCount << 2) | (texCount << 4));
+ __GXData->bpSentNot = GX_TRUE;
+
+ return;
+}
+
+void __GXSetVCD(void) {
+ GX_CP_LOAD_REG(GX_CP_REG_VCD_LO, __GXData->vcdLo);
+ GX_CP_LOAD_REG(GX_CP_REG_VCD_HI, __GXData->vcdHi);
+
+ __GXXfVtxSpecs();
+}
+
+void __GXCalculateVLim(void) {
+ static u8 tbl1[] = {0, 4, 1, 2};
+ static u8 tbl2[] = {0, 8, 1, 2};
+ static u8 tbl3[] = {0, 12, 1, 2};
+
+ u32 vlim;
+ u32 vcdLoReg;
+ u32 vcdHiReg;
+ s32 compCnt;
+
+ if (__GXData->vNum == 0) {
+ return;
+ }
+
+ vcdLoReg = __GXData->vcdLo;
+ vcdHiReg = __GXData->vcdHi;
+
+ // GXCompCnt bit of normal parameters
+ compCnt = __GXData->vatA[GX_VTXFMT0];
+ compCnt = (compCnt & 0x200) >> 9;
+
+ vlim = GX_GET_REG(vcdLoReg, GX_CP_VCD_LO_POSMTXIDX_ST, GX_CP_VCD_LO_POSMTXIDX_END);
+ vlim += GX_GET_REG(vcdLoReg, GX_CP_VCD_LO_TEX0MTXIDX_ST, GX_CP_VCD_LO_TEX0MTXIDX_END);
+ vlim += GX_GET_REG(vcdLoReg, GX_CP_VCD_LO_TEX1MTXIDX_ST, GX_CP_VCD_LO_TEX1MTXIDX_END);
+ vlim += GX_GET_REG(vcdLoReg, GX_CP_VCD_LO_TEX2MTXIDX_ST, GX_CP_VCD_LO_TEX2MTXIDX_END);
+ vlim += GX_GET_REG(vcdLoReg, GX_CP_VCD_LO_TEX3MTXIDX_ST, GX_CP_VCD_LO_TEX3MTXIDX_END);
+ vlim += GX_GET_REG(vcdLoReg, GX_CP_VCD_LO_TEX4MTXIDX_ST, GX_CP_VCD_LO_TEX4MTXIDX_END);
+ vlim += GX_GET_REG(vcdLoReg, GX_CP_VCD_LO_TEX5MTXIDX_ST, GX_CP_VCD_LO_TEX5MTXIDX_END);
+ vlim += GX_GET_REG(vcdLoReg, GX_CP_VCD_LO_TEX6MTXIDX_ST, GX_CP_VCD_LO_TEX6MTXIDX_END);
+ vlim += GX_GET_REG(vcdLoReg, GX_CP_VCD_LO_TEX7MTXIDX_ST, GX_CP_VCD_LO_TEX7MTXIDX_END);
+
+ vlim += tbl3[GX_GET_REG(vcdLoReg, GX_CP_VCD_LO_POS_ST, GX_CP_VCD_LO_POS_END)];
+ vlim += tbl3[GX_GET_REG(vcdLoReg, GX_CP_VCD_LO_NRM_ST, GX_CP_VCD_LO_NRM_END)] *
+ (compCnt == GX_NRM_NBT ? 3 : 1);
+ vlim += tbl1[GX_GET_REG(vcdLoReg, GX_CP_VCD_LO_CLRDIF_ST, GX_CP_VCD_LO_CLRDIF_END)];
+ vlim += tbl1[GX_GET_REG(vcdLoReg, GX_CP_VCD_LO_CLRSPEC_ST, GX_CP_VCD_LO_CLRSPEC_END)];
+
+ vlim += tbl2[GX_GET_REG(vcdHiReg, GX_CP_VCD_HI_TEX0COORD_ST, GX_CP_VCD_HI_TEX0COORD_END)];
+ vlim += tbl2[GX_GET_REG(vcdHiReg, GX_CP_VCD_HI_TEX1COORD_ST, GX_CP_VCD_HI_TEX1COORD_END)];
+ vlim += tbl2[GX_GET_REG(vcdHiReg, GX_CP_VCD_HI_TEX2COORD_ST, GX_CP_VCD_HI_TEX2COORD_END)];
+ vlim += tbl2[GX_GET_REG(vcdHiReg, GX_CP_VCD_HI_TEX3COORD_ST, GX_CP_VCD_HI_TEX3COORD_END)];
+ vlim += tbl2[GX_GET_REG(vcdHiReg, GX_CP_VCD_HI_TEX4COORD_ST, GX_CP_VCD_HI_TEX4COORD_END)];
+ vlim += tbl2[GX_GET_REG(vcdHiReg, GX_CP_VCD_HI_TEX5COORD_ST, GX_CP_VCD_HI_TEX5COORD_END)];
+ vlim += tbl2[GX_GET_REG(vcdHiReg, GX_CP_VCD_HI_TEX6COORD_ST, GX_CP_VCD_HI_TEX6COORD_END)];
+ vlim += tbl2[GX_GET_REG(vcdHiReg, GX_CP_VCD_HI_TEX7COORD_ST, GX_CP_VCD_HI_TEX7COORD_END)];
+
+ __GXData->vLim = vlim;
+}
+
+void GXGetVtxDesc(int param_0, GXAttrType* param_1) {
+ int local_38;
+
+ switch (param_0) {
+ case 0:
+ local_38 = __GXData->vcdLo & 1;
+ break;
+ case 1:
+ local_38 = (__GXData->vcdLo & 2) >> 1;
+ break;
+ case 2:
+ local_38 = (__GXData->vcdLo & 4) >> 2;
+ break;
+ case 3:
+ local_38 = (__GXData->vcdLo & 8) >> 3;
+ break;
+ case 4:
+ local_38 = (__GXData->vcdLo & 0x10) >> 4;
+ break;
+ case 5:
+ local_38 = (__GXData->vcdLo & 0x20) >> 5;
+ break;
+ case 6:
+ local_38 = (__GXData->vcdLo & 0x40) >> 6;
+ break;
+ case 7:
+ local_38 = (__GXData->vcdLo & 0x80) >> 7;
+ break;
+ case 8:
+ local_38 = (__GXData->vcdLo & 0x100) >> 8;
+ break;
+ case 9:
+ local_38 = (__GXData->vcdLo & 0x600) >> 9;
+ break;
+ case 10:
+ if (__GXData->hasNrms != 0) {
+ local_38 = (__GXData->vcdLo & 0x1800) >> 11;
+ } else {
+ local_38 = 0;
+ }
+ break;
+ case 0x19:
+ if (__GXData->hasBiNrms != 0) {
+ local_38 = (__GXData->vcdLo & 0x1800) >> 11;
+ } else {
+ local_38 = 0;
+ }
+ break;
+ case 11:
+ local_38 = (__GXData->vcdLo & 0x6000) >> 13;
+ break;
+ case 12:
+ local_38 = (__GXData->vcdLo & 0x18000) >> 15;
+ break;
+ case 13:
+ local_38 = (__GXData->vcdHi & 3);
+ break;
+ case 14:
+ local_38 = (__GXData->vcdHi & 0xC) >> 2;
+ break;
+ case 15:
+ local_38 = (__GXData->vcdHi & 0x30) >> 4;
+ break;
+ case 16:
+ local_38 = (__GXData->vcdHi & 0xC0) >> 6;
+ break;
+ case 17:
+ local_38 = (__GXData->vcdHi & 0x300) >> 8;
+ break;
+ case 18:
+ local_38 = (__GXData->vcdHi & 0xC00) >> 10;
+ break;
+ case 19:
+ local_38 = (__GXData->vcdHi & 0x3000) >> 12;
+ break;
+ case 20:
+ local_38 = (__GXData->vcdHi & 0xC000) >> 14;
+ break;
+ default:
+ local_38 = 0;
+ break;
+ }
+
+ *param_1 = local_38;
+}
+
+void GXGetVtxDescv(GXVtxDescList* attrPtr) {
+ int i;
+
+ for (i = 0; i <= 0x14; i++) {
+ attrPtr[i].attr = (GXAttr)i;
+ GXGetVtxDesc(i, &attrPtr[i].type);
+ }
+
+ attrPtr[i].attr = (GXAttr)0x19;
+ GXGetVtxDesc(0x19, &attrPtr[i].type);
+
+ i++;
+ attrPtr[i].attr = (GXAttr)0xFF;
+}
+
+void GXClearVtxDesc(void) {
+ __GXData->vcdLo = 0;
+ GX_BITFIELD_SET(__GXData->vcdLo, 0x15, 2, GX_DIRECT);
+ __GXData->vcdHi = 0;
+ __GXData->hasNrms = FALSE;
+ __GXData->hasBiNrms = FALSE;
+ __GXData->dirtyState |= GX_DIRTY_VCD;
+}
+
+/* ############################################################################################## */
+
+static inline void SETVAT(u32* vatA, u32* vatB, u32* vatC, GXAttr attr, GXCompCnt compCnt,
+ GXCompType compType, u8 shift) {
+ switch (attr) {
+ case GX_VA_POS:
+ GX_SET_REG(*vatA, compCnt, GX_CP_VAT_GRP0_POS_CNT_ST, GX_CP_VAT_GRP0_POS_CNT_END);
+ GX_SET_REG(*vatA, compType, GX_CP_VAT_GRP0_POS_TYPE_ST, GX_CP_VAT_GRP0_POS_TYPE_END);
+ GX_SET_REG(*vatA, shift, GX_CP_VAT_GRP0_POS_SHIFT_ST, GX_CP_VAT_GRP0_POS_SHIFT_END);
+ break;
+ case GX_VA_NRM:
+ case GX_VA_NBT:
+ GX_SET_REG(*vatA, compType, GX_CP_VAT_GRP0_NRM_TYPE_ST, GX_CP_VAT_GRP0_NRM_TYPE_END);
+ if (compCnt == GX_NRM_NBT3) {
+ // Probably because the compCnt can only be one bit?
+ GX_SET_REG(*vatA, GX_NRM_NBT, GX_CP_VAT_GRP0_NRM_CNT_ST, GX_CP_VAT_GRP0_NRM_CNT_END);
+ GX_SET_REG(*vatA, TRUE, GX_CP_VAT_GRP0_NRMIDX3_ST, GX_CP_VAT_GRP0_NRMIDX3_END);
+ } else {
+ GX_SET_REG(*vatA, compCnt, GX_CP_VAT_GRP0_NRM_CNT_ST, GX_CP_VAT_GRP0_NRM_CNT_END);
+ GX_SET_REG(*vatA, FALSE, GX_CP_VAT_GRP0_NRMIDX3_ST, GX_CP_VAT_GRP0_NRMIDX3_END);
+ }
+ break;
+ case GX_VA_CLR0:
+ GX_SET_REG(*vatA, compCnt, GX_CP_VAT_GRP0_CLRDIFF_CNT_ST, GX_CP_VAT_GRP0_CLRDIFF_CNT_END);
+ GX_SET_REG(*vatA, compType, GX_CP_VAT_GRP0_CLRDIFF_TYPE_ST,
+ GX_CP_VAT_GRP0_CLRDIFF_TYPE_END);
+ break;
+ case GX_VA_CLR1:
+ GX_SET_REG(*vatA, compCnt, GX_CP_VAT_GRP0_CLRSPEC_CNT_ST, GX_CP_VAT_GRP0_CLRSPEC_CNT_END);
+ GX_SET_REG(*vatA, compType, GX_CP_VAT_GRP0_CLRSPEC_TYPE_ST,
+ GX_CP_VAT_GRP0_CLRSPEC_TYPE_END);
+ break;
+ case GX_VA_TEX0:
+ GX_SET_REG(*vatA, compCnt, GX_CP_VAT_GRP0_TXC0_CNT_ST, GX_CP_VAT_GRP0_TXC0_CNT_END);
+ GX_SET_REG(*vatA, compType, GX_CP_VAT_GRP0_TXC0_TYPE_ST, GX_CP_VAT_GRP0_TXC0_TYPE_END);
+ GX_SET_REG(*vatA, shift, GX_CP_VAT_GRP0_TXC0_SHIFT_ST, GX_CP_VAT_GRP0_TXC0_SHIFT_END);
+ break;
+ case GX_VA_TEX1:
+ GX_SET_REG(*vatB, compCnt, GX_CP_VAT_GRP1_TXC1_CNT_ST, GX_CP_VAT_GRP1_TXC1_CNT_END);
+ GX_SET_REG(*vatB, compType, GX_CP_VAT_GRP1_TXC1_TYPE_ST, GX_CP_VAT_GRP1_TXC1_TYPE_END);
+ GX_SET_REG(*vatB, shift, GX_CP_VAT_GRP1_TXC1_SHIFT_ST, GX_CP_VAT_GRP1_TXC1_SHIFT_END);
+ break;
+ case GX_VA_TEX2:
+ GX_SET_REG(*vatB, compCnt, GX_CP_VAT_GRP1_TXC2_CNT_ST, GX_CP_VAT_GRP1_TXC2_CNT_END);
+ GX_SET_REG(*vatB, compType, GX_CP_VAT_GRP1_TXC2_TYPE_ST, GX_CP_VAT_GRP1_TXC2_TYPE_END);
+ GX_SET_REG(*vatB, shift, GX_CP_VAT_GRP1_TXC2_SHIFT_ST, GX_CP_VAT_GRP1_TXC2_SHIFT_END);
+ break;
+ case GX_VA_TEX3:
+ GX_SET_REG(*vatB, compCnt, GX_CP_VAT_GRP1_TXC3_CNT_ST, GX_CP_VAT_GRP1_TXC3_CNT_END);
+ GX_SET_REG(*vatB, compType, GX_CP_VAT_GRP1_TXC3_TYPE_ST, GX_CP_VAT_GRP1_TXC3_TYPE_END);
+ GX_SET_REG(*vatB, shift, GX_CP_VAT_GRP1_TXC3_SHIFT_ST, GX_CP_VAT_GRP1_TXC3_SHIFT_END);
+ break;
+ case GX_VA_TEX4:
+ GX_SET_REG(*vatB, compCnt, GX_CP_VAT_GRP1_TXC4_CNT_ST, GX_CP_VAT_GRP1_TXC4_CNT_END);
+ GX_SET_REG(*vatB, compType, GX_CP_VAT_GRP1_TXC4_TYPE_ST, GX_CP_VAT_GRP1_TXC4_TYPE_END);
+ GX_SET_REG(*vatC, shift, GX_CP_VAT_GRP2_TXC4_SHIFT_ST, GX_CP_VAT_GRP2_TXC4_SHIFT_END);
+ break;
+ case GX_VA_TEX5:
+ GX_SET_REG(*vatC, compCnt, GX_CP_VAT_GRP2_TXC5_CNT_ST, GX_CP_VAT_GRP2_TXC5_CNT_END);
+ GX_SET_REG(*vatC, compType, GX_CP_VAT_GRP2_TXC5_TYPE_ST, GX_CP_VAT_GRP2_TXC5_TYPE_END);
+ GX_SET_REG(*vatC, shift, GX_CP_VAT_GRP2_TXC5_SHIFT_ST, GX_CP_VAT_GRP2_TXC5_SHIFT_END);
+ break;
+ case GX_VA_TEX6:
+ GX_SET_REG(*vatC, compCnt, GX_CP_VAT_GRP2_TXC6_CNT_ST, GX_CP_VAT_GRP2_TXC6_CNT_END);
+ GX_SET_REG(*vatC, compType, GX_CP_VAT_GRP2_TXC6_TYPE_ST, GX_CP_VAT_GRP2_TXC6_TYPE_END);
+ GX_SET_REG(*vatC, shift, GX_CP_VAT_GRP2_TXC6_SHIFT_ST, GX_CP_VAT_GRP2_TXC6_SHIFT_END);
+ break;
+ case GX_VA_TEX7:
+ GX_SET_REG(*vatC, compCnt, GX_CP_VAT_GRP2_TXC7_CNT_ST, GX_CP_VAT_GRP2_TXC7_CNT_END);
+ GX_SET_REG(*vatC, compType, GX_CP_VAT_GRP2_TXC7_TYPE_ST, GX_CP_VAT_GRP2_TXC7_TYPE_END);
+ GX_SET_REG(*vatC, shift, GX_CP_VAT_GRP2_TXC7_SHIFT_ST, GX_CP_VAT_GRP2_TXC7_SHIFT_END);
+ break;
+ }
+}
+
+void GXSetVtxAttrFmt(GXVtxFmt format, GXAttr attr, GXCompCnt count, GXCompType type, u8 frac) {
+ u32* vA = (u32*)&__GXData->vatA[format];
+ u32* vB = (u32*)&__GXData->vatB[format];
+ u32* vC = &__GXData->vatC[format];
+
+ SETVAT(vA, vB, vC, attr, count, type, frac);
+
+ __GXData->dirtyState |= GX_DIRTY_VAT;
+ __GXData->dirtyVAT |= (u8)(1 << (u8)format);
+}
+
+void GXSetVtxAttrFmtv(GXVtxFmt format, GXVtxAttrFmtList* list) {
+ u32* vatA;
+ u32* vatB;
+ u32* vatC;
+
+ vatA = (u32*)&__GXData->vatA[format];
+ vatB = (u32*)&__GXData->vatB[format];
+ vatC = &__GXData->vatC[format];
+
+ for (; list->mAttrib != GX_VA_NULL; list++) {
+ SETVAT(vatA, vatB, vatC, list->mAttrib, list->mCompCnt, list->mCompType, list->mCompShift);
+ }
+
+ __GXData->dirtyState |= GX_DIRTY_VAT;
+ __GXData->dirtyVAT |= (u8)(1 << (u8)format);
+}
+
+void __GXSetVAT(void) {
+ u32 i = 0;
+ u32 dirtyVAT = __GXData->dirtyVAT;
+ do {
+ if (dirtyVAT & (1)) {
+ GX_CP_LOAD_REG(GX_CP_REG_VAT_GRP0 | i, __GXData->vatA[i]);
+ GX_CP_LOAD_REG(GX_CP_REG_VAT_GRP1 | i, __GXData->vatB[i]);
+ GX_CP_LOAD_REG(GX_CP_REG_VAT_GRP2 | i, __GXData->vatC[i]);
+ }
+ dirtyVAT >>= 1;
+ i++;
+ } while (dirtyVAT != 0);
+
+ __GXData->dirtyVAT = 0;
+}
+
+static u8 GetFracForNrm(int param_0) {
+ int var_r31;
+
+ switch (param_0) {
+ case 1:
+ var_r31 = 6;
+ break;
+ case 3:
+ var_r31 = 14;
+ break;
+ default:
+ case 2:
+ var_r31 = 0;
+ break;
+ }
+
+ return var_r31;
+}
+
+void GXGetVtxAttrFmtv(GXVtxFmt param_0, GXVtxAttrFmtList* param_1) {
+ s32 tmp;
+ s32 tmp2;
+ s32 tmp3;
+ int i;
+
+#ifdef DEBUG
+ // not fully matching
+ /* tmp = 1;
+ if (data_8074d3c8 != 0) {
+ OSPanic("GXAttr.c", 941, "\'GXGetVtxAttrFmtv\' is not allowed between GXBegin/GXEnd");
+ tmp = 0;
+ }
+
+ tmp2 = 1;
+ if (param_1 == NULL) {
+ OSPanic("GXAttr.c", 942, "GXSetVtxAttrFmt: list pointer is NULL");
+ tmp2 = 0;
+ }
+
+ tmp3 = 1;
+ if (param_0 >= 8) {
+ OSPanic("GXAttr.c", 943, "GXSetVtxAttrFmt: Format Index is out of range");
+ tmp3 = 0;
+ } */
+#endif
+
+ for (i = 9; i <= 0x14; i++) {
+ param_1->mAttrib = i;
+ GXGetVtxAttrFmt(param_0, i, &param_1->mCompCnt, &param_1->mCompType, &param_1->mCompShift);
+ param_1++;
+ }
+
+ param_1->mAttrib = 0xFF;
+}
+
+void GXGetVtxAttrFmt(GXVtxFmt param_0, int param_1, GXCompCnt* param_2, GXCompType* param_3,
+ u8* param_4) {
+ s32 tmp;
+ s32 tmp2;
+ GXCompCnt* tmp_1;
+ GXCompCnt* tmp_2;
+ u32* tmp_3;
+
+#ifdef DEBUG
+ // not fully matching
+ /* tmp = 1;
+ if (data_8074d3c8) {
+ OSPanic("GXAttr.c", 844, "\'GXGetVtxAttrFmt\' is not allowed between GXBegin/GXEnd");
+ tmp = 0;
+ }
+
+ tmp2 = 1;
+ if (param_0 >= 8) {
+ OSPanic("GXAttr.c", 845, "GXSetVtxAttrFmt: Format Index is out of range");
+ tmp2 = 0;
+ } */
+#endif
+
+ tmp_1 = (GXCompCnt*)&__GXData->vatA[param_0];
+ tmp_2 = (GXCompCnt*)&__GXData->vatB[param_0];
+ tmp_3 = &__GXData->vatC[param_0];
+
+ switch (param_1) {
+ case 9:
+ *param_2 = *tmp_1 & 1;
+ *param_3 = (*tmp_1 & 0xE) >> 1;
+ *param_4 = (*tmp_1 & 0x1F0) >> 4;
+ break;
+ case 10:
+ case 0x19:
+ *param_2 = (*tmp_1 & 0x200) >> 9;
+ if (*param_2 == 1 && ((*tmp_1 & 0x80000000) >> 31) != 0) {
+ *param_2 = 2;
+ }
+
+ *param_3 = (*tmp_1 & 0x1C00) >> 10;
+ *param_4 = GetFracForNrm(*param_3);
+ break;
+ case 11:
+ *param_2 = (*tmp_1 & 0x2000) >> 0xd;
+ *param_3 = (*tmp_1 & 0x1C000) >> 0xe;
+ *param_4 = 0;
+ break;
+ case 12:
+ *param_2 = (*tmp_1 & 0x20000) >> 0x11;
+ *param_3 = (*tmp_1 & 0x1C0000) >> 0x12;
+ *param_4 = 0;
+ break;
+ case 13:
+ *param_2 = (*tmp_1 & 0x200000) >> 0x15;
+ *param_3 = (*tmp_1 & 0x1C00000) >> 0x16;
+ *param_4 = ((*tmp_1 & 0x3e000000)) >> 25;
+ break;
+ case 14:
+ *param_2 = *tmp_2 & 1;
+ *param_3 = (*tmp_2 & 0xE) >> 1;
+ *param_4 = (*tmp_2 & 0x1F0) >> 4;
+ break;
+ case 15:
+ *param_2 = (*tmp_2 & 0x200) >> 9;
+ *param_3 = (*tmp_2 & 0x1C00) >> 10;
+ *param_4 = (*tmp_2 & 0x3E000) >> 13;
+ break;
+ case 16:
+ *param_2 = (*tmp_2 & 0x40000) >> 0x12;
+ *param_3 = (*tmp_2 & 0x380000) >> 0x13;
+ *param_4 = (*tmp_2 & 0x7C00000) >> 0x16;
+ break;
+ case 17:
+ *param_2 = (*tmp_2 & 0x8000000) >> 0x1B;
+ *param_3 = (*tmp_2 & 0x70000000) >> 0x1C;
+ *param_4 = (*tmp_3 & 0x1F);
+ break;
+ case 18:
+ *param_2 = (*tmp_3 & 0x20) >> 5;
+ *param_3 = (*tmp_3 & 0x1C0) >> 6;
+ *param_4 = (*tmp_3 & 0x3E00) >> 9;
+ break;
+ case 19:
+ *param_2 = (*tmp_3 & 0x4000) >> 0xe;
+ *param_3 = (*tmp_3 & 0x38000) >> 0xf;
+ *param_4 = (*tmp_3 & 0x7c0000) >> 0x12;
+ break;
+ case 20:
+ *param_2 = (*tmp_3 & 0x800000) >> 0x17;
+ *param_3 = (*tmp_3 & 0x7000000) >> 0x18;
+ *param_4 = (*tmp_3 & 0xF8000000) >> 0x1b;
+ break;
+ default:
+ *param_2 = 1;
+ *param_3 = 0;
+ *param_4 = 0;
+ }
+}
+
+void GXSetArray(GXAttr attr, void* basePtr, u8 stride) {
+ s32 newAttr;
+ s32 attrReg;
+
+ newAttr = attr;
+ if (newAttr == GX_VA_NBT) {
+ newAttr = GX_VA_NRM;
+ }
+
+ attrReg = newAttr - GX_VA_POS;
+
+ GX_CP_LOAD_REG(GX_BP_REG_SETMODE0_TEX4 | attrReg,
+ // Address -> offset?
+ (u32)basePtr & ~0xC0000000);
+
+ GX_CP_LOAD_REG(GX_BP_REG_SETIMAGE2_TEX4 | attrReg, stride);
+}
+
+void GXInvalidateVtxCache(void) {
+ GXFIFO.u8 = GX_FIFO_CMD_INVAL_VTX;
+}
+
+void GXSetTexCoordGen2(GXTexCoordID id, GXTexGenType type, GXTexGenSrc src, u32 texMtxIdx,
+ GXBool normalize, u32 dualTexMtxIdx) {
+ u32 reg;
+ u32 inputRow;
+ GXXfTexReg inputForm;
+
+ reg = 0;
+ inputForm = GX_XF_TEX_FORM_AB11;
+ inputRow = 5;
+
+ switch (src) {
+ case GX_TG_POS:
+ inputRow = 0;
+ inputForm = GX_XF_TEX_FORM_ABC1;
+ break;
+ case GX_TG_NRM:
+ inputRow = 1;
+ inputForm = GX_XF_TEX_FORM_ABC1;
+ break;
+ case GX_TG_BINRM:
+ inputRow = 3;
+ inputForm = GX_XF_TEX_FORM_ABC1;
+ break;
+ case GX_TG_TANGENT:
+ inputRow = 4;
+ inputForm = GX_XF_TEX_FORM_ABC1;
+ break;
+ case GX_TG_COLOR0:
+ inputRow = 2;
+ break;
+ case GX_TG_COLOR1:
+ inputRow = 2;
+ break;
+ case GX_TG_TEX0:
+ inputRow = 5;
+ break;
+ case GX_TG_TEX1:
+ inputRow = 6;
+ break;
+ case GX_TG_TEX2:
+ inputRow = 7;
+ break;
+ case GX_TG_TEX3:
+ inputRow = 8;
+ break;
+ case GX_TG_TEX4:
+ inputRow = 9;
+ break;
+ case GX_TG_TEX5:
+ inputRow = 10;
+ break;
+ case GX_TG_TEX6:
+ inputRow = 11;
+ break;
+ case GX_TG_TEX7:
+ inputRow = 12;
+ break;
+ }
+
+ switch (type) {
+ case GX_TG_NRM:
+ GX_SET_REG(reg, GX_XF_TEX_PROJ_ST, GX_XF_TEX_PROJTYPE_ST,
+ GX_XF_TEX_PROJTYPE_END); // 2x4 projection
+ GX_SET_REG(reg, inputForm, GX_XF_TEX_INPUTFORM_ST, GX_XF_TEX_INPUTFORM_END);
+ GX_SET_REG(reg, GX_TG_POS, GX_XF_TEX_TEXGENTYPE_ST, GX_XF_TEX_TEXGENTYPE_END);
+ GX_SET_REG(reg, inputRow, GX_XF_TEX_SRCROW_ST, GX_XF_TEX_SRCROW_END);
+ break;
+ case GX_TG_POS:
+ GX_SET_REG(reg, GX_XF_TEX_PROJ_STQ, GX_XF_TEX_PROJTYPE_ST,
+ GX_XF_TEX_PROJTYPE_END); // 3x4 projection
+ GX_SET_REG(reg, inputForm, GX_XF_TEX_INPUTFORM_ST, GX_XF_TEX_INPUTFORM_END);
+ GX_SET_REG(reg, GX_TG_POS, GX_XF_TEX_TEXGENTYPE_ST, GX_XF_TEX_TEXGENTYPE_END);
+ GX_SET_REG(reg, inputRow, GX_XF_TEX_SRCROW_ST, GX_XF_TEX_SRCROW_END);
+ break;
+ case GX_TG_BUMP0:
+ case GX_TG_BUMP1:
+ case GX_TG_BUMP2:
+ case GX_TG_BUMP3:
+ case GX_TG_BUMP4:
+ case GX_TG_BUMP5:
+ case GX_TG_BUMP6:
+ case GX_TG_BUMP7:
+ GX_SET_REG(reg, GX_XF_TEX_PROJ_ST, GX_XF_TEX_PROJTYPE_ST,
+ GX_XF_TEX_PROJTYPE_END); // 2x4 projection
+ GX_SET_REG(reg, inputForm, GX_XF_TEX_INPUTFORM_ST, GX_XF_TEX_INPUTFORM_END);
+ GX_SET_REG(reg, GX_TG_NRM, GX_XF_TEX_TEXGENTYPE_ST, GX_XF_TEX_TEXGENTYPE_END);
+ GX_SET_REG(reg, inputRow, GX_XF_TEX_SRCROW_ST, GX_XF_TEX_SRCROW_END);
+ GX_SET_REG(reg, src - GX_TG_TEXCOORD0, GX_XF_TEX_BUMPSRCTEX_ST, GX_XF_TEX_BUMPSRCTEX_END);
+ GX_SET_REG(reg, type - GX_TG_BUMP0, GX_XF_TEX_BUMPSRCLIGHT_ST, GX_XF_TEX_BUMPSRCLIGHT_END);
+ break;
+ case GX_TG_SRTG:
+ GX_SET_REG(reg, GX_XF_TEX_PROJ_ST, GX_XF_TEX_PROJTYPE_ST,
+ GX_XF_TEX_PROJTYPE_END); // 2x4 projection
+ GX_SET_REG(reg, inputForm, GX_XF_TEX_INPUTFORM_ST, GX_XF_TEX_INPUTFORM_END);
+
+ if (src == GX_TG_COLOR0) {
+ GX_SET_REG(reg, GX_XF_TG_CLR0, GX_XF_TEX_TEXGENTYPE_ST, GX_XF_TEX_TEXGENTYPE_END);
+ } else {
+ GX_SET_REG(reg, GX_XF_TG_CLR1, GX_XF_TEX_TEXGENTYPE_ST, GX_XF_TEX_TEXGENTYPE_END);
+ }
+ GX_SET_REG(reg, 2, GX_XF_TEX_SRCROW_ST, GX_XF_TEX_SRCROW_END);
+ break;
+ default:
+ break;
+ }
+
+ GX_XF_LOAD_REG(GX_XF_REG_TEX0 + id, reg);
+
+ reg = 0;
+ GX_SET_REG(reg, dualTexMtxIdx - 0x40, GX_XF_MTXIDX0_GEOM_ST, GX_XF_MTXIDX0_GEOM_END);
+ GX_SET_REG(reg, normalize, GX_XF_DUALTEX_NORMALISE_ST, GX_XF_DUALTEX_NORMALISE_END);
+
+ GX_XF_LOAD_REG(GX_XF_REG_DUALTEX0 + id, reg);
+
+ switch (id) {
+ case GX_TEXCOORD0:
+ GX_SET_REG(__GXData->matIdxA, texMtxIdx, GX_XF_MTXIDX0_TEX0_ST, GX_XF_MTXIDX0_TEX0_END);
+ break;
+ case GX_TEXCOORD1:
+ GX_SET_REG(__GXData->matIdxA, texMtxIdx, GX_XF_MTXIDX0_TEX1_ST, GX_XF_MTXIDX0_TEX1_END);
+ break;
+ case GX_TEXCOORD2:
+ GX_SET_REG(__GXData->matIdxA, texMtxIdx, GX_XF_MTXIDX0_TEX2_ST, GX_XF_MTXIDX0_TEX2_END);
+ break;
+ case GX_TEXCOORD3:
+ GX_SET_REG(__GXData->matIdxA, texMtxIdx, GX_XF_MTXIDX0_TEX3_ST, GX_XF_MTXIDX0_TEX3_END);
+ break;
+ case GX_TEXCOORD4:
+ GX_SET_REG(__GXData->matIdxB, texMtxIdx, GX_XF_MTXIDX1_TEX4_ST, GX_XF_MTXIDX1_TEX4_END);
+ break;
+ case GX_TEXCOORD5:
+ GX_SET_REG(__GXData->matIdxB, texMtxIdx, GX_XF_MTXIDX1_TEX5_ST, GX_XF_MTXIDX1_TEX5_END);
+ break;
+ case GX_TEXCOORD6:
+ GX_SET_REG(__GXData->matIdxB, texMtxIdx, GX_XF_MTXIDX1_TEX6_ST, GX_XF_MTXIDX1_TEX6_END);
+ break;
+ default:
+ GX_SET_REG(__GXData->matIdxB, texMtxIdx, GX_XF_MTXIDX1_TEX7_ST, GX_XF_MTXIDX1_TEX7_END);
+ break;
+ }
+ __GXSetMatrixIndex(id + 1);
+}
+
+void GXSetNumTexGens(u8 count) {
+ GX_SET_REG(__GXData->genMode, count, GX_BP_GENMODE_NUMTEX_ST, GX_BP_GENMODE_NUMTEX_END);
+ GX_XF_LOAD_REG(GX_XF_REG_NUMTEX, count);
+ __GXData->dirtyState |= GX_DIRTY_GEN_MODE;
+}
diff --git a/src/dolphin/gx/GXBump.c b/src/dolphin/gx/GXBump.c
new file mode 100644
index 00000000..8c1084df
--- /dev/null
+++ b/src/dolphin/gx/GXBump.c
@@ -0,0 +1,194 @@
+/**
+ * GXBump.c
+ * Description:
+ */
+
+#include "dolphin/gx/GXBump.h"
+#include "dolphin/gx/GX.h"
+
+void GXSetTevIndirect(GXTevStageID tevStage, GXIndTexStageID texStage, GXIndTexFormat texFmt,
+ GXIndTexBiasSel biasSel, GXIndTexMtxID mtxID, GXIndTexWrap wrapS,
+ GXIndTexWrap wrapT, u8 addPrev, u8 utcLod, GXIndTexAlphaSel alphaSel) {
+ u32 field = 0;
+ u32 stage = tevStage + 0x10;
+
+ GX_BITFIELD_SET(field, 30, 2, texStage);
+ GX_BITFIELD_SET(field, 28, 2, texFmt);
+ GX_BITFIELD_SET(field, 25, 3, biasSel);
+ GX_BITFIELD_SET(field, 23, 2, alphaSel);
+ GX_BITFIELD_SET(field, 19, 4, mtxID);
+ GX_BITFIELD_SET(field, 16, 3, wrapS);
+ GX_BITFIELD_SET(field, 13, 3, wrapT);
+ GX_BITFIELD_SET(field, 12, 1, utcLod);
+ GX_BITFIELD_SET(field, 11, 1, addPrev);
+ GX_BITFIELD_SET(field, 0, 8, stage);
+
+ GXFIFO.u8 = 0x61;
+ GXFIFO.s32 = field;
+
+ __GXData->bpSentNot = 0;
+}
+
+void GXSetIndTexMtx(GXIndTexMtxID mtxID, f32 offset[6], s8 scale_exp) {
+ u32 val;
+ u32 field;
+ f32 mtx2[6];
+
+ scale_exp += 17;
+
+ switch (mtxID) {
+ case GX_ITM_0:
+ case GX_ITM_1:
+ case GX_ITM_2:
+ val = mtxID - 1;
+ break;
+ case GX_ITM_S0:
+ case GX_ITM_S1:
+ case GX_ITM_S2:
+ val = mtxID - 5;
+ break;
+ case GX_ITM_T0:
+ case GX_ITM_T1:
+ case GX_ITM_T2:
+ val = mtxID - 9;
+ break;
+ case GX_ITM_3:
+ case GX_ITM_S3:
+ default:
+ val = 0;
+ }
+
+ field = 0;
+ GX_BITFIELD_SET(field, 21, 11, 1024.0f * offset[0]);
+ GX_BITFIELD_SET(field, 10, 11, 1024.0f * offset[3]);
+ GX_BITFIELD_SET(field, 8, 2, (scale_exp >> 0) & 3);
+ GX_BITFIELD_SET(field, 0, 8, val * 3 + 6);
+ GXFIFO.u8 = 0x61;
+ GXFIFO.s32 = field;
+
+ field = 0;
+ GX_BITFIELD_SET(field, 21, 11, 1024.0f * offset[1]);
+ GX_BITFIELD_SET(field, 10, 11, 1024.0f * offset[4]);
+ GX_BITFIELD_SET(field, 8, 2, (scale_exp >> 2) & 3);
+ GX_BITFIELD_SET(field, 0, 8, val * 3 + 7);
+ GXFIFO.u8 = 0x61;
+ GXFIFO.s32 = field;
+
+ field = 0;
+ GX_BITFIELD_SET(field, 21, 11, 1024.0f * offset[2]);
+ GX_BITFIELD_SET(field, 10, 11, 1024.0f * offset[5]);
+ GX_BITFIELD_SET(field, 8, 2, (scale_exp >> 4) & 3);
+ GX_BITFIELD_SET(field, 0, 8, val * 3 + 8);
+ GXFIFO.u8 = 0x61;
+ GXFIFO.s32 = field;
+
+ __GXData->bpSentNot = 0;
+}
+
+void GXSetIndTexCoordScale(GXIndTexStageID texStage, GXIndTexScale scaleS, GXIndTexScale scaleT) {
+ GXData* data;
+
+ switch (texStage) {
+ case GX_INDTEXSTAGE0:
+ data = __GXData;
+ GX_BITFIELD_SET(data->IndTexScale0, 28, 4, scaleS);
+ GX_BITFIELD_SET(data->IndTexScale0, 24, 4, scaleT);
+ GX_BITFIELD_SET(data->IndTexScale0, 0, 8, 0x25);
+ GXFIFO.u8 = 0x61;
+ GXFIFO.s32 = data->IndTexScale0;
+ break;
+ case GX_INDTEXSTAGE1:
+ data = __GXData;
+ GX_BITFIELD_SET(data->IndTexScale0, 20, 4, scaleS);
+ GX_BITFIELD_SET(data->IndTexScale0, 16, 4, scaleT);
+ GX_BITFIELD_SET(data->IndTexScale0, 0, 8, 0x25);
+ GXFIFO.u8 = 0x61;
+ GXFIFO.s32 = data->IndTexScale0;
+ break;
+ case GX_INDTEXSTAGE2:
+ data = __GXData;
+ GX_BITFIELD_SET(data->IndTexScale1, 28, 4, scaleS);
+ GX_BITFIELD_SET(data->IndTexScale1, 24, 4, scaleT);
+ GX_BITFIELD_SET(data->IndTexScale1, 0, 8, 0x26);
+ GXFIFO.u8 = 0x61;
+ GXFIFO.s32 = data->IndTexScale1;
+ break;
+ case GX_INDTEXSTAGE3:
+ data = __GXData;
+ GX_BITFIELD_SET(data->IndTexScale1, 20, 4, scaleS);
+ GX_BITFIELD_SET(data->IndTexScale1, 16, 4, scaleT);
+ GX_BITFIELD_SET(data->IndTexScale1, 0, 8, 0x26);
+ GXFIFO.u8 = 0x61;
+ GXFIFO.s32 = data->IndTexScale1;
+ break;
+ }
+
+ __GXData->bpSentNot = 0;
+}
+
+void GXSetIndTexOrder(GXIndTexStageID stage, GXTexCoordID coord, GXTexMapID map) {
+ GXData* data;
+
+ if (map == 0xFF) {
+ map = GX_TEXMAP0;
+ }
+
+ if (coord == 0xFF) {
+ coord = GX_TEXCOORD0;
+ }
+
+ switch (stage) {
+ case GX_INDTEXSTAGE0:
+ data = __GXData;
+ GX_BITFIELD_SET(data->iref, 29, 3, map);
+ GX_BITFIELD_SET(data->iref, 26, 3, coord);
+ break;
+ case GX_INDTEXSTAGE1:
+ data = __GXData;
+ GX_BITFIELD_SET(data->iref, 23, 3, map);
+ GX_BITFIELD_SET(data->iref, 20, 3, coord);
+ break;
+ case GX_INDTEXSTAGE2:
+ data = __GXData;
+ GX_BITFIELD_SET(data->iref, 17, 3, map);
+ GX_BITFIELD_SET(data->iref, 14, 3, coord);
+ break;
+ case GX_INDTEXSTAGE3:
+ data = __GXData;
+ GX_BITFIELD_SET(data->iref, 11, 3, map);
+ GX_BITFIELD_SET(data->iref, 8, 3, coord);
+ break;
+ }
+
+ GXFIFO.u8 = 0x61;
+ GXFIFO.s32 = __GXData->iref;
+ GXSetWasteFlags();
+}
+
+void GXSetNumIndStages(u8 num) {
+ GXData* data = __GXData;
+ GX_BITFIELD_SET(data->genMode, 13, 3, num);
+ data->dirtyState |= GX_DIRTY_BP_MASK | GX_DIRTY_GEN_MODE;
+}
+
+void GXSetTevDirect(GXTevStageID stage) {
+ GXSetTevIndirect(stage, GX_INDTEXSTAGE0, GX_ITF_8, GX_ITB_NONE, GX_ITM_OFF, GX_ITW_OFF,
+ GX_ITW_OFF, FALSE, FALSE, GX_ITBA_OFF);
+}
+
+void __GXUpdateBPMask(void) {}
+
+void __GXSetIndirectMask(u32 mask) {
+ GXData* data = __GXData;
+
+ GX_BITFIELD_SET(data->bpMask, 24, 8, mask);
+ GXFIFO.u8 = 0x61;
+ GXFIFO.s32 = data->bpMask;
+ data->bpSentNot = 0;
+}
+
+void __GXFlushTextureState(void) {
+ GXFIFO.u8 = 0x61;
+ GXFIFO.s32 = __GXData->bpMask;
+ __GXData->bpSentNot = 0;
+}
diff --git a/src/dolphin/gx/GXDisplayList.c b/src/dolphin/gx/GXDisplayList.c
new file mode 100644
index 00000000..eaebb628
--- /dev/null
+++ b/src/dolphin/gx/GXDisplayList.c
@@ -0,0 +1,21 @@
+/**
+ * GXDisplayList.c
+ * Description:
+ */
+
+#include "dolphin/gx/GXDisplayList.h"
+#include "dolphin/gx/GX.h"
+
+void GXCallDisplayList(void* list, u32 nbytes) {
+ if (__GXData->dirtyState != 0) {
+ __GXSetDirtyState();
+ }
+
+ if (*(u32*)__GXData == 0) {
+ __GXSendFlushPrim();
+ }
+
+ GXFIFO.u8 = 0x40;
+ GXFIFO.u32 = (u32)list;
+ GXFIFO.u32 = nbytes;
+}
diff --git a/src/dolphin/gx/GXDraw.c b/src/dolphin/gx/GXDraw.c
new file mode 100644
index 00000000..22311b3b
--- /dev/null
+++ b/src/dolphin/gx/GXDraw.c
@@ -0,0 +1,71 @@
+#include "dolphin/gx/GXDraw.h"
+#include "dolphin/gx/GX.h"
+
+static GXVtxDescList vcd[27];
+static GXVtxAttrFmtList vat[27];
+
+void GetVertState(void) {
+ GXGetVtxDescv(vcd);
+ GXGetVtxAttrFmtv(GX_VTXFMT3, vat);
+ GXClearVtxDesc();
+ GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
+ GXSetVtxDesc(GX_VA_NRM, GX_DIRECT);
+ GXSetVtxAttrFmt(GX_VTXFMT3, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
+ GXSetVtxAttrFmt(GX_VTXFMT3, GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0);
+}
+
+void RestoreVertState(void) {
+ GXSetVtxDescv(vcd);
+ GXSetVtxAttrFmtv(GX_VTXFMT3, vat);
+}
+
+// doesn't fully match debug
+void GXDrawCylinder(u8 numEdges) {
+ f32 temp_f29;
+ f32 temp_f30;
+ f32 temp_f31;
+
+ s32 i;
+
+ f32 sp1A0[100];
+ f32 sp10[100];
+
+ temp_f31 = 1.0f;
+ temp_f30 = -temp_f31;
+
+ GetVertState();
+ for (i = 0; i <= numEdges; i++) {
+ temp_f29 = (i * 2.0f * 3.141593f) / numEdges;
+ sp1A0[i] = cosf(temp_f29);
+ sp10[i] = sinf(temp_f29);
+ }
+
+ GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT3, (numEdges + 1) * 2);
+ for (i = 0; i <= numEdges; i++) {
+ GXPosition3f32(sp1A0[i], sp10[i], temp_f30);
+ GXNormal3f32(sp1A0[i], sp10[i], 0.0f);
+ GXPosition3f32(sp1A0[i], sp10[i], temp_f31);
+ GXNormal3f32(sp1A0[i], sp10[i], 0.0f);
+ }
+ GXEnd();
+
+ GXBegin(GX_TRIANGLEFAN, GX_VTXFMT3, numEdges + 2);
+ GXPosition3f32(0.0f, 0.0f, temp_f31);
+ GXNormal3f32(0.0f, 0.0f, 1.0f);
+ for (i = 0; i <= numEdges; i++) {
+ GXPosition3f32(sp1A0[i], -sp10[i], temp_f31);
+ GXNormal3f32(0.0f, 0.0f, 1.0f);
+ }
+ GXEnd();
+
+ GXBegin(GX_TRIANGLEFAN, GX_VTXFMT3, numEdges + 2);
+ GXPosition3f32(0.0f, 0.0f, temp_f30);
+ GXNormal3f32(0.0f, 0.0f, -1.0f);
+ for (i = 0; i <= numEdges; i++) {
+ GXPosition3f32(sp1A0[i], sp10[i], temp_f30);
+ GXNormal3f32(0.0f, 0.0f, -1.0f);
+ }
+ GXEnd();
+
+ RestoreVertState();
+} \ No newline at end of file
diff --git a/src/dolphin/gx/GXFifo.c b/src/dolphin/gx/GXFifo.c
new file mode 100644
index 00000000..7ff20556
--- /dev/null
+++ b/src/dolphin/gx/GXFifo.c
@@ -0,0 +1,337 @@
+#include "dolphin/gx/GXFifo.h"
+#include "dolphin/gx/GX.h"
+#include "dolphin/os/OS.h"
+
+static void GXInitFifoLimits(GXFifoObj* fifo, u32 hi_watermark, u32 lo_watermark);
+
+static GXFifoObj* CPUFifo;
+
+static GXFifoObj* GPFifo;
+
+static OSThread* __GXCurrentThread;
+
+static GXBool data_80451954;
+
+static u32 GXOverflowSuspendInProgress;
+
+static GXBreakPtCallback BreakPointCB;
+
+static u32 __GXOverflowCount;
+
+static void GXOverflowHandler() {
+ __GXOverflowCount += 1;
+ __GXWriteFifoIntEnable(0, 1);
+ __GXWriteFifoIntReset(1, 0);
+ GXOverflowSuspendInProgress = TRUE;
+ OSSuspendThread(__GXCurrentThread);
+}
+
+static void GXUnderflowHandler() {
+ OSResumeThread(__GXCurrentThread);
+ GXOverflowSuspendInProgress = FALSE;
+ __GXWriteFifoIntReset(1, 1);
+ __GXWriteFifoIntEnable(1, 0);
+}
+
+static void GXBreakPointHandler(OSContext* context) {
+ OSContext bpContext;
+
+ FAST_FLAG_SET(__GXData->cpEnable, 0, 5, 1);
+ GX_SET_CP_REG(1, __GXData->cpEnable);
+
+ if (BreakPointCB) {
+ OSClearContext(&bpContext);
+ OSSetCurrentContext(&bpContext);
+ BreakPointCB();
+ OSClearContext(&bpContext);
+ OSSetCurrentContext(context);
+ }
+}
+
+static void GXCPInterruptHandler(s16 p1, OSContext* context) {
+ __GXData->cpStatus = GX_GET_CP_REG(0);
+
+ if ((__GXData->cpEnable >> 3 & 1) && (__GXData->cpStatus >> 1 & 1)) {
+ GXUnderflowHandler();
+ }
+
+ if ((__GXData->cpEnable >> 2 & 1) && (__GXData->cpStatus >> 0 & 1)) {
+ GXOverflowHandler();
+ }
+
+ if ((__GXData->cpEnable >> 5 & 1) && (__GXData->cpStatus >> 4 & 1)) {
+ GXBreakPointHandler(context);
+ }
+}
+
+void GXInitFifoBase(GXFifoObj* fifo, void* base, u32 size) {
+ fifo->base = base;
+ fifo->end = (void*)((u32)base + size - 4);
+ fifo->size = size;
+ fifo->rw_dst = 0;
+ GXInitFifoLimits(fifo, size - 0x4000, OSRoundDown32B(size / 2));
+ GXInitFifoPtrs(fifo, base, base);
+}
+
+void GXInitFifoPtrs(GXFifoObj* fifo, void* readPtr, void* writePtr) {
+ int interrupts = OSDisableInterrupts();
+ fifo->read_ptr = readPtr;
+ fifo->write_ptr = writePtr;
+ fifo->rw_dst = (u32)writePtr - (u32)readPtr;
+ if (fifo->rw_dst < 0) {
+ fifo->rw_dst += fifo->size;
+ }
+ OSRestoreInterrupts(interrupts);
+}
+
+static void GXInitFifoLimits(GXFifoObj* fifo, u32 hi_watermark, u32 lo_watermark) {
+ fifo->high_wtrmark = hi_watermark;
+ fifo->low_wtrmark = lo_watermark;
+}
+
+void GXSetCPUFifo(GXFifoObj* fifo) {
+ BOOL interrupts;
+ interrupts = OSDisableInterrupts();
+
+ CPUFifo = fifo;
+
+ if (fifo == GPFifo) {
+ u32 reg;
+ GX_SET_PI_REG(3, (u32)fifo->base & 0x3FFFFFFF);
+ GX_SET_PI_REG(4, (u32)fifo->end & 0x3FFFFFFF);
+ reg = 0;
+ GX_BITFIELD_SET(reg, 6, 21, (u32)fifo->write_ptr >> 5);
+ GX_BITFIELD_SET(reg, 5, 1, 0);
+ GX_SET_PI_REG(5, reg);
+
+ data_80451954 = GX_TRUE;
+
+ __GXWriteFifoIntReset(1, 1);
+ __GXWriteFifoIntEnable(1, 0);
+ __GXFifoLink(1);
+ } else {
+ u32 reg;
+ if (data_80451954) {
+ __GXFifoLink(0);
+ data_80451954 = GX_FALSE;
+ }
+ __GXWriteFifoIntEnable(0, 0);
+
+ GX_SET_PI_REG(3, (u32)fifo->base & 0x3FFFFFFF);
+ GX_SET_PI_REG(4, (u32)fifo->end & 0x3FFFFFFF);
+ reg = 0;
+ GX_BITFIELD_SET(reg, 6, 21, (u32)fifo->write_ptr >> 5);
+ GX_BITFIELD_SET(reg, 5, 1, 0);
+ GX_SET_PI_REG(5, reg);
+ }
+
+ PPCSync();
+
+ OSRestoreInterrupts(interrupts);
+}
+
+void GXSetGPFifo(GXFifoObj* fifo) {
+ int interrupts = OSDisableInterrupts();
+ u32 reg;
+ __GXFifoReadDisable();
+ __GXWriteFifoIntEnable(0, 0);
+ GPFifo = fifo;
+ GX_SET_CP_REG(16, (u16)fifo->base);
+ GX_SET_CP_REG(18, (u16)fifo->end);
+ GX_SET_CP_REG(24, (u16)fifo->rw_dst);
+ GX_SET_CP_REG(26, (u16)fifo->write_ptr);
+ GX_SET_CP_REG(28, (u16)fifo->read_ptr);
+ GX_SET_CP_REG(20, (u16)fifo->high_wtrmark);
+ GX_SET_CP_REG(22, (u16)fifo->low_wtrmark);
+
+ GX_SET_CP_REG(17, ((u32)fifo->base & 0x3FFFFFFF) >> 16);
+ GX_SET_CP_REG(19, ((u32)fifo->end & 0x3FFFFFFF) >> 16);
+ GX_SET_CP_REG(25, (fifo->rw_dst) >> 16);
+ GX_SET_CP_REG(27, ((u32)fifo->write_ptr & 0x3FFFFFFF) >> 16);
+ GX_SET_CP_REG(29, ((u32)fifo->read_ptr & 0x3FFFFFFF) >> 16);
+ GX_SET_CP_REG(21, (fifo->high_wtrmark) >> 16);
+ GX_SET_CP_REG(23, (fifo->low_wtrmark) >> 16);
+
+ PPCSync();
+
+ if (CPUFifo == GPFifo) {
+ data_80451954 = 1;
+ __GXWriteFifoIntEnable(1, 0);
+ __GXFifoLink(1);
+ } else {
+ data_80451954 = 0;
+ __GXWriteFifoIntEnable(0, 0);
+ __GXFifoLink(0);
+ }
+ reg = __GXData->cpEnable;
+ GX_BITFIELD_SET(reg, 0x1e, 1, 0);
+ GX_BITFIELD_SET(reg, 0x1a, 1, 0);
+ GX_SET_CP_REG(1, reg);
+ GX_SET_CP_REG(1, __GXData->cpEnable);
+ __GXWriteFifoIntReset(1, 1);
+ __GXFifoReadEnable();
+ OSRestoreInterrupts(interrupts);
+}
+
+void GXSaveCPUFifo(GXFifoObj* fifo) {
+ GXFlush();
+ __GXSaveCPUFifoAux(fifo);
+}
+
+void __GXSaveCPUFifoAux(GXFifoObj* fifo) {
+ int interrupts = OSDisableInterrupts();
+ fifo->base = OSPhysicalToCached(GX_GET_PI_REG(3));
+ fifo->end = OSPhysicalToCached(GX_GET_PI_REG(4));
+ fifo->write_ptr = OSPhysicalToCached(GX_GET_PI_REG(5) & ~0x4000000);
+ if (data_80451954 != 0) {
+ u32 reg2 = GX_GET_CP_REG(28) | (GX_GET_CP_REG(29) << 16);
+ fifo->read_ptr = (void*)(reg2 + -0x80000000);
+ fifo->rw_dst = (((u32)GX_GET_CP_REG(24) | (GX_GET_CP_REG(25) << 16)));
+ } else {
+ fifo->rw_dst = (u32)fifo->write_ptr - (u32)fifo->read_ptr;
+ if (fifo->rw_dst < 0) {
+ fifo->rw_dst += fifo->size;
+ }
+ }
+ OSRestoreInterrupts(interrupts);
+}
+
+void GXGetGPStatus(GXBool* overhi, GXBool* underlow, GXBool* readIdle, GXBool* cmdIdle,
+ GXBool* brkpt) {
+ __GXData->cpStatus = GX_GET_CP_REG(0);
+ *overhi = __GXData->cpStatus & 1;
+ *underlow = (__GXData->cpStatus >> 1) & 1;
+ *readIdle = (__GXData->cpStatus >> 2) & 1;
+ *cmdIdle = (__GXData->cpStatus >> 3) & 1;
+ *brkpt = (__GXData->cpStatus >> 4) & 1;
+}
+
+void* GXGetFifoBase(GXFifoObj* fifo) {
+ return fifo->base;
+}
+
+u32 GXGetFifoSize(GXFifoObj* fifo) {
+ return fifo->size;
+}
+
+GXBreakPtCallback GXSetBreakPtCallback(GXBreakPtCallback cb) {
+ GXBreakPtCallback oldCallback = BreakPointCB;
+ int interrupts = OSDisableInterrupts();
+ BreakPointCB = cb;
+ OSRestoreInterrupts(interrupts);
+ return oldCallback;
+}
+
+void __GXFifoInit(void) {
+ __OSSetInterruptHandler(0x11, GXCPInterruptHandler);
+ __OSUnmaskInterrupts(0x4000);
+ __GXCurrentThread = OSGetCurrentThread();
+ GXOverflowSuspendInProgress = 0;
+ CPUFifo = NULL;
+ GPFifo = NULL;
+}
+
+void __GXFifoReadEnable(void) {
+ FAST_FLAG_SET(__GXData->cpEnable, 1, 0, 1);
+ GX_SET_CP_REG(1, __GXData->cpEnable);
+}
+
+void __GXFifoReadDisable(void) {
+ FAST_FLAG_SET(__GXData->cpEnable, 0, 0, 1);
+ GX_SET_CP_REG(1, __GXData->cpEnable);
+}
+
+void __GXFifoLink(u8 link) {
+ u32 b;
+ if (link) {
+ b = 1;
+ } else {
+ b = 0;
+ }
+ FAST_FLAG_SET(__GXData->cpEnable, b, 4, 1);
+ GX_SET_CP_REG(1, __GXData->cpEnable);
+}
+
+void __GXWriteFifoIntEnable(u32 p1, u32 p2) {
+ FAST_FLAG_SET(__GXData->cpEnable, p1, 2, 1);
+ FAST_FLAG_SET(__GXData->cpEnable, (u8)p2, 3, 1);
+ GX_SET_CP_REG(1, __GXData->cpEnable);
+}
+
+void __GXWriteFifoIntReset(u32 p1, u32 p2) {
+ FAST_FLAG_SET(__GXData->cpClr, p1, 0, 1);
+ FAST_FLAG_SET(__GXData->cpClr, (u8)p2, 1, 1);
+ GX_SET_CP_REG(2, __GXData->cpClr);
+}
+
+void __GXCleanGPFifo(void) {
+ BOOL interrupts;
+ GXFifoObj tempObj; // 0x14
+ u32 i, j, k; // stack alloc
+ GXFifoObj* gpFifo; // r31
+ GXFifoObj* cpuFifo; // r30
+ void* tempPtr; // r29
+
+ gpFifo = GXGetGPFifo();
+ if (!gpFifo) {
+ return;
+ }
+
+ cpuFifo = GXGetCPUFifo();
+ tempPtr = gpFifo->base;
+
+ tempObj = *gpFifo;
+
+ interrupts = OSDisableInterrupts();
+
+ tempObj.read_ptr = tempPtr;
+ tempObj.write_ptr = tempPtr;
+ tempObj.rw_dst = 0;
+ if (tempObj.rw_dst < 0) {
+ tempObj.rw_dst += tempObj.size;
+ }
+
+ OSRestoreInterrupts(interrupts);
+
+ GXSetGPFifo(&tempObj);
+
+ if (cpuFifo == gpFifo) {
+ GXSetCPUFifo(&tempObj);
+ }
+
+ interrupts = OSDisableInterrupts();
+
+ gpFifo->read_ptr = tempPtr;
+ gpFifo->write_ptr = tempPtr;
+ gpFifo->rw_dst = 0;
+
+ if (gpFifo->rw_dst < 0) {
+ gpFifo->rw_dst += gpFifo->size;
+ }
+ OSRestoreInterrupts(interrupts);
+
+ GXSetGPFifo(gpFifo);
+ if (cpuFifo == gpFifo) {
+ GXSetCPUFifo(cpuFifo);
+ }
+}
+
+OSThread* GXSetCurrentGXThread(void) {
+ BOOL interrupts = OSDisableInterrupts();
+ OSThread* prevThread = __GXCurrentThread;
+ __GXCurrentThread = OSGetCurrentThread();
+ OSRestoreInterrupts(interrupts);
+ return prevThread;
+}
+
+OSThread* GXGetCurrentGXThread(void) {
+ return *(OSThread**)(&__GXCurrentThread);
+}
+
+GXFifoObj* GXGetCPUFifo(void) {
+ return *(GXFifoObj**)(&CPUFifo);
+}
+
+GXFifoObj* GXGetGPFifo(void) {
+ return GPFifo;
+}
diff --git a/src/dolphin/gx/GXFrameBuf.c b/src/dolphin/gx/GXFrameBuf.c
new file mode 100644
index 00000000..3cedf7e6
--- /dev/null
+++ b/src/dolphin/gx/GXFrameBuf.c
@@ -0,0 +1,638 @@
+#include "dolphin/gx/GXFrameBuf.h"
+#include "dolphin/gx/GX.h"
+
+GXRenderModeObj GXNtsc480IntDf = {
+ VI_TVMODE_NTSC_INT,
+ 640,
+ 480,
+ 480,
+ 40,
+ 0,
+ 640,
+ 480,
+ VI_XFBMODE_DF,
+ GX_FALSE,
+ GX_FALSE,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 8,
+ 8,
+ 10,
+ 12,
+ 10,
+ 8,
+ 8,
+};
+
+GXRenderModeObj GXNtsc480Int = {
+ VI_TVMODE_NTSC_INT,
+ 640,
+ 480,
+ 480,
+ 40,
+ 0,
+ 640,
+ 480,
+ VI_XFBMODE_DF,
+ GX_FALSE,
+ GX_FALSE,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 0,
+ 0,
+ 21,
+ 22,
+ 21,
+ 0,
+ 0,
+};
+
+GXRenderModeObj GXMpal480IntDf = {
+ VI_TVMODE_MPAL_INT,
+ 640,
+ 480,
+ 480,
+ 40,
+ 0,
+ 640,
+ 480,
+ VI_XFBMODE_DF,
+ GX_FALSE,
+ GX_FALSE,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 8,
+ 8,
+ 10,
+ 12,
+ 10,
+ 8,
+ 8,
+};
+
+GXRenderModeObj GXPal528IntDf = {
+ VI_TVMODE_PAL_INT,
+ 640,
+ 528,
+ 528,
+ 40,
+ 23,
+ 640,
+ 528,
+ VI_XFBMODE_DF,
+ GX_FALSE,
+ GX_FALSE,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 8,
+ 8,
+ 10,
+ 12,
+ 10,
+ 8,
+ 8,
+};
+
+GXRenderModeObj GXEurgb60Hz480IntDf = {
+ VI_TVMODE_EURGB60_INT,
+ 640,
+ 480,
+ 480,
+ 40,
+ 0,
+ 640,
+ 480,
+ VI_XFBMODE_DF,
+ GX_FALSE,
+ GX_FALSE,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 8,
+ 8,
+ 10,
+ 12,
+ 10,
+ 8,
+ 8,
+};
+
+void GXSetDispCopySrc(u16 left, u16 top, u16 width, u16 height) {
+ __GXData->cpDispSrc = 0;
+ GX_BITFIELD_SET(__GXData->cpDispSrc, 22, 10, left);
+ GX_BITFIELD_SET(__GXData->cpDispSrc, 12, 10, top);
+ GX_BITFIELD_SET(__GXData->cpDispSrc, 0, 8, 73);
+
+ __GXData->cpDispSize = 0;
+ GX_BITFIELD_SET(__GXData->cpDispSize, 22, 10, width - 1);
+ GX_BITFIELD_SET(__GXData->cpDispSize, 12, 10, height - 1);
+ GX_BITFIELD_SET(__GXData->cpDispSize, 0, 8, 74);
+}
+
+void GXSetTexCopySrc(u16 left, u16 top, u16 width, u16 height) {
+ __GXData->cpTexSrc = 0;
+ GX_BITFIELD_SET(__GXData->cpTexSrc, 22, 10, left);
+ GX_BITFIELD_SET(__GXData->cpTexSrc, 12, 10, top);
+ GX_BITFIELD_SET(__GXData->cpTexSrc, 0, 8, 0x49);
+ __GXData->cpTexSize = 0;
+ GX_BITFIELD_SET(__GXData->cpTexSize, 22, 10, width - 1);
+ GX_BITFIELD_SET(__GXData->cpTexSize, 12, 10, height - 1);
+ GX_BITFIELD_SET(__GXData->cpTexSize, 0, 8, 0x4A);
+}
+
+void GXSetDispCopyDst(u16 arg0, u16 arg1) {
+ s32 val = (s32)((arg0 << 1) & 0xFFFE) >> 5;
+ __GXData->cpDispStride = 0;
+ GX_BITFIELD_SET(__GXData->cpDispStride, 22, 10, val);
+ GX_BITFIELD_SET(__GXData->cpDispStride, 0, 8, 0x4D);
+}
+
+void GXSetTexCopyDst(u16 width, u16 height, GXTexFmt format, GXBool useMIPmap) {
+ u32 sp20, sp1C, sp18;
+ u32 value;
+ u8 depthRelated;
+
+ __GXData->cpTexZ = GX_NONE;
+
+ depthRelated = format & 0xf;
+ if (format == GX_TF_Z16) {
+ depthRelated = 0xb;
+ }
+
+ switch (format) {
+ case GX_TF_I4:
+ case GX_TF_I8:
+ case GX_TF_IA4:
+ case GX_TF_IA8:
+ case GX_CTF_A8:
+ GX_SET_REG(__GXData->cpTex, 3, 15, 16);
+ break;
+ default:
+ GX_SET_REG(__GXData->cpTex, 2, 15, 16);
+ break;
+ }
+
+ __GXData->cpTexZ = (format & 0x10) == 0x10;
+
+ value = depthRelated >> 3;
+
+ GX_SET_REG(__GXData->cpTex, value, 28, 28);
+
+ depthRelated &= 7;
+
+ __GetImageTileCount(format, width, height, &sp20, &sp1C, &sp18);
+
+ __GXData->cpTexStride = GX_NONE;
+ GX_SET_REG(__GXData->cpTexStride, sp20 * sp18, 22, 31);
+ GX_SET_REG(__GXData->cpTexStride, 0x4D, 0, 7);
+
+ GX_SET_REG(__GXData->cpTex, useMIPmap, 22, 22);
+ GX_SET_REG(__GXData->cpTex, depthRelated, 25, 27);
+}
+
+void GXSetDispCopyFrame2Field(GXCopyMode arg0) {
+ GX_BITFIELD_SET(__GXData->cpDisp, 18, 2, arg0);
+ GX_BITFIELD_SET(__GXData->cpTex, 18, 2, 0);
+}
+
+// clang-format off
+#define INSERT_FIELD(reg, value, nbits, shift) \
+ (reg) = ((u32) (reg) & ~(((1 << (nbits)) - 1) << (shift))) | \
+ ((u32) (value) << (shift));
+// clang-format on
+
+void GXSetCopyClamp(GXFBClamp clamp) {
+ u8 isTop = (clamp & GX_CLAMP_TOP) == GX_CLAMP_TOP;
+ u8 isBottom = (clamp & GX_CLAMP_BOTTOM) == GX_CLAMP_BOTTOM;
+ __GXData->cpDisp = __rlwimi(__GXData->cpDisp, isTop, 0, 31, 31);
+ __GXData->cpDisp = __rlwimi(__GXData->cpDisp, isBottom, 1, 30, 30);
+ __GXData->cpTex = __rlwimi(__GXData->cpTex, isTop, 0, 31, 31);
+ __GXData->cpTex = __rlwimi(__GXData->cpTex, isBottom, 1, 30, 30);
+}
+
+static u32 __GXGetNumXfbLines(u32 height, u32 scale) {
+ u32 numLines;
+ u32 actualHeight;
+ u32 newScale;
+
+ numLines = (height - 1) * 0x100;
+ actualHeight = (numLines / scale) + 1;
+
+ newScale = scale;
+
+ if (newScale > 0x80 && newScale < 0x100) {
+ while (newScale % 2 == 0) {
+ newScale /= 2;
+ }
+
+ if (height % newScale == 0) {
+ actualHeight++;
+ }
+ }
+
+ if (actualHeight > 0x400) {
+ actualHeight = 0x400;
+ }
+
+ return actualHeight;
+}
+
+u16 GXGetNumXfbLines(const u16 efbHeight, f32 yScale) {
+ u32 scale = (u32)(256.0f / yScale) & 0x1FF;
+
+ return __GXGetNumXfbLines(efbHeight, scale);
+}
+
+f32 GXGetYScaleFactor(u16 efbHeight, u16 xfbHeight) {
+ u32 scale;
+ u32 height1;
+ u32 height2;
+ f32 scale2;
+ f32 scale1;
+
+ height1 = xfbHeight;
+ scale1 = (f32)xfbHeight / (f32)efbHeight;
+ scale = (u32)(256.0f / scale1) & 0x1FF;
+ height2 = __GXGetNumXfbLines(efbHeight, scale);
+
+ while (height2 > xfbHeight) {
+ height1--;
+ scale1 = (f32)height1 / (f32)efbHeight;
+ scale = (u32)(256.0f / scale1) & 0x1FF;
+ height2 = __GXGetNumXfbLines(efbHeight, scale);
+ }
+
+ scale2 = scale1;
+ while (height2 < xfbHeight) {
+ scale2 = scale1;
+ height1++;
+ scale1 = (f32)height1 / (f32)efbHeight;
+ scale = (u32)(256.0f / scale1) & 0x1FF;
+ height2 = __GXGetNumXfbLines(efbHeight, scale);
+ }
+
+ return scale2;
+}
+
+u32 GXSetDispCopyYScale(f32 vertScale) {
+ u32 scale;
+ GXBool check;
+ u32 height;
+ u32 reg;
+
+ scale = (u32)(256.0f / vertScale) & 0x1FF;
+ check = (scale != 0x100);
+
+ reg = 0;
+ GX_SET_REG(reg, scale, 23, 31);
+ GX_SET_REG(reg, 0x4E, 0, 7);
+ GX_BP_LOAD_REG(reg);
+ __GXData->bpSentNot = GX_FALSE;
+
+ GX_SET_REG(__GXData->cpDisp, check, 21, 21);
+
+ height = (__GXData->cpDispSize >> 10 & 0x3FF) + 1;
+
+ return __GXGetNumXfbLines(height, scale);
+}
+
+void GXSetCopyClear(GXColor color, u32 clear_z) {
+ u32 r6 = 0;
+ GX_BITFIELD_SET(r6, 24, 8, color.r);
+ GX_BITFIELD_SET(r6, 16, 8, color.a);
+ GX_BITFIELD_SET(r6, 0, 8, 0x4f);
+ GXFIFO.u8 = 0x61;
+ GXFIFO.u32 = r6;
+
+ r6 = 0;
+ GX_BITFIELD_SET(r6, 24, 8, color.b);
+ GX_BITFIELD_SET(r6, 16, 8, color.g);
+ GX_BITFIELD_SET(r6, 0, 8, 0x50);
+ GXFIFO.u8 = 0x61;
+ GXFIFO.u32 = r6;
+
+ r6 = 0;
+ GX_BITFIELD_SET(r6, 8, 24, clear_z);
+ GX_BITFIELD_SET(r6, 0, 8, 0x51);
+ GXFIFO.u8 = 0x61;
+ GXFIFO.u32 = r6;
+
+ __GXData->bpSentNot = 0;
+}
+
+void GXSetCopyFilter(GXBool useAA, u8 samplePattern[12][2], GXBool doVertFilt, u8 vFilt[7]) {
+ u32 vals[4];
+ u32 unk1;
+ u32 unk2;
+
+ if (useAA) {
+ vals[0] = 0;
+ GX_SET_REG(vals[0], samplePattern[0][0], 28, 31);
+ GX_SET_REG(vals[0], samplePattern[0][1], 24, 27);
+ GX_SET_REG(vals[0], samplePattern[1][0], 20, 23);
+ GX_SET_REG(vals[0], samplePattern[1][1], 16, 19);
+ GX_SET_REG(vals[0], samplePattern[2][0], 12, 15);
+ GX_SET_REG(vals[0], samplePattern[2][1], 8, 11);
+ GX_SET_REG(vals[0], 1, 0, 7);
+
+ vals[1] = 0;
+ GX_SET_REG(vals[1], samplePattern[3][0], 28, 31);
+ GX_SET_REG(vals[1], samplePattern[3][1], 24, 27);
+ GX_SET_REG(vals[1], samplePattern[4][0], 20, 23);
+ GX_SET_REG(vals[1], samplePattern[4][1], 16, 19);
+ GX_SET_REG(vals[1], samplePattern[5][0], 12, 15);
+ GX_SET_REG(vals[1], samplePattern[5][1], 8, 11);
+ GX_SET_REG(vals[1], 2, 0, 7);
+
+ vals[2] = 0;
+ GX_SET_REG(vals[2], samplePattern[6][0], 28, 31);
+ GX_SET_REG(vals[2], samplePattern[6][1], 24, 27);
+ GX_SET_REG(vals[2], samplePattern[7][0], 20, 23);
+ GX_SET_REG(vals[2], samplePattern[7][1], 16, 19);
+ GX_SET_REG(vals[2], samplePattern[8][0], 12, 15);
+ GX_SET_REG(vals[2], samplePattern[8][1], 8, 11);
+ GX_SET_REG(vals[2], 3, 0, 7);
+
+ vals[3] = 0;
+ GX_SET_REG(vals[3], samplePattern[9][0], 28, 31);
+ GX_SET_REG(vals[3], samplePattern[9][1], 24, 27);
+ GX_SET_REG(vals[3], samplePattern[10][0], 20, 23);
+ GX_SET_REG(vals[3], samplePattern[10][1], 16, 19);
+ GX_SET_REG(vals[3], samplePattern[11][0], 12, 15);
+ GX_SET_REG(vals[3], samplePattern[11][1], 8, 11);
+ GX_SET_REG(vals[3], 4, 0, 7);
+ } else {
+ vals[0] = 0x01666666;
+ vals[1] = 0x02666666;
+ vals[2] = 0x03666666;
+ vals[3] = 0x04666666;
+ }
+
+ GX_BP_LOAD_REG(vals[0]);
+ GX_BP_LOAD_REG(vals[1]);
+ GX_BP_LOAD_REG(vals[2]);
+ GX_BP_LOAD_REG(vals[3]);
+
+ unk1 = 0;
+ GX_SET_REG(unk1, 0x53, 0, 7);
+ unk2 = 0;
+ GX_SET_REG(unk2, 0x54, 0, 7);
+
+ if (doVertFilt) {
+ GX_SET_REG(unk1, vFilt[0], 26, 31);
+ GX_SET_REG(unk1, vFilt[1], 20, 25);
+ GX_SET_REG(unk1, vFilt[2], 14, 19);
+ GX_SET_REG(unk1, vFilt[3], 8, 13);
+ GX_SET_REG(unk2, vFilt[4], 26, 31);
+ GX_SET_REG(unk2, vFilt[5], 20, 25);
+ GX_SET_REG(unk2, vFilt[6], 14, 19);
+
+ } else {
+ GX_SET_REG(unk1, 0, 26, 31);
+ GX_SET_REG(unk1, 0, 20, 25);
+ GX_SET_REG(unk1, 21, 14, 19);
+ GX_SET_REG(unk1, 22, 8, 13);
+ GX_SET_REG(unk2, 21, 26, 31);
+ GX_SET_REG(unk2, 0, 20, 25);
+ GX_SET_REG(unk2, 0, 14, 19);
+ }
+
+ GX_BP_LOAD_REG(unk1);
+ GX_BP_LOAD_REG(unk2);
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetDispCopyGamma(GXGamma gamma) {
+ GX_BITFIELD_SET(__GXData->cpDisp, 23, 2, gamma);
+}
+
+void GXCopyDisp(void* dest, GXBool doClear) {
+ u32 reg;
+ u32 newDest;
+ GXBool check;
+
+ if (doClear) {
+ reg = __GXData->zmode;
+ GX_SET_REG(reg, 1, 31, 31);
+ GX_SET_REG(reg, 7, 28, 30);
+ GX_BP_LOAD_REG(reg);
+
+ reg = __GXData->cmode0;
+ GX_SET_REG(reg, 0, 31, 31);
+ GX_SET_REG(reg, 0, 30, 30);
+ GX_BP_LOAD_REG(reg);
+ }
+
+ check = GX_FALSE;
+ if ((doClear || (__GXData->peCtrl & 0x7) == 3) && (__GXData->peCtrl >> 6 & 0x1) == 1) {
+ check = GX_TRUE;
+ reg = __GXData->peCtrl;
+ GX_SET_REG(reg, 0, 25, 25);
+ GX_BP_LOAD_REG(reg);
+ }
+
+ GX_BP_LOAD_REG(__GXData->cpDispSrc);
+ GX_BP_LOAD_REG(__GXData->cpDispSize);
+ GX_BP_LOAD_REG(__GXData->cpDispStride);
+
+ newDest = (u32)dest & 0x3FFFFFFF;
+ reg = 0;
+ GX_SET_REG(reg, newDest >> 5, 11, 31);
+ GX_SET_REG(reg, 0x4B, 0, 7);
+ GX_BP_LOAD_REG(reg);
+
+ GX_SET_REG(__GXData->cpDisp, doClear, 20, 20);
+ GX_SET_REG(__GXData->cpDisp, 1, 17, 17);
+ GX_SET_REG(__GXData->cpDisp, 0x52, 0, 7);
+ GX_BP_LOAD_REG(__GXData->cpDisp);
+
+ if (doClear) {
+ GX_BP_LOAD_REG(__GXData->zmode);
+ GX_BP_LOAD_REG(__GXData->cmode0);
+ }
+
+ if (check) {
+ GX_BP_LOAD_REG(__GXData->peCtrl);
+ }
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXCopyTex(void* dest, GXBool doClear) {
+ u32 reg;
+ u32 reg2;
+ u32 newDest;
+ GXBool check;
+
+ if (doClear) {
+ reg = __GXData->zmode;
+ GX_SET_REG(reg, 1, 31, 31);
+ GX_SET_REG(reg, 7, 28, 30);
+ GX_BP_LOAD_REG(reg);
+
+ reg = __GXData->cmode0;
+ GX_SET_REG(reg, 0, 31, 31);
+ GX_SET_REG(reg, 0, 30, 30);
+ GX_BP_LOAD_REG(reg);
+ }
+
+ check = GX_FALSE;
+ reg2 = __GXData->peCtrl;
+ if (__GXData->cpTexZ && (reg2 & 0x7) != 3) {
+ check = GX_TRUE;
+ GX_SET_REG(reg2, 3, 29, 31);
+ }
+
+ if ((doClear || (reg2 & 0x7) == 3) && (reg2 >> 6 & 0x1) == 1) {
+ check = GX_TRUE;
+ GX_SET_REG(reg2, 0, 25, 25);
+ }
+
+ if (check) {
+ GX_BP_LOAD_REG(reg2);
+ }
+
+ GX_BP_LOAD_REG(__GXData->cpTexSrc);
+ GX_BP_LOAD_REG(__GXData->cpTexSize);
+ GX_BP_LOAD_REG(__GXData->cpTexStride);
+
+ newDest = (u32)dest & 0x3FFFFFFF;
+ reg = 0;
+ GX_SET_REG(reg, newDest >> 5, 11, 31);
+ GX_SET_REG(reg, 0x4B, 0, 7);
+ GX_BP_LOAD_REG(reg);
+
+ GX_SET_REG(__GXData->cpTex, doClear, 20, 20);
+ GX_SET_REG(__GXData->cpTex, 0, 17, 17);
+ GX_SET_REG(__GXData->cpTex, 0x52, 0, 7);
+ GX_BP_LOAD_REG(__GXData->cpTex);
+
+ if (doClear) {
+ GX_BP_LOAD_REG(__GXData->zmode);
+ GX_BP_LOAD_REG(__GXData->cmode0);
+ }
+
+ if (check) {
+ GX_BP_LOAD_REG(__GXData->peCtrl);
+ }
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXClearBoundingBox(void) {
+ GXFIFO.u8 = GX_LOAD_BP_REG;
+ GXFIFO.u32 = 0x550003FF;
+ GXFIFO.u8 = GX_LOAD_BP_REG;
+ GXFIFO.u32 = 0x560003FF;
+ set_x2(GX_FALSE);
+}
diff --git a/src/dolphin/gx/GXGeometry.c b/src/dolphin/gx/GXGeometry.c
new file mode 100644
index 00000000..a6de9560
--- /dev/null
+++ b/src/dolphin/gx/GXGeometry.c
@@ -0,0 +1,149 @@
+/**
+ * GXGeometry.c
+ * Description:
+ */
+
+#include "dolphin/gx/GXGeometry.h"
+#include "dolphin/gx/GX.h"
+
+void __GXSetDirtyState(void) {
+ u32 dirtyFlags = __GXData->dirtyState;
+
+ if (dirtyFlags & GX_DIRTY_SU_TEX) {
+ __GXSetSUTexRegs();
+ }
+
+ if (dirtyFlags & GX_DIRTY_BP_MASK) {
+ __GXUpdateBPMask();
+ }
+
+ if (dirtyFlags & GX_DIRTY_GEN_MODE) {
+ __GXSetGenMode();
+ }
+
+ if (dirtyFlags & GX_DIRTY_VCD) {
+ __GXSetVCD();
+ }
+
+ if (dirtyFlags & GX_DIRTY_VAT) {
+ __GXSetVAT();
+ }
+
+ if (dirtyFlags & GX_DIRTY_VLIM) {
+ __GXCalculateVLim();
+ }
+
+ __GXData->dirtyState = 0;
+}
+
+void GXBegin(GXPrimitive type, GXVtxFmt fmt, u16 vert_num) {
+ GXData* data = __GXData;
+ u32 dirtyFlags = data->dirtyState;
+
+ if (data->dirtyState != 0) {
+ if (dirtyFlags & GX_DIRTY_SU_TEX) {
+ __GXSetSUTexRegs();
+ }
+
+ if (dirtyFlags & GX_DIRTY_BP_MASK) {
+ __GXUpdateBPMask();
+ }
+
+ if (dirtyFlags & GX_DIRTY_GEN_MODE) {
+ __GXSetGenMode();
+ }
+
+ if (dirtyFlags & GX_DIRTY_VCD) {
+ __GXSetVCD();
+ }
+
+ if (dirtyFlags & GX_DIRTY_VAT) {
+ __GXSetVAT();
+ }
+
+ if (dirtyFlags & GX_DIRTY_VLIM) {
+ __GXCalculateVLim();
+ }
+
+ __GXData->dirtyState = 0;
+ }
+
+ if (*(u32*)__GXData == 0) {
+ __GXSendFlushPrim();
+ }
+
+ GXFIFO.u8 = fmt | type;
+ GXFIFO.u16 = vert_num;
+}
+
+void __GXSendFlushPrim(void) {
+ u32 i;
+ u32 sz = __GXData->vNum * __GXData->vLim;
+
+ GXFIFO.u8 = 0x98;
+ GXFIFO.u16 = __GXData->vNum;
+
+ for (i = 0; i < sz; i += 4) {
+ GXFIFO.s32 = 0;
+ }
+
+ __GXData->bpSentNot = 1;
+}
+
+void GXSetLineWidth(u8 width, GXTexOffset offsets) {
+ GXData* data = __GXData;
+
+ GX_BITFIELD_SET(data->lpSize, 24, 8, width);
+ GX_BITFIELD_SET(data->lpSize, 13, 3, offsets);
+ GXFIFO.u8 = 0x61;
+ GXFIFO.u32 = data->lpSize;
+ data->bpSentNot = 0;
+}
+
+void GXSetPointSize(u8 size, GXTexOffset offsets) {
+ GXData* data = __GXData;
+
+ GX_BITFIELD_SET(data->lpSize, 16, 8, size);
+ GX_BITFIELD_SET(data->lpSize, 10, 3, offsets);
+ GXFIFO.u8 = 0x61;
+ GXFIFO.u32 = data->lpSize;
+ data->bpSentNot = 0;
+}
+
+void GXEnableTexOffsets(GXTexCoordID coord, GXBool line, GXBool point) {
+ GXData* data = __GXData;
+
+ GX_BITFIELD_SET(data->suTs0[coord], 13, 1, line);
+ GX_BITFIELD_SET(data->suTs0[coord], 12, 1, point);
+ GXFIFO.u8 = 0x61;
+ GXFIFO.u32 = data->suTs0[coord];
+ data->bpSentNot = 0;
+}
+
+void GXSetCullMode(GXCullMode mode) {
+ GXData* data;
+ GXCullMode mode2;
+ data = __GXData;
+
+ mode2 = (mode >> 1) & 1;
+ GX_BITFIELD_SET(mode2, 30, 1, mode);
+
+ GX_BITFIELD_SET(data->genMode, 16, 2, mode2);
+ data->dirtyState |= GX_DIRTY_GEN_MODE;
+}
+
+void GXSetCoPlanar(GXBool enable) {
+ GXData* data = __GXData;
+
+ GX_BITFIELD_SET(data->genMode, 12, 1, enable);
+ GXFIFO.u8 = 0x61;
+ GXFIFO.u32 = 0xFE080000;
+ GXFIFO.u8 = 0x61;
+ GXFIFO.u32 = data->genMode;
+}
+
+void __GXSetGenMode(void) {
+ GXFIFO.u8 = 0x61;
+ GXFIFO.u32 = __GXData->genMode;
+ __GXData->bpSentNot = 0;
+}
diff --git a/src/dolphin/gx/GXInit.c b/src/dolphin/gx/GXInit.c
new file mode 100644
index 00000000..f8e47061
--- /dev/null
+++ b/src/dolphin/gx/GXInit.c
@@ -0,0 +1,561 @@
+#include "dolphin/gx/GX.h"
+#include "dolphin/os/OS.h"
+#include "dolphin/vi/vi.h"
+
+char* __GXVersion = "<< Dolphin SDK - GX release build: Nov 10 2004 06:27:12 (0x2301) >>";
+
+static GXFifoObj FifoObj;
+
+static GXData gxData;
+
+GXData* const __GXData = &gxData;
+
+GXTexRegion* __GXDefaultTexRegionCallback(const GXTexObj* obj, GXTexMapID id) {
+ GXTexFmt format; // r31
+ GXBool isMipMap; // r3
+
+ format = GXGetTexObjFmt(obj);
+ isMipMap = GXGetTexObjMipMap(obj);
+ id = (GXTexMapID)(id % GX_MAX_TEXMAP);
+
+ switch (format) {
+ case GX_TF_RGBA8:
+ if (isMipMap) {
+ return &__GXData->TexRegions2[id];
+ }
+ return &__GXData->TexRegions1[id];
+
+ case GX_TF_C4:
+ case GX_TF_C8:
+ case GX_TF_C14X2:
+ return &__GXData->TexRegions0[id];
+
+ default:
+ if (isMipMap) {
+ return &__GXData->TexRegions1[id];
+ }
+ return &__GXData->TexRegions0[id];
+ }
+}
+
+GXTlutRegion* __GXDefaultTlutRegionCallback(u32 tlut) {
+ if (tlut >= 0x14) {
+ return NULL;
+ } else {
+ return &__GXData->TlutRegions[tlut];
+ }
+}
+
+u32 resetFuncRegistered;
+
+u32 calledOnce;
+
+OSTime time;
+
+u32 peCount;
+
+vu16* __memReg;
+
+u16* __peReg;
+
+u16* __cpReg;
+
+/* ############################################################################################## */
+u32* __piReg;
+
+BOOL __GXShutdown(BOOL final) {
+ u32 val;
+ u32 newPeCount;
+ OSTime newTime;
+
+ if (!final) {
+ if (!calledOnce) {
+ peCount = GXReadMEMReg(0x28, 0x27);
+ time = OSGetTime();
+ calledOnce = 1;
+ return FALSE;
+ }
+
+ newTime = OSGetTime();
+ newPeCount = GXReadMEMReg(0x28, 0x27);
+
+ if (newTime - time < 10) {
+ return FALSE;
+ }
+
+ if (newPeCount != peCount) {
+ peCount = newPeCount;
+ time = newTime;
+ return FALSE;
+ }
+
+ } else {
+ GXSetBreakPtCallback(NULL);
+ GXSetDrawSyncCallback(NULL);
+ GXSetDrawDoneCallback(NULL);
+
+ GX_WRITE_U32(0);
+ GX_WRITE_U32(0);
+ GX_WRITE_U32(0);
+ GX_WRITE_U32(0);
+ GX_WRITE_U32(0);
+ GX_WRITE_U32(0);
+ GX_WRITE_U32(0);
+ GX_WRITE_U32(0);
+
+ PPCSync();
+
+ GX_SET_CP_REG(1, 0);
+ GX_SET_CP_REG(2, 3);
+
+ __GXData->abtWaitPECopy = GX_TRUE;
+
+ __GXAbort();
+ }
+
+ return TRUE;
+}
+
+void __GXInitRevisionBits(void) {
+ u32 i;
+ for (i = 0; i < 8; i++) {
+ FAST_FLAG_SET(__GXData->vatA[i], 1, 30, 33);
+ FAST_FLAG_SET(__GXData->vatB[i], 1, 31, 33);
+
+ GX_WRITE_U8(0x8);
+ GX_WRITE_U8(i | 0x80);
+ GX_WRITE_U32(__GXData->vatB[i]);
+ }
+
+ {
+ u32 reg1 = 0;
+ u32 reg2 = 0;
+
+ FAST_FLAG_SET(reg1, 1, 0, 1);
+ FAST_FLAG_SET(reg1, 1, 1, 1);
+ FAST_FLAG_SET(reg1, 1, 2, 1);
+ FAST_FLAG_SET(reg1, 1, 3, 1);
+ FAST_FLAG_SET(reg1, 1, 4, 1);
+ FAST_FLAG_SET(reg1, 1, 5, 1);
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1000);
+ GX_WRITE_U32(reg1);
+
+ FAST_FLAG_SET(reg2, 1, 0, 1);
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1012);
+ GX_WRITE_U32(reg2);
+ }
+
+ {
+ u32 reg = 0;
+ FAST_FLAG_SET(reg, 1, 0, 1);
+ FAST_FLAG_SET(reg, 1, 1, 1);
+ FAST_FLAG_SET(reg, 1, 2, 1);
+ FAST_FLAG_SET(reg, 1, 3, 1);
+ FAST_FLAG_SET(reg, 0x58, 24, 8);
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(reg);
+ }
+}
+
+static u16 DefaultTexData[] ALIGN_DECL(32) = {
+ 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
+ 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
+};
+
+static GXVtxAttrFmtList GXDefaultVATList[] = {
+ {GX_VA_POS, GX_POS_XYZ, GX_F32, 0},
+ {GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0},
+ {GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0},
+ {GX_VA_CLR1, GX_CLR_RGBA, GX_RGBA8, 0},
+ {GX_VA_TEX0, GX_TEX_ST, GX_F32, 0},
+ {GX_VA_TEX1, GX_TEX_ST, GX_F32, 0},
+ {GX_VA_TEX2, GX_TEX_ST, GX_F32, 0},
+ {GX_VA_TEX3, GX_TEX_ST, GX_F32, 0},
+ {GX_VA_TEX4, GX_TEX_ST, GX_F32, 0},
+ {GX_VA_TEX5, GX_TEX_ST, GX_F32, 0},
+ {GX_VA_TEX6, GX_TEX_ST, GX_F32, 0},
+ {GX_VA_TEX7, GX_TEX_ST, GX_F32, 0},
+ {GX_VA_NULL, GX_COMPCNT_NULL, GX_COMP_NULL, 0},
+};
+
+static f32 GXDefaultProjData[] = {1.0f, 0.0f, 1.0f, 0.0f, -1.0f, -2.0f, 0.0f};
+
+static u32 GXTexRegionAddrTable[] = {
+ 0x00000, 0x10000, 0x20000, 0x30000, 0x40000, 0x50000, 0x60000, 0x70000, 0x08000, 0x18000,
+ 0x28000, 0x38000, 0x48000, 0x58000, 0x68000, 0x78000, 0x00000, 0x90000, 0x20000, 0xB0000,
+ 0x40000, 0x98000, 0x60000, 0xB8000, 0x80000, 0x10000, 0xA0000, 0x30000, 0x88000, 0x50000,
+ 0xA8000, 0x70000, 0x00000, 0x90000, 0x20000, 0xB0000, 0x40000, 0x90000, 0x60000, 0xB0000,
+ 0x80000, 0x10000, 0xA0000, 0x30000, 0x80000, 0x50000, 0xA0000, 0x70000,
+};
+
+static OSResetFunctionInfo GXResetFuncInfo = {__GXShutdown, OS_RESET_PRIO_GX};
+
+static void EnableWriteGatherPipe() {
+ u32 hid2; // r31
+ hid2 = PPCMfhid2();
+ PPCMtwpar(OSUncachedToPhysical((void*)GXFIFO_ADDR));
+ hid2 |= 0x40000000;
+ PPCMthid2(hid2);
+}
+
+GXFifoObj* GXInit(void* base, u32 size) {
+ u32 i;
+ u32 pad2; // for stack matching
+
+ OSRegisterVersion(__GXVersion);
+ __GXData->inDispList = GX_FALSE;
+ __GXData->dlSaveContext = GX_TRUE;
+ __GXData->abtWaitPECopy = GX_TRUE;
+
+ __GXData->tcsManEnab = 0;
+ __GXData->tevTcEnab = 0;
+
+ GXSetMisc(GX_MT_XF_FLUSH, 0);
+
+ __piReg = (void*)OSPhysicalToUncached(GX_PI_ADDR);
+ __cpReg = (void*)OSPhysicalToUncached(GX_CP_ADDR);
+ __peReg = (void*)OSPhysicalToUncached(GX_PE_ADDR);
+ __memReg = (void*)OSPhysicalToUncached(GX_MEM_ADDR);
+
+ __GXFifoInit();
+
+ GXInitFifoBase(&FifoObj, base, size);
+ GXSetCPUFifo(&FifoObj);
+ GXSetGPFifo(&FifoObj);
+
+ if (!resetFuncRegistered) {
+ OSRegisterResetFunction(&GXResetFuncInfo);
+ resetFuncRegistered = 1;
+ }
+
+ __GXPEInit();
+ EnableWriteGatherPipe();
+
+ __GXData->genMode = 0;
+ FAST_FLAG_SET(__GXData->genMode, 0, 24, 8);
+
+ __GXData->bpMask = 255;
+ FAST_FLAG_SET(__GXData->bpMask, 0xF, 24, 8);
+
+ __GXData->lpSize = 0;
+ FAST_FLAG_SET(__GXData->lpSize, 34, 24, 8);
+
+ for (i = 0; i < GX_MAX_TEVSTAGE; i++) {
+ __GXData->tevc[i] = 0;
+ __GXData->teva[i] = 0;
+ __GXData->tref[i / 2] = 0;
+ __GXData->texmapId[i] = GX_TEXMAP_NULL;
+
+ FAST_FLAG_SET(__GXData->tevc[i], 0xC0 + i * 2, 24, 8);
+ FAST_FLAG_SET(__GXData->teva[i], 0xC1 + i * 2, 24, 8);
+ FAST_FLAG_SET(__GXData->tevKsel[i / 2], 0xF6 + i / 2, 24, 8);
+ FAST_FLAG_SET(__GXData->tref[i / 2], 0x28 + i / 2, 24, 8);
+ }
+
+ __GXData->iref = 0;
+ FAST_FLAG_SET(__GXData->iref, 0x27, 24, 8);
+
+ for (i = 0; i < GX_MAXCOORD; i++) {
+ __GXData->suTs0[i] = 0;
+ __GXData->suTs1[i] = 0;
+
+ FAST_FLAG_SET(__GXData->suTs0[i], 0x30 + i * 2, 24, 8);
+ FAST_FLAG_SET(__GXData->suTs1[i], 0x31 + i * 2, 24, 8);
+ }
+
+ FAST_FLAG_SET(__GXData->suScis0, 0x20, 24, 8);
+ FAST_FLAG_SET(__GXData->suScis1, 0x21, 24, 8);
+
+ FAST_FLAG_SET(__GXData->cmode0, 0x41, 24, 8);
+ FAST_FLAG_SET(__GXData->cmode1, 0x42, 24, 8);
+
+ FAST_FLAG_SET(__GXData->zmode, 0x40, 24, 8);
+ FAST_FLAG_SET(__GXData->peCtrl, 0x43, 24, 8);
+
+ FAST_FLAG_SET(__GXData->cpTex, 0, 7, 2);
+
+ __GXData->zScale = 1.6777216E7f;
+ __GXData->zOffset = 0.0f;
+
+ __GXData->dirtyState = 0;
+ __GXData->dirtyVAT = 0;
+
+ {
+ u32 val1;
+ u32 val2;
+
+ val2 = OS_BUS_CLOCK / 500;
+
+ __GXFlushTextureState();
+
+ val1 = (val2 / 2048) | 0x69000400;
+
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(val1);
+
+ __GXFlushTextureState();
+
+ val1 = (val2 / 4224) | 0x46000200;
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(val1);
+ }
+
+ __GXInitRevisionBits();
+
+ for (i = 0; i < GX_MAX_TEXMAP; i++) {
+ GXInitTexCacheRegion(&__GXData->TexRegions0[i], GX_FALSE, GXTexRegionAddrTable[i],
+ GX_TEXCACHE_32K, GXTexRegionAddrTable[i + 8], GX_TEXCACHE_32K);
+ GXInitTexCacheRegion(&__GXData->TexRegions1[i], GX_FALSE, GXTexRegionAddrTable[i + 16],
+ GX_TEXCACHE_32K, GXTexRegionAddrTable[i + 24], GX_TEXCACHE_32K);
+ GXInitTexCacheRegion(&__GXData->TexRegions2[i], GX_TRUE, GXTexRegionAddrTable[i + 32],
+ GX_TEXCACHE_32K, GXTexRegionAddrTable[i + 40], GX_TEXCACHE_32K);
+ }
+
+ for (i = 0; i < GX_MAX_TLUT; i++) {
+ GXInitTlutRegion(&__GXData->TlutRegions[i], 0xC0000 + 0x2000 * i, GX_TLUT_256);
+ }
+
+ for (i = 0; i < GX_MAX_BIGTLUT; i++) {
+ GXInitTlutRegion(&__GXData->TlutRegions[i + 16], 0xE0000 + 0x8000 * i, GX_TLUT_1K);
+ }
+
+ GX_SET_CP_REG(3, 0);
+
+ FAST_FLAG_SET(__GXData->perfSel, 0, 4, 4);
+
+ GX_WRITE_U8(0x8);
+ GX_WRITE_U8(0x20);
+ GX_WRITE_U32(__GXData->perfSel);
+
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1006);
+ GX_WRITE_U32(0);
+
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x23000000);
+
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x24000000);
+
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x67000000);
+
+ __GXSetIndirectMask(0);
+ __GXSetTmemConfig(2);
+ __GXInitGX();
+
+ return &FifoObj;
+}
+
+void __GXInitGX(void) {
+ GXRenderModeObj* renderObj;
+ GXTexObj texObj;
+ Mtx ident;
+ GXColor clearColor = {64, 64, 64, 255};
+ GXColor ambColor = {0, 0, 0, 0};
+ GXColor matColor = {255, 255, 255, 255};
+ u32 i;
+
+ switch (VIGetTvFormat()) {
+ case VI_NTSC:
+ renderObj = &GXNtsc480IntDf;
+ break;
+
+ case VI_PAL:
+ renderObj = &GXPal528IntDf;
+ break;
+
+ case VI_EURGB60:
+ renderObj = &GXEurgb60Hz480IntDf;
+ break;
+
+ case VI_MPAL:
+ renderObj = &GXMpal480IntDf;
+ break;
+
+ default:
+ renderObj = &GXNtsc480IntDf;
+ break;
+ }
+
+ GXSetCopyClear(clearColor, 0xFFFFFF);
+
+ GXSetTexCoordGen2(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY, GX_FALSE, GX_PTIDENTITY);
+ GXSetTexCoordGen2(GX_TEXCOORD1, GX_TG_MTX2x4, GX_TG_TEX1, GX_IDENTITY, GX_FALSE, GX_PTIDENTITY);
+ GXSetTexCoordGen2(GX_TEXCOORD2, GX_TG_MTX2x4, GX_TG_TEX2, GX_IDENTITY, GX_FALSE, GX_PTIDENTITY);
+ GXSetTexCoordGen2(GX_TEXCOORD3, GX_TG_MTX2x4, GX_TG_TEX3, GX_IDENTITY, GX_FALSE, GX_PTIDENTITY);
+ GXSetTexCoordGen2(GX_TEXCOORD4, GX_TG_MTX2x4, GX_TG_TEX4, GX_IDENTITY, GX_FALSE, GX_PTIDENTITY);
+ GXSetTexCoordGen2(GX_TEXCOORD5, GX_TG_MTX2x4, GX_TG_TEX5, GX_IDENTITY, GX_FALSE, GX_PTIDENTITY);
+ GXSetTexCoordGen2(GX_TEXCOORD6, GX_TG_MTX2x4, GX_TG_TEX6, GX_IDENTITY, GX_FALSE, GX_PTIDENTITY);
+ GXSetTexCoordGen2(GX_TEXCOORD7, GX_TG_MTX2x4, GX_TG_TEX7, GX_IDENTITY, GX_FALSE, GX_PTIDENTITY);
+
+ GXSetNumTexGens(1);
+ GXClearVtxDesc();
+ GXInvalidateVtxCache();
+
+ for (i = GX_VA_POS; i <= GX_LIGHT_ARRAY; i++) {
+ GXSetArray((GXAttr)i, __GXData, 0);
+ }
+
+ for (i = 0; i < GX_MAX_VTXFMT; i++) {
+ GXSetVtxAttrFmtv((GXVtxFmt)i, GXDefaultVATList);
+ }
+
+ GXSetLineWidth(6, GX_TO_ZERO);
+ GXSetPointSize(6, GX_TO_ZERO);
+ GXEnableTexOffsets(GX_TEXCOORD0, GX_FALSE, GX_FALSE);
+ GXEnableTexOffsets(GX_TEXCOORD1, GX_FALSE, GX_FALSE);
+ GXEnableTexOffsets(GX_TEXCOORD2, GX_FALSE, GX_FALSE);
+ GXEnableTexOffsets(GX_TEXCOORD3, GX_FALSE, GX_FALSE);
+ GXEnableTexOffsets(GX_TEXCOORD4, GX_FALSE, GX_FALSE);
+ GXEnableTexOffsets(GX_TEXCOORD5, GX_FALSE, GX_FALSE);
+ GXEnableTexOffsets(GX_TEXCOORD6, GX_FALSE, GX_FALSE);
+ GXEnableTexOffsets(GX_TEXCOORD7, GX_FALSE, GX_FALSE);
+
+ ident[0][0] = 1.0f;
+ ident[0][1] = 0.0f;
+ ident[0][2] = 0.0f;
+ ident[0][3] = 0.0f;
+
+ ident[1][0] = 0.0f;
+ ident[1][1] = 1.0f;
+ ident[1][2] = 0.0f;
+ ident[1][3] = 0.0f;
+
+ ident[2][0] = 0.0f;
+ ident[2][1] = 0.0f;
+ ident[2][2] = 1.0f;
+ ident[2][3] = 0.0f;
+
+ GXLoadPosMtxImm(ident, GX_PNMTX0);
+ GXLoadNrmMtxImm(ident, GX_PNMTX0);
+ GXSetCurrentMtx(GX_PNMTX0);
+
+ GXLoadTexMtxImm(ident, GX_IDENTITY, GX_MTX3x4);
+ GXLoadTexMtxImm(ident, GX_PTIDENTITY, GX_MTX3x4);
+
+ GXSetViewport(0.0f, 0.0f, renderObj->fb_width, renderObj->xfb_height, 0.0f, 1.0f);
+
+ GXSetProjectionv(GXDefaultProjData);
+
+ GXSetCoPlanar(GX_FALSE);
+ GXSetCullMode(GX_CULL_BACK);
+ GXSetClipMode(GX_CLIP_ENABLE);
+
+ GXSetScissor(0, 0, renderObj->fb_width, renderObj->efb_height);
+ GXSetScissorBoxOffset(0, 0);
+
+ GXSetNumChans(0);
+ GXSetChanCtrl(GX_COLOR0A0, GX_FALSE, GX_SRC_REG, GX_SRC_VTX, 0, GX_DF_NONE, GX_AF_NONE);
+ GXSetChanAmbColor(GX_COLOR0A0, ambColor);
+ GXSetChanMatColor(GX_COLOR0A0, matColor);
+
+ GXSetChanCtrl(GX_COLOR1A1, GX_FALSE, GX_SRC_REG, GX_SRC_VTX, 0, GX_DF_NONE, GX_AF_NONE);
+ GXSetChanAmbColor(GX_COLOR1A1, ambColor);
+ GXSetChanMatColor(GX_COLOR1A1, matColor);
+
+ GXInvalidateTexAll();
+ GXSetTexRegionCallback(__GXDefaultTexRegionCallback);
+ GXSetTlutRegionCallback(__GXDefaultTlutRegionCallback);
+
+ GXInitTexObj(&texObj, DefaultTexData, 4, 4, GX_TF_IA8, GX_CLAMP, GX_CLAMP, GX_FALSE);
+ GXLoadTexObj(&texObj, GX_TEXMAP0);
+ GXLoadTexObj(&texObj, GX_TEXMAP1);
+ GXLoadTexObj(&texObj, GX_TEXMAP2);
+ GXLoadTexObj(&texObj, GX_TEXMAP3);
+ GXLoadTexObj(&texObj, GX_TEXMAP4);
+ GXLoadTexObj(&texObj, GX_TEXMAP5);
+ GXLoadTexObj(&texObj, GX_TEXMAP6);
+ GXLoadTexObj(&texObj, GX_TEXMAP7);
+
+ GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
+ GXSetTevOrder(GX_TEVSTAGE1, GX_TEXCOORD1, GX_TEXMAP1, GX_COLOR0A0);
+ GXSetTevOrder(GX_TEVSTAGE2, GX_TEXCOORD2, GX_TEXMAP2, GX_COLOR0A0);
+ GXSetTevOrder(GX_TEVSTAGE3, GX_TEXCOORD3, GX_TEXMAP3, GX_COLOR0A0);
+ GXSetTevOrder(GX_TEVSTAGE4, GX_TEXCOORD4, GX_TEXMAP4, GX_COLOR0A0);
+ GXSetTevOrder(GX_TEVSTAGE5, GX_TEXCOORD5, GX_TEXMAP5, GX_COLOR0A0);
+ GXSetTevOrder(GX_TEVSTAGE6, GX_TEXCOORD6, GX_TEXMAP6, GX_COLOR0A0);
+ GXSetTevOrder(GX_TEVSTAGE7, GX_TEXCOORD7, GX_TEXMAP7, GX_COLOR0A0);
+
+ GXSetTevOrder(GX_TEVSTAGE8, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL);
+ GXSetTevOrder(GX_TEVSTAGE9, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL);
+ GXSetTevOrder(GX_TEVSTAGE10, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL);
+ GXSetTevOrder(GX_TEVSTAGE11, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL);
+ GXSetTevOrder(GX_TEVSTAGE12, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL);
+ GXSetTevOrder(GX_TEVSTAGE13, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL);
+ GXSetTevOrder(GX_TEVSTAGE14, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL);
+ GXSetTevOrder(GX_TEVSTAGE15, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL);
+
+ GXSetNumTevStages(1);
+ GXSetTevOp(GX_TEVSTAGE0, GX_REPLACE);
+
+ GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0);
+
+ GXSetZTexture(GX_ZT_DISABLE, GX_TF_Z8, 0);
+
+ for (i = 0; i < GX_MAX_TEVSTAGE; i++) {
+ GXSetTevKColorSel((GXTevStageID)i, GX_TEV_KCSEL_1_4);
+ GXSetTevKAlphaSel((GXTevStageID)i, GX_TEV_KASEL_1);
+ GXSetTevSwapMode((GXTevStageID)i, GX_TEV_SWAP0, GX_TEV_SWAP0);
+ }
+
+ GXSetTevSwapModeTable(GX_TEV_SWAP0, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA);
+ GXSetTevSwapModeTable(GX_TEV_SWAP1, GX_CH_RED, GX_CH_RED, GX_CH_RED, GX_CH_ALPHA);
+ GXSetTevSwapModeTable(GX_TEV_SWAP2, GX_CH_GREEN, GX_CH_GREEN, GX_CH_GREEN, GX_CH_ALPHA);
+ GXSetTevSwapModeTable(GX_TEV_SWAP3, GX_CH_BLUE, GX_CH_BLUE, GX_CH_BLUE, GX_CH_ALPHA);
+
+ for (i = 0; i < GX_MAX_TEVSTAGE; i++) {
+ GXSetTevDirect((GXTevStageID)i);
+ }
+
+ GXSetNumIndStages(0);
+ GXSetIndTexCoordScale(GX_INDTEXSTAGE0, GX_ITS_1, GX_ITS_1);
+ GXSetIndTexCoordScale(GX_INDTEXSTAGE1, GX_ITS_1, GX_ITS_1);
+ GXSetIndTexCoordScale(GX_INDTEXSTAGE2, GX_ITS_1, GX_ITS_1);
+ GXSetIndTexCoordScale(GX_INDTEXSTAGE3, GX_ITS_1, GX_ITS_1);
+
+ GXSetFog(GX_FOG_NONE, 0.0f, 1.0f, 0.1f, 1.0f, ambColor);
+ GXSetFogRangeAdj(GX_FALSE, 0, NULL);
+
+ GXSetBlendMode(GX_BM_NONE, GX_BL_SRC_ALPHA, GX_BL_INV_SRC_ALPHA, GX_LO_CLEAR);
+
+ GXSetColorUpdate(GX_TRUE);
+ GXSetAlphaUpdate(GX_TRUE);
+
+ GXSetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE);
+ GXSetZCompLoc(GX_TRUE);
+
+ GXSetDither(GX_TRUE);
+
+ GXSetDstAlpha(GX_FALSE, 0);
+ GXSetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR);
+
+ GXSetFieldMask(GX_TRUE, GX_TRUE);
+ GXSetFieldMode(
+ (GXBool)renderObj->field_rendering,
+ (GXBool)((renderObj->vi_height == 2 * renderObj->xfb_height) ? GX_TRUE : GX_FALSE));
+
+ GXSetDispCopySrc(0, 0, renderObj->fb_width, renderObj->efb_height);
+ GXSetDispCopyDst(renderObj->fb_width, renderObj->efb_height);
+ GXSetDispCopyYScale((f32)renderObj->xfb_height / (f32)renderObj->efb_height);
+ GXSetCopyClamp(GX_CLAMP_BOTH);
+
+ GXSetCopyFilter(renderObj->antialiasing, renderObj->sample_pattern, GX_TRUE,
+ renderObj->vfilter);
+ GXSetDispCopyGamma(GX_GM_1_0);
+ GXSetDispCopyFrame2Field(GX_COPY_PROGRESSIVE);
+ GXClearBoundingBox();
+
+ GXPokeColorUpdate(GX_TRUE);
+ GXPokeAlphaUpdate(GX_TRUE);
+ GXPokeDither(GX_FALSE);
+ GXPokeBlendMode(GX_BM_NONE, GX_BL_ZERO, GX_BL_ONE, GX_LO_SET);
+ GXPokeAlphaMode(GX_ALWAYS, 0);
+ GXPokeAlphaRead(GX_READ_FF);
+ GXPokeDstAlpha(GX_FALSE, 0);
+ GXPokeZMode(GX_TRUE, GX_ALWAYS, GX_TRUE);
+ GXSetGPMetric(GX_PERF0_NONE, GX_PERF1_NONE);
+ GXClearGPMetric();
+} \ No newline at end of file
diff --git a/src/dolphin/gx/GXLight.c b/src/dolphin/gx/GXLight.c
new file mode 100644
index 00000000..a90c2a21
--- /dev/null
+++ b/src/dolphin/gx/GXLight.c
@@ -0,0 +1,294 @@
+/**
+ * GXLight.c
+ * Description:
+ */
+
+#include "dolphin/gx/GXLight.h"
+#include "dolphin/gx/GX.h"
+#include "math.h"
+
+void GXInitLightAttn(GXLightObj* obj, f32 a0, f32 a1, f32 a2, f32 k0, f32 k1, f32 k2) {
+ obj->a0 = a0;
+ obj->a1 = a1;
+ obj->a2 = a2;
+ obj->k0 = k0;
+ obj->k1 = k1;
+ obj->k2 = k2;
+}
+
+void GXInitLightSpot(GXLightObj* obj, f32 cutoff, GXSpotFn spot_fn) {
+ f32 rad;
+ f32 a, b, c, d;
+
+ if (cutoff <= 0.0f || cutoff > 90.0f) {
+ spot_fn = GX_SP_OFF;
+ }
+
+ rad = cosf((3.1415927f * cutoff) / 180.0f);
+
+ switch (spot_fn) {
+ case GX_SP_FLAT:
+ a = -1000.0f * rad;
+ b = 1000.0f;
+ c = 0.0f;
+ break;
+ case GX_SP_COS:
+ b = 1.0f / (1.0f - rad);
+ a = -rad * b;
+ c = 0.0f;
+ break;
+ case GX_SP_COS2:
+ c = 1.0f / (1.0f - rad);
+ a = 0.0f;
+ b = -rad * c;
+ break;
+ case GX_SP_SHARP:
+ d = 1.0f / ((1.0f - rad) * (1.0f - rad));
+ a = (rad * (rad - 2.0f)) * d;
+ b = 2.0f * d;
+ c = -d;
+ break;
+ case GX_SP_RING1:
+ d = 1.0f / ((1.0f - rad) * (1.0f - rad));
+ c = -4.0f * d;
+ a = c * rad;
+ b = 4.0f * (1.0f + rad) * d;
+ break;
+ case GX_SP_RING2:
+ d = 1.0f / ((1.0f - rad) * (1.0f - rad));
+ a = 1.0f - 2.0f * rad * rad * d;
+ b = 4.0f * rad * d;
+ c = -2.0f * d;
+ break;
+ case GX_SP_OFF:
+ default:
+ a = 1.0f;
+ b = 0.0f;
+ c = 0.0f;
+ break;
+ }
+
+ obj->a0 = a;
+ obj->a1 = b;
+ obj->a2 = c;
+}
+
+void GXInitLightDistAttn(GXLightObj* obj, f32 dist, f32 brightness, GXDistAttnFn dist_fn) {
+ f32 a, b, c;
+
+ if (dist < 0.0f) {
+ dist_fn = GX_DA_OFF;
+ }
+
+ if (brightness <= 0.0f || brightness >= 1.0f) {
+ dist_fn = GX_DA_OFF;
+ }
+
+ switch (dist_fn) {
+ case GX_DA_GENTLE:
+ a = 1.0f;
+ b = (1.0f - brightness) / (brightness * dist);
+ c = 0.0f;
+ break;
+ case GX_DA_MEDIUM:
+ a = 1.0f;
+ b = (0.5f * (1.0f - brightness)) / (brightness * dist);
+ c = (0.5f * (1.0f - brightness)) / (dist * (brightness * dist));
+ break;
+ case GX_DA_STEEP:
+ a = 1.0f;
+ b = 0.0f;
+ c = (1.0f - brightness) / (dist * (brightness * dist));
+ break;
+ case GX_DA_OFF:
+ default:
+ a = 1.0f;
+ b = 0.0f;
+ c = 0.0f;
+ break;
+ }
+
+ obj->k0 = a;
+ obj->k1 = b;
+ obj->k2 = c;
+}
+
+void GXInitLightPos(GXLightObj* obj, f32 x, f32 y, f32 z) {
+ obj->posX = x;
+ obj->posY = y;
+ obj->posZ = z;
+}
+
+void GXInitLightDir(GXLightObj* obj, f32 x, f32 y, f32 z) {
+ obj->dirX = -x;
+ obj->dirY = -y;
+ obj->dirZ = -z;
+}
+
+void GXInitLightColor(GXLightObj* obj, GXColor color) {
+ *(u32*)&obj->color = *(u32*)&color;
+}
+
+static inline void PushLight(const register GXLightObj* lt_obj, register void* dest) {
+ register u32 zero, color;
+ register f32 a0_a1, a2_k0, k1_k2;
+ register f32 px_py, pz_dx, dy_dz;
+#ifdef __MWERKS__ // clang-format off
+ asm {
+ lwz color, 12(lt_obj)
+ xor zero, zero, zero
+ psq_l a0_a1, 16(lt_obj), 0, 0
+ psq_l a2_k0, 24(lt_obj), 0, 0
+ psq_l k1_k2, 32(lt_obj), 0, 0
+ psq_l px_py, 40(lt_obj), 0, 0
+ psq_l pz_dx, 48(lt_obj), 0, 0
+ psq_l dy_dz, 56(lt_obj), 0, 0
+
+ stw zero, 0(dest)
+ stw zero, 0(dest)
+ stw zero, 0(dest)
+ stw color, 0(dest)
+ psq_st a0_a1, 0(dest), 0, 0
+ psq_st a2_k0, 0(dest), 0, 0
+ psq_st k1_k2, 0(dest), 0, 0
+ psq_st px_py, 0(dest), 0, 0
+ psq_st pz_dx, 0(dest), 0, 0
+ psq_st dy_dz, 0(dest), 0, 0
+ }
+#endif // clang-format on
+}
+
+void GXLoadLightObjImm(GXLightObj* obj, GXLightID light) {
+ u32 addr;
+ u32 idx;
+ GXLightObj* pObj = (GXLightObj*)obj;
+
+ idx = 31 - __cntlzw(light);
+ idx &= 7;
+
+ addr = 0x600 + idx * 0x10;
+
+ GX_XF_LOAD_REG_HDR(addr | (0x10 - 1) << 16);
+
+ PushLight(pObj, (void*)GXFIFO_ADDR);
+ __GXData->bpSentNot = 1;
+}
+
+void GXSetChanAmbColor(GXChannelID channel, GXColor color) {
+ u32 reg;
+ u32 colorID;
+ u8 alpha;
+
+ switch (channel) {
+ case GX_COLOR0:
+ reg = __GXData->ambColor[GX_COLOR0];
+ reg = GX_SET_TRUNC(reg, GXCOLOR_AS_U32(color), 0, 23);
+ colorID = GX_COLOR0;
+ break;
+ case GX_COLOR1:
+ reg = __GXData->ambColor[GX_COLOR1];
+ reg = GX_SET_TRUNC(reg, GXCOLOR_AS_U32(color), 0, 23);
+ colorID = GX_COLOR1;
+ break;
+ case GX_ALPHA0:
+ reg = __GXData->ambColor[GX_COLOR0];
+ reg = GX_SET_TRUNC(reg, color.a, 24, 31);
+ colorID = GX_COLOR0;
+ break;
+ case GX_ALPHA1:
+ reg = __GXData->ambColor[GX_COLOR1];
+ reg = GX_SET_TRUNC(reg, color.a, 24, 31);
+ colorID = GX_COLOR1;
+ break;
+ case GX_COLOR0A0:
+ reg = GXCOLOR_AS_U32(color);
+ colorID = GX_COLOR0;
+ break;
+ case GX_COLOR1A1:
+ reg = GXCOLOR_AS_U32(color);
+ colorID = GX_COLOR1;
+ break;
+ default:
+ return;
+ }
+
+ GX_XF_LOAD_REG(GX_XF_REG_AMBIENT0 + colorID, reg);
+ __GXData->bpSentNot = GX_TRUE;
+ __GXData->ambColor[colorID] = reg;
+}
+
+void GXSetChanMatColor(GXChannelID channel, GXColor color) {
+ u32 reg = 0;
+ GXChannelID colorID;
+
+ switch (channel) {
+ case GX_COLOR0:
+ reg = __GXData->matColor[GX_COLOR0];
+ reg = GX_SET_TRUNC(reg, GXCOLOR_AS_U32(color), 0, 23);
+ colorID = GX_COLOR0;
+ break;
+ case GX_COLOR1:
+ reg = __GXData->matColor[GX_COLOR1];
+ reg = GX_SET_TRUNC(reg, GXCOLOR_AS_U32(color), 0, 23);
+ colorID = GX_COLOR1;
+ break;
+ case GX_ALPHA0:
+ reg = __GXData->matColor[GX_COLOR0];
+ reg = GX_SET_TRUNC(reg, color.a, 24, 31);
+ colorID = GX_COLOR0;
+ break;
+ case GX_ALPHA1:
+ reg = __GXData->matColor[GX_COLOR1];
+ reg = GX_SET_TRUNC(reg, color.a, 24, 31);
+ colorID = GX_COLOR1;
+ break;
+ case GX_COLOR0A0:
+ reg = GXCOLOR_AS_U32(color);
+ colorID = GX_COLOR0;
+ break;
+ case GX_COLOR1A1:
+ reg = GXCOLOR_AS_U32(color);
+ colorID = GX_COLOR1;
+ break;
+ default:
+ return;
+ }
+
+ GX_XF_LOAD_REG(GX_XF_REG_MATERIAL0 + colorID, reg);
+ __GXData->bpSentNot = GX_TRUE;
+ __GXData->matColor[colorID] = reg;
+}
+
+void GXSetNumChans(u8 count) {
+ GX_SET_REG(__GXData->genMode, count, 25, 27);
+ GX_XF_LOAD_REG(GX_XF_REG_NUMCOLORS, count);
+ __GXData->dirtyState |= GX_DIRTY_GEN_MODE;
+}
+
+void GXSetChanCtrl(GXChannelID channel, GXBool doEnable, GXColorSrc ambSrc, GXColorSrc matSrc,
+ u32 mask, GXDiffuseFn diffFunc, GXAttnFn attnFunc) {
+ const u32 colorID = (u32)channel & 0x3;
+ u32 reg = 0;
+
+ GX_SET_REG(reg, doEnable, GX_XF_CLR0CTRL_LIGHT_ST, GX_XF_CLR0CTRL_LIGHT_END);
+ GX_SET_REG(reg, matSrc, GX_XF_CLR0CTRL_MTXSRC_ST, GX_XF_CLR0CTRL_MTXSRC_END);
+ GX_SET_REG(reg, ambSrc, GX_XF_CLR0CTRL_AMBSRC_ST, GX_XF_CLR0CTRL_AMBSRC_END);
+ GX_SET_REG(reg, (attnFunc == GX_AF_SPEC ? GX_DF_NONE : diffFunc), GX_XF_CLR0CTRL_DIFATTN_ST,
+ GX_XF_CLR0CTRL_DIFATTN_END);
+ GX_SET_REG(reg, (attnFunc != GX_AF_NONE), GX_XF_CLR0CTRL_ATTNENABLE_ST,
+ GX_XF_CLR0CTRL_ATTNENABLE_END);
+ GX_SET_REG(reg, (attnFunc != GX_AF_SPEC), GX_XF_CLR0CTRL_ATTNSEL_ST,
+ GX_XF_CLR0CTRL_ATTNSEL_END);
+ GX_BITFIELD_SET(reg, 26, 4, (u32)mask);
+ reg = __rlwimi(reg, (u32)mask, 7, 0x11, 0x14);
+
+ GX_XF_LOAD_REG(GX_XF_REG_COLOR0CNTRL + colorID, reg);
+
+ if (channel == GX_COLOR0A0) {
+ GX_XF_LOAD_REG(GX_XF_REG_ALPHA0CNTRL, reg);
+ } else if (channel == GX_COLOR1A1) {
+ GX_XF_LOAD_REG(GX_XF_REG_ALPHA1CNTRL, reg);
+ }
+
+ __GXData->bpSentNot = GX_TRUE;
+}
diff --git a/src/dolphin/gx/GXMisc.c b/src/dolphin/gx/GXMisc.c
new file mode 100644
index 00000000..468192ea
--- /dev/null
+++ b/src/dolphin/gx/GXMisc.c
@@ -0,0 +1,266 @@
+#include "dolphin/gx/GXMisc.h"
+#include "dolphin/gx/GX.h"
+#include "dolphin/os/OSInterrupt.h"
+#include "dolphin/os/OSReset.h"
+#include "dolphin/os/OSTime.h"
+
+static void GXTokenInterruptHandler(__OSInterrupt interrupt, OSContext* context);
+static void GXFinishInterruptHandler(__OSInterrupt interrupt, OSContext* pContext);
+
+void GXSetMisc(GXMiscToken token, u32 val) {
+ switch (token) {
+ case GX_MT_NULL:
+ break;
+
+ case GX_MT_XF_FLUSH:
+ __GXData->vNum = val;
+ __GXData->vNumNot = !__GXData->vNum;
+ __GXData->bpSentNot = GX_TRUE;
+
+ if (__GXData->vNum) {
+ __GXData->dirtyState |= GX_DIRTY_VCD;
+ }
+ break;
+
+ case GX_MT_DL_SAVE_CONTEXT:
+ __GXData->dlSaveContext = (val != 0);
+ break;
+
+ case GX_MT_ABORT_WAIT_COPYOUT:
+ __GXData->abtWaitPECopy = (val != 0);
+ break;
+ }
+}
+
+void GXFlush(void) {
+ if (__GXData->dirtyState) {
+ __GXSetDirtyState();
+ }
+
+ GXFIFO.u32 = 0;
+ GXFIFO.u32 = 0;
+ GXFIFO.u32 = 0;
+ GXFIFO.u32 = 0;
+ GXFIFO.u32 = 0;
+ GXFIFO.u32 = 0;
+ GXFIFO.u32 = 0;
+ GXFIFO.u32 = 0;
+
+ PPCSync();
+}
+
+static void __GXAbortWait(u32 clocks) {
+ OSTime time0, time1;
+ time0 = OSGetTime();
+
+ do {
+ time1 = OSGetTime();
+ } while (time1 - time0 <= clocks / 4);
+}
+
+static void __GXAbortWaitPECopyDone(void) {
+ u32 peCnt0, peCnt1;
+
+ peCnt0 = GXReadMEMReg(0x28, 0x27);
+ do {
+ peCnt1 = peCnt0;
+ __GXAbortWait(32);
+
+ peCnt0 = GXReadMEMReg(0x28, 0x27);
+ } while (peCnt0 != peCnt1);
+}
+
+void __GXAbort(void) {
+ if (__GXData->abtWaitPECopy && GXGetGPFifo()) {
+ __GXAbortWaitPECopyDone();
+ }
+
+ __PIRegs[0x18 / 4] = 1;
+ __GXAbortWait(200);
+ __PIRegs[0x18 / 4] = 0;
+ __GXAbortWait(20);
+}
+
+void GXAbortFrame(void) {
+ __GXAbort();
+ if (GXGetGPFifo()) {
+ __GXCleanGPFifo();
+ __GXInitRevisionBits();
+ __GXData->dirtyState = 0;
+ GXFlush();
+ }
+}
+
+/* ############################################################################################## */
+static GXDrawSyncCallback TokenCB;
+
+static GXDrawDoneCallback DrawDoneCB;
+
+static GXBool DrawDone;
+
+void GXSetDrawDone(void) {
+ u8 padding[8];
+ BOOL restore = OSDisableInterrupts();
+ GFWriteBPCmd(0x45000002);
+ GXFlush();
+ DrawDone = 0;
+ OSRestoreInterrupts(restore);
+}
+
+/* ############################################################################################## */
+static OSThreadQueue FinishQueue;
+
+static void GXWaitDrawDone(void) {
+ BOOL restore = OSDisableInterrupts();
+ while (DrawDone == 0) {
+ OSSleepThread(&FinishQueue);
+ }
+ OSRestoreInterrupts(restore);
+}
+
+void GXDrawDone(void) {
+ u8 padding[8];
+ GXSetDrawDone();
+ GXWaitDrawDone();
+}
+
+void GXPixModeSync(void) {
+ GXFIFO.u8 = 0x61;
+ GXFIFO.u32 = __GXData->peCtrl;
+ __GXData->bpSentNot = 0;
+}
+
+void GXPokeAlphaMode(GXCompare comp, u8 threshold) {
+ __peReg[3] = (comp << 8) | threshold;
+}
+
+void GXPokeAlphaRead(GXAlphaReadMode mode) {
+ u32 val = 0;
+ GX_BITFIELD_SET(val, 0x1e, 2, mode);
+ GX_BITFIELD_SET(val, 0x1d, 1, 1);
+ __peReg[4] = val;
+}
+
+void GXPokeAlphaUpdate(GXBool enable_update) {
+ GX_BITFIELD_SET(__peReg[1], 0x1b, 1, enable_update);
+}
+
+void GXPokeBlendMode(GXBlendMode mode, GXBlendFactor srcFactor, GXBlendFactor destFactor,
+ GXLogicOp op) {
+ u32 reg;
+
+ reg = GX_GET_PE_REG(1);
+ GX_SET_REG(reg, (mode == GX_BM_BLEND) || (mode == GX_BM_SUBTRACT), 31, 31);
+ GX_SET_REG(reg, (mode == GX_BM_SUBTRACT), 20, 20);
+ GX_SET_REG(reg, (mode == GX_BM_LOGIC), 30, 30);
+ GX_SET_REG(reg, op, 16, 19);
+ GX_SET_REG(reg, srcFactor, 21, 23);
+ GX_SET_REG(reg, destFactor, 24, 26);
+ GX_SET_REG(reg, 0x41, 0, 7);
+ GX_SET_PE_REG(1, reg);
+}
+
+void GXPokeColorUpdate(GXBool enable_update) {
+ GX_BITFIELD_SET(__peReg[1], 0x1c, 1, enable_update);
+}
+
+void GXPokeDstAlpha(GXBool enable, u8 alpha) {
+ u32 val = 0;
+ GX_BITFIELD_SET(val, 0x18, 8, alpha);
+ GX_BITFIELD_SET(val, 0x17, 1, enable);
+ __peReg[2] = val;
+}
+
+void GXPokeDither(GXBool enable) {
+ GX_BITFIELD_SET(__peReg[1], 0x1d, 1, enable);
+}
+
+void GXPokeZMode(GXBool enable_compare, GXCompare comp, GXBool update_enable) {
+ u32 val = 0;
+ GX_BITFIELD_SET(val, 0x1f, 1, enable_compare);
+ GX_BITFIELD_SET(val, 0x1c, 3, comp);
+ GX_BITFIELD_SET(val, 0x1b, 1, update_enable);
+ __peReg[0] = val;
+}
+
+void GXPeekZ(u16 x, u16 y, u32* z) {
+ u32 addr = 0xc8000000;
+ GX_BITFIELD_SET(addr, 0x14, 10, x);
+ GX_BITFIELD_SET(addr, 0xa, 10, y);
+ GX_BITFIELD_SET(addr, 8, 2, 1);
+ *z = *(u32*)addr;
+}
+
+GXDrawSyncCallback GXSetDrawSyncCallback(GXDrawSyncCallback callback) {
+ BOOL restore;
+ GXDrawSyncCallback prevCb = TokenCB;
+ restore = OSDisableInterrupts();
+ TokenCB = callback;
+ OSRestoreInterrupts(restore);
+ return prevCb;
+}
+
+static void GXTokenInterruptHandler(__OSInterrupt interrupt, OSContext* context) {
+ u16 token;
+ OSContext exceptContext;
+ u32 reg;
+
+ token = GX_GET_PE_REG(7);
+
+ if (TokenCB) {
+ OSClearContext(&exceptContext);
+ OSSetCurrentContext(&exceptContext);
+ TokenCB(token);
+ OSClearContext(&exceptContext);
+ OSSetCurrentContext(context);
+ }
+
+ reg = GX_GET_PE_REG(5);
+ GX_SET_REG(reg, 1, 29, 29);
+ GX_SET_PE_REG(5, reg);
+}
+
+GXDrawDoneCallback GXSetDrawDoneCallback(GXDrawDoneCallback callback) {
+ BOOL restore;
+ GXDrawDoneCallback prevCb = DrawDoneCB;
+ restore = OSDisableInterrupts();
+ DrawDoneCB = callback;
+ OSRestoreInterrupts(restore);
+ return prevCb;
+}
+
+static void GXFinishInterruptHandler(__OSInterrupt interrupt, OSContext* context) {
+ OSContext exceptContext;
+ u32 reg;
+
+ reg = GX_GET_PE_REG(5);
+ GX_SET_REG(reg, 1, 28, 28);
+ GX_SET_PE_REG(5, reg);
+
+ DrawDone = GX_TRUE;
+
+ if (DrawDoneCB) {
+ OSClearContext(&exceptContext);
+ OSSetCurrentContext(&exceptContext);
+ DrawDoneCB();
+ OSClearContext(&exceptContext);
+ OSSetCurrentContext(context);
+ }
+
+ OSWakeupThread(&FinishQueue);
+}
+
+void __GXPEInit(void) {
+ u32 val;
+ __OSSetInterruptHandler(OS_INTR_PI_PE_TOKEN, GXTokenInterruptHandler);
+ __OSSetInterruptHandler(OS_INTR_PI_PE_FINISH, GXFinishInterruptHandler);
+ OSInitThreadQueue(&FinishQueue);
+ __OSUnmaskInterrupts(OS_INTERRUPTMASK_PI_PE_TOKEN);
+ __OSUnmaskInterrupts(OS_INTERRUPTMASK_PI_PE_FINISH);
+ val = __peReg[5];
+ GX_BITFIELD_SET(val, 0x1d, 1, 1);
+ GX_BITFIELD_SET(val, 0x1c, 1, 1);
+ GX_BITFIELD_SET(val, 0x1f, 1, 1);
+ GX_BITFIELD_SET(val, 0x1e, 1, 1);
+ __peReg[5] = val;
+}
diff --git a/src/dolphin/gx/GXPerf.c b/src/dolphin/gx/GXPerf.c
new file mode 100644
index 00000000..60591b0b
--- /dev/null
+++ b/src/dolphin/gx/GXPerf.c
@@ -0,0 +1,384 @@
+#include "dolphin/gx/GXPerf.h"
+#include "dolphin/gx/GX.h"
+
+void GXSetGPMetric(GXPerf0 perf0, GXPerf1 perf1) {
+ switch (__GXData->perf0) {
+ case GX_PERF0_VERTICES:
+ case GX_PERF0_CLIP_VTX:
+ case GX_PERF0_CLIP_CLKS:
+ case GX_PERF0_XF_WAIT_IN:
+ case GX_PERF0_XF_WAIT_OUT:
+ case GX_PERF0_XF_XFRM_CLKS:
+ case GX_PERF0_XF_LIT_CLKS:
+ case GX_PERF0_XF_BOT_CLKS:
+ case GX_PERF0_XF_REGLD_CLKS:
+ case GX_PERF0_XF_REGRD_CLKS:
+ case GX_PERF0_CLIP_RATIO:
+ case GX_PERF0_CLOCKS:
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1006);
+ GX_WRITE_U32(0);
+ break;
+
+ case GX_PERF0_TRIANGLES:
+ case GX_PERF0_TRIANGLES_CULLED:
+ case GX_PERF0_TRIANGLES_PASSED:
+ case GX_PERF0_TRIANGLES_SCISSORED:
+ case GX_PERF0_TRIANGLES_0TEX:
+ case GX_PERF0_TRIANGLES_1TEX:
+ case GX_PERF0_TRIANGLES_2TEX:
+ case GX_PERF0_TRIANGLES_3TEX:
+ case GX_PERF0_TRIANGLES_4TEX:
+ case GX_PERF0_TRIANGLES_5TEX:
+ case GX_PERF0_TRIANGLES_6TEX:
+ case GX_PERF0_TRIANGLES_7TEX:
+ case GX_PERF0_TRIANGLES_8TEX:
+ case GX_PERF0_TRIANGLES_0CLR:
+ case GX_PERF0_TRIANGLES_1CLR:
+ case GX_PERF0_TRIANGLES_2CLR:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x23000000);
+ break;
+
+ case GX_PERF0_QUAD_0CVG:
+ case GX_PERF0_QUAD_NON0CVG:
+ case GX_PERF0_QUAD_1CVG:
+ case GX_PERF0_QUAD_2CVG:
+ case GX_PERF0_QUAD_3CVG:
+ case GX_PERF0_QUAD_4CVG:
+ case GX_PERF0_AVG_QUAD_CNT:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x24000000);
+ break;
+
+ case GX_PERF0_NONE:
+ break;
+ }
+
+ switch (__GXData->perf1) {
+ case GX_PERF1_TEXELS:
+ case GX_PERF1_TX_IDLE:
+ case GX_PERF1_TX_REGS:
+ case GX_PERF1_TX_MEMSTALL:
+ case GX_PERF1_TC_CHECK1_2:
+ case GX_PERF1_TC_CHECK3_4:
+ case GX_PERF1_TC_CHECK5_6:
+ case GX_PERF1_TC_CHECK7_8:
+ case GX_PERF1_TC_MISS:
+ case GX_PERF1_CLOCKS:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x67000000);
+ break;
+
+ case GX_PERF1_VC_ELEMQ_FULL:
+ case GX_PERF1_VC_MISSQ_FULL:
+ case GX_PERF1_VC_MEMREQ_FULL:
+ case GX_PERF1_VC_STATUS7:
+ case GX_PERF1_VC_MISSREP_FULL:
+ case GX_PERF1_VC_STREAMBUF_LOW:
+ case GX_PERF1_VC_ALL_STALLS:
+ case GX_PERF1_VERTICES:
+ FAST_FLAG_SET(__GXData->perfSel, 0, 4, 4);
+ GX_WRITE_U8(8);
+ GX_WRITE_U8(32);
+ GX_WRITE_U32(__GXData->perfSel);
+ break;
+
+ case GX_PERF1_FIFO_REQ:
+ case GX_PERF1_CALL_REQ:
+ case GX_PERF1_VC_MISS_REQ:
+ case GX_PERF1_CP_ALL_REQ:
+ GX_SET_CP_REG(3, 0);
+ break;
+
+ case GX_PERF1_NONE:
+ break;
+ }
+
+ __GXData->perf0 = perf0;
+
+ switch (__GXData->perf0) {
+ case GX_PERF0_VERTICES:
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1006);
+ GX_WRITE_U32(0x273);
+ break;
+ case GX_PERF0_CLIP_VTX:
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1006);
+ GX_WRITE_U32(0x14A);
+ break;
+ case GX_PERF0_CLIP_CLKS:
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1006);
+ GX_WRITE_U32(0x16B);
+ break;
+ case GX_PERF0_XF_WAIT_IN:
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1006);
+ GX_WRITE_U32(0x84);
+ break;
+ case GX_PERF0_XF_WAIT_OUT:
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1006);
+ GX_WRITE_U32(0xC6);
+ break;
+ case GX_PERF0_XF_XFRM_CLKS:
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1006);
+ GX_WRITE_U32(0x210);
+ break;
+ case GX_PERF0_XF_LIT_CLKS:
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1006);
+ GX_WRITE_U32(0x252);
+ break;
+ case GX_PERF0_XF_BOT_CLKS:
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1006);
+ GX_WRITE_U32(0x231);
+ break;
+ case GX_PERF0_XF_REGLD_CLKS:
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1006);
+ GX_WRITE_U32(0x1AD);
+ break;
+ case GX_PERF0_XF_REGRD_CLKS:
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1006);
+ GX_WRITE_U32(0x1CE);
+ break;
+ case GX_PERF0_CLOCKS:
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1006);
+ GX_WRITE_U32(0x21);
+ break;
+ case GX_PERF0_CLIP_RATIO:
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1006);
+ GX_WRITE_U32(0x153);
+ break;
+
+ case GX_PERF0_TRIANGLES:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2300AE7F);
+ break;
+ case GX_PERF0_TRIANGLES_CULLED:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x23008E7F);
+ break;
+ case GX_PERF0_TRIANGLES_PASSED:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x23009E7F);
+ break;
+ case GX_PERF0_TRIANGLES_SCISSORED:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x23001E7F);
+ break;
+ case GX_PERF0_TRIANGLES_0TEX:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2300AC3F);
+ break;
+ case GX_PERF0_TRIANGLES_1TEX:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2300AC7F);
+ break;
+ case GX_PERF0_TRIANGLES_2TEX:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2300ACBF);
+ break;
+ case GX_PERF0_TRIANGLES_3TEX:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2300ACFF);
+ break;
+ case GX_PERF0_TRIANGLES_4TEX:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2300AD3F);
+ break;
+ case GX_PERF0_TRIANGLES_5TEX:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2300AD7F);
+ break;
+ case GX_PERF0_TRIANGLES_6TEX:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2300ADBF);
+ break;
+ case GX_PERF0_TRIANGLES_7TEX:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2300ADFF);
+ break;
+ case GX_PERF0_TRIANGLES_8TEX:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2300AE3F);
+ break;
+ case GX_PERF0_TRIANGLES_0CLR:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2300A27F);
+ break;
+ case GX_PERF0_TRIANGLES_1CLR:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2300A67F);
+ break;
+ case GX_PERF0_TRIANGLES_2CLR:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2300AA7F);
+ break;
+
+ case GX_PERF0_QUAD_0CVG:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2402C0C6);
+ break;
+ case GX_PERF0_QUAD_NON0CVG:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2402C16B);
+ break;
+ case GX_PERF0_QUAD_1CVG:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2402C0E7);
+ break;
+ case GX_PERF0_QUAD_2CVG:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2402C108);
+ break;
+ case GX_PERF0_QUAD_3CVG:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2402C129);
+ break;
+ case GX_PERF0_QUAD_4CVG:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2402C14A);
+ break;
+ case GX_PERF0_AVG_QUAD_CNT:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2402C1AD);
+ break;
+
+ case GX_PERF0_NONE:
+ break;
+ }
+
+ __GXData->perf1 = perf1;
+
+ switch (__GXData->perf1) {
+ case GX_PERF1_TEXELS:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x67000042);
+ break;
+ case GX_PERF1_TX_IDLE:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x67000084);
+ break;
+ case GX_PERF1_TX_REGS:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x67000063);
+ break;
+ case GX_PERF1_TX_MEMSTALL:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x67000129);
+ break;
+ case GX_PERF1_TC_MISS:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x67000252);
+ break;
+ case GX_PERF1_CLOCKS:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x67000021);
+ break;
+ case GX_PERF1_TC_CHECK1_2:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x6700014B);
+ break;
+ case GX_PERF1_TC_CHECK3_4:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x6700018D);
+ break;
+ case GX_PERF1_TC_CHECK5_6:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x670001CF);
+ break;
+ case GX_PERF1_TC_CHECK7_8:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x67000211);
+ break;
+
+ case GX_PERF1_VC_ELEMQ_FULL:
+ FAST_FLAG_SET(__GXData->perfSel, 2, 4, 4);
+ GX_WRITE_U8(8);
+ GX_WRITE_U8(32);
+ GX_WRITE_U32(__GXData->perfSel);
+ break;
+ case GX_PERF1_VC_MISSQ_FULL:
+ FAST_FLAG_SET(__GXData->perfSel, 3, 4, 4);
+ GX_WRITE_U8(8);
+ GX_WRITE_U8(32);
+ GX_WRITE_U32(__GXData->perfSel);
+ break;
+ case GX_PERF1_VC_MEMREQ_FULL:
+ FAST_FLAG_SET(__GXData->perfSel, 4, 4, 4);
+ GX_WRITE_U8(8);
+ GX_WRITE_U8(32);
+ GX_WRITE_U32(__GXData->perfSel);
+ break;
+ case GX_PERF1_VC_STATUS7:
+ FAST_FLAG_SET(__GXData->perfSel, 5, 4, 4);
+ GX_WRITE_U8(8);
+ GX_WRITE_U8(32);
+ GX_WRITE_U32(__GXData->perfSel);
+ break;
+ case GX_PERF1_VC_MISSREP_FULL:
+ FAST_FLAG_SET(__GXData->perfSel, 6, 4, 4);
+ GX_WRITE_U8(8);
+ GX_WRITE_U8(32);
+ GX_WRITE_U32(__GXData->perfSel);
+ break;
+ case GX_PERF1_VC_STREAMBUF_LOW:
+ FAST_FLAG_SET(__GXData->perfSel, 7, 4, 4);
+ GX_WRITE_U8(8);
+ GX_WRITE_U8(32);
+ GX_WRITE_U32(__GXData->perfSel);
+ break;
+ case GX_PERF1_VC_ALL_STALLS:
+ FAST_FLAG_SET(__GXData->perfSel, 9, 4, 4);
+ GX_WRITE_U8(8);
+ GX_WRITE_U8(32);
+ GX_WRITE_U32(__GXData->perfSel);
+ break;
+ case GX_PERF1_VERTICES:
+ FAST_FLAG_SET(__GXData->perfSel, 8, 4, 4);
+ GX_WRITE_U8(8);
+ GX_WRITE_U8(32);
+ GX_WRITE_U32(__GXData->perfSel);
+ break;
+
+ case GX_PERF1_FIFO_REQ:
+ GX_SET_CP_REG(3, 2);
+ break;
+ case GX_PERF1_CALL_REQ:
+ GX_SET_CP_REG(3, 3);
+ break;
+ case GX_PERF1_VC_MISS_REQ:
+ GX_SET_CP_REG(3, 4);
+ break;
+ case GX_PERF1_CP_ALL_REQ:
+ GX_SET_CP_REG(3, 5);
+ break;
+
+ case GX_PERF1_NONE:
+ break;
+ }
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXClearGPMetric(void) {
+ GX_SET_CP_REG(2, 4);
+}
+
+#pragma scheduling off
+void GXReadXfRasMetric(u32* xfWaitIn, u32* xfWaitOut, u32* rasBusy, u32* clocks) {
+ *rasBusy = GXReadCPReg(32, 33);
+ *clocks = GXReadCPReg(34, 35);
+ *xfWaitIn = GXReadCPReg(36, 37);
+ *xfWaitOut = GXReadCPReg(38, 39);
+}
+#pragma scheduling reset
diff --git a/src/dolphin/gx/GXPixel.c b/src/dolphin/gx/GXPixel.c
new file mode 100644
index 00000000..f3448bc3
--- /dev/null
+++ b/src/dolphin/gx/GXPixel.c
@@ -0,0 +1,235 @@
+#include "dolphin/gx/GXPixel.h"
+#include "dolphin/gx/GX.h"
+
+void GXSetFog(GXFogType type, f32 startz, f32 endz, f32 nearz, f32 farz, GXColor color) {
+ f32 a, c;
+ u32 a_bits, c_bits;
+
+ u32 fogColorReg = 0;
+ u32 fogParamReg0 = 0;
+ u32 fogParamReg1 = 0;
+ u32 fogParamReg2 = 0;
+ u32 fogParamReg3 = 0;
+
+ u32 fsel = type & 7;
+ BOOL isOrtho = (type >> 3) & 1;
+ u32 col;
+
+ if (isOrtho) {
+ if (farz == nearz || endz == startz) {
+ a = 0.0f;
+ c = 0.0f;
+ } else {
+ a = (1.0f / (endz - startz)) * (farz - nearz);
+ c = (1.0f / (endz - startz)) * (startz - nearz);
+ }
+ } else {
+ f32 tmpA, tmpB, tmpC;
+ u32 expB, magB, shiftB;
+
+ if (farz == nearz || endz == startz) {
+ tmpA = 0.0f;
+ tmpB = 0.5f;
+ tmpC = 0.0f;
+ } else {
+ tmpA = (farz * nearz) / ((farz - nearz) * (endz - startz));
+ tmpB = farz / (farz - nearz);
+ tmpC = startz / (endz - startz);
+ }
+
+ expB = 0;
+ while (tmpB > 1.0) {
+ tmpB /= 2.0f;
+ expB++;
+ }
+ while (tmpB > 0.0f && tmpB < 0.5) {
+ tmpB *= 2.0f;
+ expB--;
+ }
+
+ a = tmpA / (1 << expB + 1);
+ magB = 8388638.0f * tmpB;
+ shiftB = expB + 1;
+ c = tmpC;
+
+ GX_SET_REG(fogParamReg1, magB, GX_BP_FOGPARAM1_B_MAG_ST, GX_BP_FOGPARAM1_B_MAG_END);
+ GX_SET_REG(fogParamReg2, shiftB, GX_BP_FOGPARAM2_B_SHIFT_ST, GX_BP_FOGPARAM2_B_SHIFT_END);
+
+ GX_SET_REG(fogParamReg1, GX_BP_REG_FOGPARAM1, 0, 7);
+ GX_SET_REG(fogParamReg2, GX_BP_REG_FOGPARAM2, 0, 7);
+ }
+
+ a_bits = *(u32*)&a;
+ c_bits = *(u32*)&c;
+
+ GX_SET_REG(fogParamReg0, a_bits >> 12, GX_BP_FOGPARAM0_A_MANT_ST, GX_BP_FOGPARAM0_A_MANT_END);
+ GX_SET_REG(fogParamReg0, a_bits >> 23, GX_BP_FOGPARAM0_A_EXP_ST, GX_BP_FOGPARAM0_A_EXP_END);
+ GX_SET_REG(fogParamReg0, a_bits >> 31, GX_BP_FOGPARAM0_A_SIGN_ST, GX_BP_FOGPARAM0_A_SIGN_END);
+ GX_SET_REG(fogParamReg0, GX_BP_REG_FOGPARAM0, 0, 7);
+
+ GX_SET_REG(fogParamReg3, c_bits >> 12, GX_BP_FOGPARAM3_C_MANT_ST, GX_BP_FOGPARAM3_C_MANT_END);
+ GX_SET_REG(fogParamReg3, c_bits >> 23, GX_BP_FOGPARAM3_C_EXP_ST, GX_BP_FOGPARAM3_C_EXP_END);
+ GX_SET_REG(fogParamReg3, c_bits >> 31, GX_BP_FOGPARAM3_C_SIGN_ST, GX_BP_FOGPARAM3_C_SIGN_END);
+ GX_SET_REG(fogParamReg3, isOrtho, GX_BP_FOGPARAM3_PROJ_ST, GX_BP_FOGPARAM3_PROJ_END);
+ GX_SET_REG(fogParamReg3, fsel, GX_BP_FOGPARAM3_FSEL_ST, GX_BP_FOGPARAM3_FSEL_END);
+ GX_SET_REG(fogParamReg3, GX_BP_REG_FOGPARAM3, 0, 7);
+
+ col = *(u32*)&color;
+ GX_SET_REG(fogColorReg, col >> 8, GX_BP_FOGCOLOR_RGB_ST, GX_BP_FOGCOLOR_RGB_END);
+ GX_SET_REG(fogColorReg, GX_BP_REG_FOGCOLOR, 0, 7);
+
+ GX_BP_LOAD_REG(fogParamReg0);
+ GX_BP_LOAD_REG(fogParamReg1);
+ GX_BP_LOAD_REG(fogParamReg2);
+ GX_BP_LOAD_REG(fogParamReg3);
+ GX_BP_LOAD_REG(fogColorReg);
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetFogRangeAdj(GXBool enable, u16 center, GXFogAdjTable* table) {
+ u32 fogRangeReg;
+ u32 fogRangeRegK;
+ u32 i;
+
+ if (enable) {
+ for (i = 0; i < 10; i += 2) {
+ fogRangeRegK = 0;
+ GX_SET_REG(fogRangeRegK, table->fogVals[i], GX_BP_FOGRANGEK_HI_ST,
+ GX_BP_FOGRANGEK_HI_END);
+ GX_SET_REG(fogRangeRegK, table->fogVals[i + 1], GX_BP_FOGRANGEK_LO_ST,
+ GX_BP_FOGRANGEK_LO_END);
+ GX_SET_REG(fogRangeRegK, GX_BP_REG_FOGRANGEK0 + (i / 2), 0, 7);
+ GX_BP_LOAD_REG(fogRangeRegK);
+ }
+ }
+
+ fogRangeReg = 0;
+ GX_SET_REG(fogRangeReg, center + 342, GX_BP_FOGRANGE_CENTER_ST, GX_BP_FOGRANGE_CENTER_END);
+ GX_SET_REG(fogRangeReg, enable, GX_BP_FOGRANGE_ENABLED_ST, GX_BP_FOGRANGE_ENABLED_END);
+ GX_SET_REG(fogRangeReg, GX_BP_REG_FOGRANGE, 0, 7);
+ GX_BP_LOAD_REG(fogRangeReg);
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetBlendMode(GXBlendMode type, GXBlendFactor src_factor, GXBlendFactor dst_factor,
+ GXLogicOp op) {
+ u32 blendModeReg = __GXData->cmode0;
+ GX_SET_REG(blendModeReg, type == GX_BM_SUBTRACT, GX_BP_BLENDMODE_SUBTRACT_ST,
+ GX_BP_BLENDMODE_SUBTRACT_END);
+ GX_SET_REG(blendModeReg, type, GX_BP_BLENDMODE_ENABLE_ST, GX_BP_BLENDMODE_ENABLE_END);
+ GX_SET_REG(blendModeReg, type == GX_BM_LOGIC, GX_BP_BLENDMODE_LOGIC_OP_ST,
+ GX_BP_BLENDMODE_LOGIC_OP_END);
+ GX_SET_REG(blendModeReg, op, GX_BP_BLENDMODE_LOGICMODE_ST, GX_BP_BLENDMODE_LOGICMODE_END);
+ GX_SET_REG(blendModeReg, src_factor, GX_BP_BLENDMODE_SRCFACTOR_ST,
+ GX_BP_BLENDMODE_SRCFACTOR_END);
+ GX_SET_REG(blendModeReg, dst_factor, GX_BP_BLENDMODE_DSTFACTOR_ST,
+ GX_BP_BLENDMODE_DSTFACTOR_END);
+
+ GX_BP_LOAD_REG(blendModeReg);
+ __GXData->cmode0 = blendModeReg;
+
+ __GXData->bpSentNot = FALSE;
+}
+
+void GXSetColorUpdate(GXBool updateEnable) {
+ u32 blendModeReg = __GXData->cmode0;
+ GX_SET_REG(blendModeReg, updateEnable, GX_BP_BLENDMODE_COLOR_UPDATE_ST,
+ GX_BP_BLENDMODE_COLOR_UPDATE_END);
+ GX_BP_LOAD_REG(blendModeReg);
+ __GXData->cmode0 = blendModeReg;
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetAlphaUpdate(GXBool updateEnable) {
+ u32 blendModeReg = __GXData->cmode0;
+ GX_SET_REG(blendModeReg, updateEnable, GX_BP_BLENDMODE_ALPHA_UPDATE_ST,
+ GX_BP_BLENDMODE_ALPHA_UPDATE_END);
+ GX_BP_LOAD_REG(blendModeReg);
+ __GXData->cmode0 = blendModeReg;
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetZMode(GXBool compareEnable, GXCompare func, GXBool updateEnable) {
+ u32 zModeReg = __GXData->zmode;
+ GX_SET_REG(zModeReg, compareEnable, GX_BP_ZMODE_TEST_ENABLE_ST, GX_BP_ZMODE_TEST_ENABLE_END);
+ GX_SET_REG(zModeReg, func, GX_BP_ZMODE_COMPARE_ST, GX_BP_ZMODE_COMPARE_END);
+ GX_SET_REG(zModeReg, updateEnable, GX_BP_ZMODE_UPDATE_ENABLE_ST, GX_BP_ZMODE_UPDATE_ENABLE_END);
+ GX_BP_LOAD_REG(zModeReg);
+ __GXData->zmode = zModeReg;
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetZCompLoc(GXBool beforeTex) {
+ GX_SET_REG(__GXData->peCtrl, beforeTex, GX_BP_ZCONTROL_BEFORE_TEX_ST,
+ GX_BP_ZCONTROL_BEFORE_TEX_END);
+ GX_BP_LOAD_REG(__GXData->peCtrl);
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetPixelFmt(GXPixelFmt pixelFmt, GXZFmt16 zFmt) {
+ GXBool isZ16;
+ static u32 p2f[GX_PF_MAX] = {GX_PF_RGB8_Z24, GX_PF_RGBA6_Z24, GX_PF_RGB565_Z16, GX_PF_Z24,
+ GX_PF_Y8, GX_PF_Y8, GX_PF_Y8, GX_PF_U8};
+
+ const u32 zControlRegOld = __GXData->peCtrl;
+
+ GX_SET_REG(__GXData->peCtrl, p2f[pixelFmt], GX_BP_ZCONTROL_PIXEL_FMT_ST,
+ GX_BP_ZCONTROL_PIXEL_FMT_END);
+ GX_SET_REG(__GXData->peCtrl, zFmt, GX_BP_ZCONTROL_Z_FMT_ST, GX_BP_ZCONTROL_Z_FMT_END);
+
+ if (zControlRegOld != __GXData->peCtrl) {
+ GX_BP_LOAD_REG(__GXData->peCtrl);
+ isZ16 = (pixelFmt == GX_PF_RGB565_Z16) ? GX_TRUE : GX_FALSE;
+ GX_SET_REG(__GXData->genMode, isZ16, GX_BP_GENMODE_MULTISAMPLE_ST,
+ GX_BP_GENMODE_MULTISAMPLE_END);
+ __GXData->dirtyState |= GX_DIRTY_GEN_MODE;
+ }
+
+ if (p2f[pixelFmt] == GX_PF_Y8) {
+ GX_SET_REG(__GXData->cmode1, pixelFmt - GX_PF_Y8, GX_BP_DSTALPHA_YUV_FMT_ST,
+ GX_BP_DSTALPHA_YUV_FMT_END);
+ GX_SET_REG(__GXData->cmode1, GX_BP_REG_DSTALPHA, 0, 7);
+ GX_BP_LOAD_REG(__GXData->cmode1);
+ }
+
+ __GXData->bpSentNot = FALSE;
+}
+
+void GXSetDither(GXBool dither) {
+ u32 blendModeReg = __GXData->cmode0;
+ GX_SET_REG(blendModeReg, dither, GX_BP_BLENDMODE_DITHER_ST, GX_BP_BLENDMODE_DITHER_END);
+ GX_BP_LOAD_REG(blendModeReg);
+ __GXData->cmode0 = blendModeReg;
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetDstAlpha(GXBool enable, u8 alpha) {
+ u32 dstAlpha = __GXData->cmode1;
+ GX_SET_REG(dstAlpha, alpha, GX_BP_DSTALPHA_ALPHA_ST, GX_BP_DSTALPHA_ALPHA_END);
+ GX_SET_REG(dstAlpha, enable, GX_BP_DSTALPHA_ENABLE_ST, GX_BP_DSTALPHA_ENABLE_END);
+ GX_BP_LOAD_REG(dstAlpha);
+ __GXData->cmode1 = dstAlpha;
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetFieldMask(GXBool enableEven, GXBool enableOdd) {
+ u32 fieldMaskReg = 0;
+ GX_SET_REG(fieldMaskReg, enableOdd, GX_BP_FIELDMASK_ODD_ST, GX_BP_FIELDMASK_ODD_END);
+ GX_SET_REG(fieldMaskReg, enableEven, GX_BP_FIELDMASK_EVEN_ST, GX_BP_FIELDMASK_EVEN_END);
+ GX_SET_REG(fieldMaskReg, GX_BP_REG_FIELDMASK, 0, 7);
+
+ GX_BP_LOAD_REG(fieldMaskReg);
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetFieldMode(GXBool texLOD, GXBool adjustAR) {
+ GX_SET_REG(__GXData->lpSize, adjustAR, GX_BP_LINEPTWIDTH_ADJUST_ST,
+ GX_BP_LINEPTWIDTH_ADJUST_END);
+ GX_BP_LOAD_REG(__GXData->lpSize);
+
+ __GXFlushTextureState();
+ GX_BP_LOAD_REG(GX_BP_REG_FIELDMODE << 24 | texLOD);
+ __GXFlushTextureState();
+}
diff --git a/src/dolphin/gx/GXTev.c b/src/dolphin/gx/GXTev.c
new file mode 100644
index 00000000..af060678
--- /dev/null
+++ b/src/dolphin/gx/GXTev.c
@@ -0,0 +1,366 @@
+#include "dolphin/gx/GXTev.h"
+#include "dolphin/gx/GX.h"
+
+/* ############################################################################################## */
+static u32 TEVCOpTableST0[] = {
+ 0xC008F8AF, // modulate
+ 0xC008A89F, // decal
+ 0xC008AC8F, // blend
+ 0xC008FFF8, // replace
+ 0xC008FFFA, // passclr
+};
+
+static u32 TEVCOpTableST1[] = {
+ 0xC008F80F, // modulate
+ 0xC008089F, // decal
+ 0xC0080C8F, // blend
+ 0xC008FFF8, // replace
+ 0xC008FFF0, // passclr
+};
+
+static u32 TEVAOpTableST0[] = {
+ 0xC108F2F0, // modulate
+ 0xC108FFD0, // decal
+ 0xC108F2F0, // blend
+ 0xC108FFC0, // replace
+ 0xC108FFD0, // passclr
+};
+
+static u32 TEVAOpTableST1[] = {
+ 0xC108F070, // modulate
+ 0xC108FF80, // decal
+ 0xC108F070, // blend
+ 0xC108FFC0, // replace
+ 0xC108FF80, // passclr
+};
+
+void GXSetTevOp(GXTevStageID stage, GXTevMode mode) {
+ u32* color;
+ u32* alpha;
+ u32 tevReg;
+
+ if (stage == GX_TEVSTAGE0) {
+ color = &TEVCOpTableST0[mode];
+ alpha = &TEVAOpTableST0[mode];
+ } else {
+ color = &TEVCOpTableST1[mode];
+ alpha = &TEVAOpTableST1[mode];
+ }
+
+ tevReg = __GXData->tevc[stage];
+ tevReg = (*color & ~0xFF000000) | (tevReg & 0xFF000000);
+
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(tevReg);
+
+ __GXData->tevc[stage] = tevReg;
+
+ tevReg = __GXData->teva[stage];
+ tevReg = (*alpha & ~0xFF00000F) | (tevReg & 0xFF00000F);
+
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(tevReg);
+
+ __GXData->teva[stage] = tevReg;
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetTevColorIn(GXTevStageID stage, GXTevColorArg a, GXTevColorArg b, GXTevColorArg c,
+ GXTevColorArg d) {
+ u32 tevReg;
+
+ tevReg = __GXData->tevc[stage];
+
+ FAST_FLAG_SET(tevReg, a, 12, 4);
+ FAST_FLAG_SET(tevReg, b, 8, 4);
+ FAST_FLAG_SET(tevReg, c, 4, 4);
+ FAST_FLAG_SET(tevReg, d, 0, 4);
+
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(tevReg);
+
+ __GXData->tevc[stage] = tevReg;
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetTevAlphaIn(GXTevStageID stage, GXTevAlphaArg a, GXTevAlphaArg b, GXTevAlphaArg c,
+ GXTevAlphaArg d) {
+ u32 tevReg;
+
+ tevReg = __GXData->teva[stage];
+
+ FAST_FLAG_SET(tevReg, a, 13, 3);
+ FAST_FLAG_SET(tevReg, b, 10, 3);
+ FAST_FLAG_SET(tevReg, c, 7, 3);
+ FAST_FLAG_SET(tevReg, d, 4, 3);
+
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(tevReg);
+
+ __GXData->teva[stage] = tevReg;
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetTevColorOp(GXTevStageID stage, GXTevOp op, GXTevBias bias, GXTevScale scale,
+ GXBool doClamp, GXTevRegID outReg) {
+ u32 tevReg;
+
+ tevReg = __GXData->tevc[stage];
+ FAST_FLAG_SET(tevReg, op & 1, 18, 1);
+
+ if (op <= 1) {
+ FAST_FLAG_SET(tevReg, scale, 20, 2);
+ FAST_FLAG_SET(tevReg, bias, 16, 2);
+ } else {
+ FAST_FLAG_SET(tevReg, (op >> 1) & 3, 20, 2);
+ FAST_FLAG_SET(tevReg, 3, 16, 2);
+ }
+
+ FAST_FLAG_SET(tevReg, doClamp, 19, 1);
+ FAST_FLAG_SET(tevReg, outReg, 22, 2);
+
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(tevReg);
+ __GXData->tevc[stage] = tevReg;
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetTevAlphaOp(GXTevStageID stage, GXTevOp op, GXTevBias bias, GXTevScale scale,
+ GXBool doClamp, GXTevRegID outReg) {
+ u32 tevReg;
+
+ tevReg = __GXData->teva[stage];
+ FAST_FLAG_SET(tevReg, op & 1, 18, 1);
+
+ if (op <= 1) {
+ FAST_FLAG_SET(tevReg, scale, 20, 2);
+ FAST_FLAG_SET(tevReg, bias, 16, 2);
+ } else {
+ FAST_FLAG_SET(tevReg, (op >> 1) & 3, 20, 2);
+ FAST_FLAG_SET(tevReg, 3, 16, 2);
+ }
+
+ FAST_FLAG_SET(tevReg, doClamp, 19, 1);
+ FAST_FLAG_SET(tevReg, outReg, 22, 2);
+
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(tevReg);
+ __GXData->teva[stage] = tevReg;
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetTevColor(GXTevRegID reg, GXColor color) {
+ u32 col = *(u32*)&color;
+ u32 ra = (0xE0 + reg * 2) << 24;
+ u32 bg = (0xE1 + reg * 2) << 24;
+
+ GX_SET_REG(ra, col >> 24, 24, 31);
+ GX_SET_REG(bg, col >> 8, 24, 31);
+ GX_SET_REG(bg, col >> 16, 12, 19);
+ GX_SET_REG(ra, col & 0xFF, 12, 19);
+
+ GX_BP_LOAD_REG(ra);
+ GX_BP_LOAD_REG(bg);
+ GX_BP_LOAD_REG(bg);
+ GX_BP_LOAD_REG(bg);
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetTevColorS10(GXTevRegID reg, GXColorS10 color) {
+ u32 col = *(u32*)&color;
+ u32 col1 = ((u32*)&color)[1];
+ u32 ra = (0xE0 + reg * 2) << 24;
+ u32 bg = (0xE1 + reg * 2) << 24;
+
+ GX_SET_REG(ra, col >> 16, 21, 31);
+ GX_SET_REG(bg, col1 >> 16, 21, 31);
+ GX_SET_REG(bg, col & 0x7FF, 9, 19);
+ GX_SET_REG(ra, col1 & 0x7FF, 9, 19);
+
+ GX_BP_LOAD_REG(ra);
+ GX_BP_LOAD_REG(bg);
+ GX_BP_LOAD_REG(bg);
+ GX_BP_LOAD_REG(bg);
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetTevKColor(GXTevKColorID id, GXColor color) {
+ u32 col = *(u32*)&color;
+ u32 ra;
+ u32 bg;
+
+ ra = (0xE0 + id * 2) << 24;
+ GX_SET_REG(ra, col >> 24, 24, 31);
+ GX_SET_REG(ra, col & 0xFF, 12, 19);
+ GX_SET_REG(ra, 8, 8, 11);
+
+ bg = (0xE1 + id * 2) << 24;
+ GX_SET_REG(bg, col >> 8, 24, 31);
+ GX_SET_REG(bg, col >> 16, 12, 19);
+ GX_SET_REG(bg, 8, 8, 11);
+
+ GX_BP_LOAD_REG(ra);
+ GX_BP_LOAD_REG(bg);
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetTevKColorSel(GXTevStageID stage, GXTevKColorSel sel) {
+ u32* reg;
+
+ reg = &__GXData->tevKsel[stage >> 1];
+
+ if (stage & 1) {
+ GX_SET_REG(*reg, sel, 13, 17);
+ } else {
+ GX_SET_REG(*reg, sel, 23, 27);
+ }
+
+ GX_BP_LOAD_REG(*reg);
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetTevKAlphaSel(GXTevStageID stage, GXTevKAlphaSel sel) {
+ u32* reg;
+
+ reg = &__GXData->tevKsel[stage >> 1];
+
+ if (stage & 1) {
+ GX_SET_REG(*reg, sel, 8, 12);
+ } else {
+ GX_SET_REG(*reg, sel, 18, 22);
+ }
+
+ GX_BP_LOAD_REG(*reg);
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetTevSwapMode(GXTevStageID stage, GXTevSwapSel rasSel, GXTevSwapSel texSel) {
+ u32* reg = &__GXData->teva[stage];
+ GX_SET_REG(*reg, rasSel, 30, 31);
+ GX_SET_REG(*reg, texSel, 28, 29);
+
+ GX_BP_LOAD_REG(*reg);
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetTevSwapModeTable(GXTevSwapSel table, GXTevColorChan red, GXTevColorChan green,
+ GXTevColorChan blue, GXTevColorChan alpha) {
+ u32* reg;
+
+ reg = &__GXData->tevKsel[table << 1];
+ GX_SET_REG(*reg, red, 30, 31);
+ GX_SET_REG(*reg, green, 28, 29);
+
+ GX_BP_LOAD_REG(*reg);
+
+ reg = &__GXData->tevKsel[(table << 1) + 1];
+ GX_SET_REG(*reg, blue, 30, 31);
+ GX_SET_REG(*reg, alpha, 28, 29);
+
+ GX_BP_LOAD_REG(*reg);
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetAlphaCompare(GXCompare comp0, u8 ref0, GXAlphaOp op, GXCompare comp1, u8 ref1) {
+ u32 reg = 0xF3000000;
+
+ GX_SET_REG(reg, ref0, 24, 31);
+ GX_SET_REG(reg, ref1, 16, 23);
+ GX_SET_REG(reg, comp0, 13, 15);
+ GX_SET_REG(reg, comp1, 10, 12);
+ GX_SET_REG(reg, op, 8, 9);
+
+ GX_BP_LOAD_REG(reg);
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetZTexture(GXZTexOp op, GXTexFmt format, u32 bias) {
+ u32 val1;
+ u32 val2;
+ u32 val3;
+
+ val1 = 0;
+ GX_SET_REG(val1, bias, 8, 31);
+ GX_SET_REG(val1, 0xF4, 0, 7);
+
+ val2 = 0;
+ switch (format) {
+ case GX_TF_Z8:
+ val3 = 0;
+ break;
+ case GX_TF_Z16:
+ val3 = 1;
+ break;
+ case GX_TF_Z24X8:
+ val3 = 2;
+ break;
+ default:
+ val3 = 2;
+ break;
+ }
+
+ GX_SET_REG(val2, val3, 30, 31);
+ GX_SET_REG(val2, op, 28, 29);
+ GX_SET_REG(val2, 0xF5, 0, 7);
+
+ GX_BP_LOAD_REG(val1);
+
+ GX_BP_LOAD_REG(val2);
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetTevOrder(GXTevStageID stage, GXTexCoordID coord, GXTexMapID map, GXChannelID color) {
+ static int c2r[] = {0, 1, 0, 1, 0, 1, 7, 5, 6};
+
+ u32* reg;
+ u32 tempMap;
+ u32 tempCoord;
+
+ reg = &__GXData->tref[stage / 2];
+ __GXData->texmapId[stage] = map;
+
+ tempMap = map & ~0x100;
+ tempMap = (tempMap >= GX_MAX_TEXMAP) ? GX_TEXMAP0 : tempMap;
+
+ if (coord >= GX_MAXCOORD) {
+ tempCoord = GX_TEXCOORD0;
+ __GXData->tevTcEnab = __GXData->tevTcEnab & ~(1 << stage);
+ } else {
+ tempCoord = coord;
+ __GXData->tevTcEnab = __GXData->tevTcEnab | (1 << stage);
+ }
+
+ if (stage & 1) {
+ GX_SET_REG(*reg, tempMap, 17, 19);
+ GX_SET_REG(*reg, tempCoord, 14, 16);
+ GX_SET_REG(*reg, (color == GX_COLOR_NULL ? 7 : c2r[color]), 10, 12);
+ GX_SET_REG(*reg, ((map != GX_TEXMAP_NULL) && !(map & 0x100)), 13, 13);
+
+ } else {
+ GX_SET_REG(*reg, tempMap, 29, 31);
+ GX_SET_REG(*reg, tempCoord, 26, 28);
+ GX_SET_REG(*reg, (color == GX_COLOR_NULL ? 7 : c2r[color]), 22, 24);
+ GX_SET_REG(*reg, ((map != GX_TEXMAP_NULL) && !(map & 0x100)), 25, 25);
+ }
+
+ GX_BP_LOAD_REG(*reg);
+
+ __GXData->bpSentNot = GX_FALSE;
+ __GXData->dirtyState |= 1;
+}
+
+void GXSetNumTevStages(u8 count) {
+ GX_SET_REG(__GXData->genMode, count - 1, 18, 21);
+
+ __GXData->dirtyState |= 0x4;
+}
diff --git a/src/dolphin/gx/GXTexture.c b/src/dolphin/gx/GXTexture.c
new file mode 100644
index 00000000..e4b8485d
--- /dev/null
+++ b/src/dolphin/gx/GXTexture.c
@@ -0,0 +1,593 @@
+#include "dolphin/gx/GXTexture.h"
+#include "dolphin/gx/GX.h"
+
+#define GET_TILE_COUNT(a, b) (((a) + (1 << (b)) - 1) >> (b))
+
+inline void __GXGetTexTileShift(GXTexFmt format, u32* widthTiles, u32* heightTiles) {
+ switch (format) {
+ case GX_TF_I4:
+ case GX_TF_C4:
+ case GX_TF_CMPR:
+ case GX_CTF_R4:
+ case GX_CTF_Z4:
+ *widthTiles = 3;
+ *heightTiles = 3;
+ break;
+
+ case GX_TF_I8:
+ case GX_TF_IA4:
+ case GX_TF_C8:
+ case GX_TF_Z8:
+ case GX_CTF_RA4:
+ case GX_CTF_R8:
+ case GX_CTF_G8:
+ case GX_CTF_B8:
+ case GX_CTF_RG8:
+ case GX_CTF_Z8M:
+ case GX_CTF_Z8L:
+ *widthTiles = 3;
+ *heightTiles = 2;
+ break;
+
+ case GX_TF_IA8:
+ case GX_TF_RGB565:
+ case GX_TF_RGB5A3:
+ case GX_TF_RGBA8:
+ case GX_TF_C14X2:
+ case GX_TF_Z16:
+ case GX_TF_Z24X8:
+ case GX_CTF_RA8:
+ case GX_CTF_GB8:
+ case 44:
+ case GX_CTF_Z16L:
+ *widthTiles = 2;
+ *heightTiles = 2;
+ break;
+
+ default:
+ *heightTiles = 0;
+ *widthTiles = 0;
+ break;
+ }
+}
+
+u32 GXGetTexBufferSize(u16 width, u16 height, u32 format, GXBool mipmap, u8 max_lod) {
+ u32 widthTiles, heightTiles, tileSize, bufferSize, numX, numY, i;
+
+ __GXGetTexTileShift(format, &widthTiles, &heightTiles);
+
+ if (format == GX_TF_RGBA8 || format == GX_TF_Z24X8) {
+ tileSize = 0x40;
+ } else {
+ tileSize = 0x20;
+ }
+
+ if (mipmap == GX_TRUE) {
+ bufferSize = 0;
+
+ for (i = 0; i < max_lod; i++) {
+ numX = GET_TILE_COUNT(width, widthTiles);
+ numY = GET_TILE_COUNT(height, heightTiles);
+
+ bufferSize += numX * numY * tileSize;
+ if (width == 1 && height == 1) {
+ break;
+ }
+
+ width = (width > 1) ? (width >> 1) : 1;
+ height = (height > 1) ? (height >> 1) : 1;
+ }
+
+ } else {
+ numX = GET_TILE_COUNT(width, widthTiles);
+ numY = GET_TILE_COUNT(height, heightTiles);
+ bufferSize = numX * numY * tileSize;
+ }
+
+ return bufferSize;
+}
+
+void __GetImageTileCount(GXTexFmt format, u16 width, u16 height, u32* a, u32* b, u32* c) {
+ u32 widthTiles, heightTiles;
+
+ __GXGetTexTileShift(format, &widthTiles, &heightTiles);
+
+ if (width <= 0) {
+ width = 1;
+ }
+
+ if (height <= 0) {
+ height = 1;
+ }
+
+ *a = GET_TILE_COUNT(width, widthTiles);
+ *b = GET_TILE_COUNT(height, heightTiles);
+ *c = (format == GX_TF_RGBA8 || format == GX_TF_Z24X8) ? 2 : 1;
+}
+
+void GXInitTexObj(GXTexObj* obj, void* imagePtr, u16 width, u16 height, GXTexFmt format,
+ GXTexWrapMode sWrap, GXTexWrapMode tWrap, GXBool useMIPmap) {
+ u32 imageBase;
+ u16 a, b;
+ u32 c, d;
+
+ GXTexObj* internal = (GXTexObj*)obj;
+ memset(internal, 0, sizeof(*internal));
+
+ GX_SET_REG(internal->texture_filter, sWrap, 30, 31);
+ GX_SET_REG(internal->texture_filter, tWrap, 28, 29);
+ GX_SET_REG(internal->texture_filter, GX_TRUE, 27, 27);
+
+ if (useMIPmap) {
+ u32 maxDimSize;
+ internal->texture_flags |= 1;
+ if (format == 8 || format == 9 || format == 10) {
+ GX_SET_REG(internal->texture_filter, 5, 24, 26);
+ } else {
+ GX_SET_REG(internal->texture_filter, 6, 24, 26);
+ }
+
+ maxDimSize = width > height ? 31 - __cntlzw(width) : 31 - __cntlzw(height);
+
+ GX_SET_REG(internal->texture_lod, (maxDimSize) * 16.f, 16, 23);
+ } else {
+ GX_SET_REG(internal->texture_filter, 4, 24, 26);
+ }
+
+ internal->texture_format = format;
+ GX_SET_REG(internal->texture_size, width - 1, 22, 31);
+ GX_SET_REG(internal->texture_size, height - 1, 12, 21);
+
+ GX_SET_REG(internal->texture_size, format & 0xf, 8, 11);
+ imageBase = (u32)imagePtr >> 5;
+ GX_SET_REG(internal->texture_address, imageBase, 11, 31);
+
+ switch (format & 0xf) {
+ case 0:
+ case 8:
+ internal->texture_tile_type = 1;
+ a = 3;
+ b = 3;
+ break;
+ case 1:
+ case 2:
+ case 9:
+ internal->texture_tile_type = 2;
+ a = 3;
+ b = 2;
+ break;
+ case 3:
+ case 4:
+ case 5:
+ case 10:
+ internal->texture_tile_type = 2;
+ a = 2;
+ b = 2;
+ break;
+ case 6:
+ internal->texture_tile_type = 3;
+ a = 2;
+ b = 2;
+ break;
+ case 0xe:
+ internal->texture_tile_type = 0;
+ a = 3;
+ b = 3;
+ break;
+ default:
+ internal->texture_tile_type = 2;
+ a = 2;
+ b = 2;
+ break;
+ }
+
+ internal->texture_time_count = (GET_TILE_COUNT(width, a) * GET_TILE_COUNT(height, b)) & 0x7fff;
+
+ internal->texture_flags |= 2;
+}
+
+void GXInitTexObjCI(GXTexObj* obj, void* imagePtr, u16 width, u16 height, GXCITexFmt format,
+ GXTexWrapMode sWrap, GXTexWrapMode tWrap, GXBool useMIPmap, u32 tlut_name) {
+ GXTexObj* internal = (GXTexObj*)obj;
+
+ GXInitTexObj(obj, imagePtr, width, height, format, sWrap, tWrap, useMIPmap);
+
+ internal->texture_flags &= ~2;
+ internal->tlut_name = tlut_name;
+}
+
+u8 GXTexMode0Ids[8] = {0x80, 0x81, 0x82, 0x83, 0xA0, 0xA1, 0xA2, 0xA3};
+
+u8 GXTexMode1Ids[8] = {0x84, 0x85, 0x86, 0x87, 0xA4, 0xA5, 0xA6, 0xA7};
+
+u8 GXTexImage0Ids[8] = {0x88, 0x89, 0x8a, 0x8b, 0xA8, 0xA9, 0xAa, 0xAb};
+
+u8 GXTexImage1Ids[8] = {0x8c, 0x8d, 0x8e, 0x8f, 0xAc, 0xAd, 0xAe, 0xAf};
+
+u8 GXTexImage2Ids[8] = {0x90, 0x91, 0x92, 0x93, 0xB0, 0xB1, 0xB2, 0xB3};
+
+u8 GXTexImage3Ids[8] = {0x94, 0x95, 0x96, 0x97, 0xB4, 0xB5, 0xB6, 0xB7};
+
+u8 GXTexTlutIds[8] = {0x98, 0x99, 0x9a, 0x9b, 0xB8, 0xB9, 0xBa, 0xBb};
+
+u8 GX2HWFiltConv[6] = {0x00, 0x04, 0x01, 0x05, 0x02, 0x06};
+
+void GXInitTexObjLOD(GXTexObj* obj, GXTexFilter minFilter, GXTexFilter maxFilter, f32 minLOD,
+ f32 maxLOD, f32 lodBias, GXBool doBiasClamp, GXBool doEdgeLOD,
+ GXAnisotropy maxAniso) {
+ GXTexObj* internal = (GXTexObj*)obj;
+ u8 reg1, reg2;
+ if (lodBias < -4.0f) {
+ lodBias = -4.0f;
+ } else if (lodBias >= 4.0f) {
+ lodBias = 3.99f;
+ }
+
+ GX_SET_REG(internal->texture_filter, lodBias * 32.0f, 15, 22);
+ GX_SET_REG(internal->texture_filter, maxFilter == 1 ? 1 : 0, 27, 27);
+ GX_SET_REG(internal->texture_filter, GX2HWFiltConv[minFilter], 24, 26);
+ GX_SET_REG(internal->texture_filter, doEdgeLOD ? 0 : 1, 23, 23);
+ GX_SET_REG(internal->texture_filter, 0, 14, 14);
+ GX_SET_REG(internal->texture_filter, 0, 13, 13);
+ GX_SET_REG(internal->texture_filter, maxAniso, 11, 12);
+ GX_SET_REG(internal->texture_filter, doBiasClamp, 10, 10);
+
+ if (minLOD < 0.0f) {
+ minLOD = 0.0f;
+ } else if (minLOD > 10.0f) {
+ minLOD = 10.0f;
+ }
+ reg1 = minLOD * 16.0f;
+
+ if (maxLOD < 0.0f) {
+ maxLOD = 0.0f;
+ } else if (maxLOD > 10.0f) {
+ maxLOD = 10.0f;
+ }
+ reg2 = maxLOD * 16.0f;
+
+ GX_SET_REG(internal->texture_lod, reg1, 24, 31);
+ GX_SET_REG(internal->texture_lod, reg2, 16, 23);
+}
+
+u16 GXGetTexObjWidth(GXTexObj* obj) {
+ return (obj->texture_size & 0x3ff) + 1;
+}
+
+u16 GXGetTexObjHeight(GXTexObj* obj) {
+ return ((obj->texture_size >> 10) & 0x3ff) + 1;
+}
+
+GXTexFmt GXGetTexObjFmt(const GXTexObj* obj) {
+ return obj->texture_format;
+}
+
+GXTexWrapMode GXGetTexObjWrapS(GXTexObj* obj) {
+ return obj->texture_filter & 0x3;
+}
+
+GXTexWrapMode GXGetTexObjWrapT(GXTexObj* obj) {
+ return (obj->texture_filter & 0xc) >> 2;
+}
+
+GXBool GXGetTexObjMipMap(const GXTexObj* obj) {
+ return (obj->texture_flags & 1) == 1;
+}
+
+u32 GXGetTexObjTlut(GXTexObj* obj) {
+ return obj->tlut_name;
+}
+
+void GXLoadTexObjPreLoaded(GXTexObj* obj, GXTexRegion* region, GXTexMapID map) {
+ u8 stackManipulation[0x18];
+
+ GXTexObj* internalObj = (GXTexObj*)obj;
+ GXTexRegion* internalRegion = (GXTexRegion*)region;
+
+ GX_SET_REG(internalObj->texture_filter, GXTexMode0Ids[map], 0, 7);
+ GX_SET_REG(internalObj->texture_lod, GXTexMode1Ids[map], 0, 7);
+ GX_SET_REG(internalObj->texture_size, GXTexImage0Ids[map], 0, 7);
+
+ GX_SET_REG(internalRegion->unk0, GXTexImage1Ids[map], 0, 7);
+ GX_SET_REG(internalRegion->unk4, GXTexImage2Ids[map], 0, 7);
+
+ GX_SET_REG(internalObj->texture_address, GXTexImage3Ids[map], 0, 7);
+
+ GX_BP_LOAD_REG(internalObj->texture_filter);
+ GX_BP_LOAD_REG(internalObj->texture_lod);
+ GX_BP_LOAD_REG(internalObj->texture_size);
+ GX_BP_LOAD_REG(internalRegion->unk0);
+ GX_BP_LOAD_REG(internalRegion->unk4);
+ GX_BP_LOAD_REG(internalObj->texture_address);
+
+ if ((internalObj->texture_flags & 2) == 0) {
+ GXTlutObj* tlut = (GXTlutObj*)__GXData->tlutRegionCallback(internalObj->tlut_name);
+ GX_SET_REG(tlut->address, GXTexTlutIds[map], 0, 7);
+
+ GX_BP_LOAD_REG(tlut->address);
+ }
+
+ __GXData->tImage0[map] = internalObj->texture_size;
+ __GXData->tMode0[map] = internalObj->texture_filter;
+
+ __GXData->dirtyState |= GX_DIRTY_SU_TEX;
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXLoadTexObj(GXTexObj* obj, GXTexMapID map) {
+ GXTexRegion* ret = (GXTexRegion*)__GXData->texRegionCallback(obj, map);
+
+ GXLoadTexObjPreLoaded(obj, ret, map);
+}
+
+void GXInitTlutObj(GXTlutObj* obj, void* table, GXTlutFmt format, u16 numEntries) {
+ GXTlutObj* internal = (GXTlutObj*)obj;
+
+ internal->format = 0;
+
+ GX_SET_REG(internal->format, format, 20, 21);
+ GX_SET_REG(internal->address, (u32)table >> 5, 11, 31);
+ GX_SET_REG(internal->address, 100, 0, 7);
+
+ internal->numEntries = numEntries;
+}
+
+void GXLoadTlut(GXTlutObj* obj, u32 tlut_name) {
+ GXTlutObj* internal = (GXTlutObj*)obj;
+ GXTlutRegion* ret = (GXTlutRegion*)__GXData->tlutRegionCallback(tlut_name);
+ u32 reg;
+
+ __GXFlushTextureState();
+
+ GX_BP_LOAD_REG(internal->address);
+ GX_BP_LOAD_REG(ret->unk0);
+
+ __GXFlushTextureState();
+
+ reg = ret->unk0;
+ GX_SET_REG(internal->format, reg, 22, 31);
+
+ ret->tlutObj = *internal;
+}
+
+void GXInitTexCacheRegion(GXTexRegion* region, GXBool is32bMIPmap, u32 memEven,
+ GXTexCacheSize sizeEven, u32 memOdd, GXTexCacheSize sizeOdd) {
+ GXTexRegion* internal = (GXTexRegion*)region;
+
+ u32 reg;
+ switch (sizeEven) {
+ case 0:
+ reg = 3;
+ break;
+ case 1:
+ reg = 4;
+ break;
+ case 2:
+ reg = 5;
+ break;
+ }
+
+ internal->unk0 = 0;
+
+ GX_SET_REG(internal->unk0, memEven >> 5, 17, 31);
+ GX_SET_REG(internal->unk0, reg, 14, 16);
+ GX_SET_REG(internal->unk0, reg, 11, 13);
+ GX_SET_REG(internal->unk0, 0, 10, 10);
+
+ switch (sizeOdd) {
+ case 0:
+ reg = 3;
+ break;
+ case 1:
+ reg = 4;
+ break;
+ case 2:
+ reg = 5;
+ break;
+ case 3:
+ reg = 0;
+ break;
+ }
+
+ internal->unk4 = 0;
+ GX_SET_REG(internal->unk4, memOdd >> 5, 17, 31);
+ GX_SET_REG(internal->unk4, reg, 14, 16);
+ GX_SET_REG(internal->unk4, reg, 11, 13);
+
+ internal->unkC = is32bMIPmap;
+ internal->unkD = 1;
+}
+
+void GXInitTlutRegion(GXTlutRegion* region, u32 memAddr, GXTlutSize tlutSize) {
+ GXTlutRegion* internal = (GXTlutRegion*)region;
+
+ internal->unk0 = 0;
+ GX_SET_REG(internal->unk0, (memAddr - 0x80000) >> 9, 22, 31);
+ GX_SET_REG(internal->unk0, tlutSize, 11, 21);
+ GX_SET_REG(internal->unk0, 0x65, 0, 7);
+}
+
+void GXInvalidateTexAll(void) {
+ __GXFlushTextureState();
+ GXFIFO.u8 = 0x61;
+ GXFIFO.u32 = 0x66001000;
+ GXFIFO.u8 = 0x61;
+ GXFIFO.u32 = 0x66001100;
+ __GXFlushTextureState();
+}
+
+GXTexRegionCallback GXSetTexRegionCallback(GXTexRegionCallback callback) {
+ GXTexRegionCallback prev = __GXData->texRegionCallback;
+ __GXData->texRegionCallback = callback;
+ return prev;
+}
+
+GXTlutRegionCallback GXSetTlutRegionCallback(GXTlutRegionCallback callback) {
+ GXTlutRegionCallback prev = __GXData->tlutRegionCallback;
+ __GXData->tlutRegionCallback = callback;
+ return prev;
+}
+
+void GXSetTexCoordScaleManually(GXTexCoordID coord, GXBool enable, u16 s_scale, u16 t_scale) {
+ /* Nonmatching */
+}
+
+void __SetSURegs(u32 texImgIndex, u32 setUpRegIndex) {
+ u16 a1, a2;
+ GXBool b, c;
+
+ a1 = GX_GET_REG(__GXData->tImage0[texImgIndex], 22, 31);
+ a2 = (__GXData->tImage0[texImgIndex] & (0x3ff << 10)) >> 10;
+
+ GX_SET_REG(__GXData->suTs0[setUpRegIndex], a1, 16, 31);
+ GX_SET_REG(__GXData->suTs1[setUpRegIndex], a2, 16, 31);
+
+ b = GX_GET_REG(__GXData->tMode0[texImgIndex], 30, 31) == 1;
+ c = GX_GET_REG(__GXData->tMode0[texImgIndex], 28, 29) == 1;
+
+ GX_SET_REG(__GXData->suTs0[setUpRegIndex], b, 15, 15);
+ GX_SET_REG(__GXData->suTs1[setUpRegIndex], c, 15, 15);
+
+ GX_BP_LOAD_REG(__GXData->suTs0[setUpRegIndex]);
+ GX_BP_LOAD_REG(__GXData->suTs1[setUpRegIndex]);
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+#pragma dont_inline on
+void __GXSetSUTexRegs(void) {
+ u32 i;
+ u32 b;
+ u32 a;
+ u32 c;
+ u32 d;
+ u32 stackFiller;
+ if (__GXData->tcsManEnab != 0xff) {
+ a = GX_GET_REG(__GXData->genMode, 18, 21) + 1;
+ b = GX_GET_REG(__GXData->genMode, 13, 15);
+ for (i = 0; i < b; i++) {
+ switch (i) {
+ case 0:
+ c = GX_GET_REG(__GXData->iref, 29, 31);
+ d = GX_GET_REG(__GXData->iref, 26, 28);
+ break;
+ case 1:
+ c = GX_GET_REG(__GXData->iref, 23, 25);
+ d = GX_GET_REG(__GXData->iref, 20, 22);
+ break;
+ case 2:
+ c = GX_GET_REG(__GXData->iref, 17, 19);
+ d = GX_GET_REG(__GXData->iref, 14, 16);
+ break;
+ case 3:
+ c = GX_GET_REG(__GXData->iref, 11, 13);
+ d = GX_GET_REG(__GXData->iref, 8, 10);
+ break;
+ }
+
+ if (!(__GXData->tcsManEnab & (1 << d))) {
+ __SetSURegs(c, d);
+ }
+ }
+
+ for (i = 0; i < a; i++) {
+ u32* g = &__GXData->tref[i / 2];
+
+ c = __GXData->texmapId[i] & ~0x100;
+
+ if (i & 1) {
+ d = GX_GET_REG(*g, 14, 16);
+ } else {
+ d = GX_GET_REG(*g, 26, 28);
+ }
+
+ if (c != 0xff && !(__GXData->tcsManEnab & (1 << d)) && __GXData->tevTcEnab & (1 << i)) {
+ __SetSURegs(c, d);
+ }
+ }
+ }
+}
+#pragma dont_inline reset
+
+void __GXSetTmemConfig(u32 config) {
+ switch (config) {
+ case 2:
+ GX_BP_LOAD_REG(0x8c0d8000);
+ GX_BP_LOAD_REG(0x900dc000);
+
+ GX_BP_LOAD_REG(0x8d0d8800);
+ GX_BP_LOAD_REG(0x910dc800);
+
+ GX_BP_LOAD_REG(0x8e0d9000);
+ GX_BP_LOAD_REG(0x920dd000);
+
+ GX_BP_LOAD_REG(0x8f0d9800);
+ GX_BP_LOAD_REG(0x930dd800);
+
+ GX_BP_LOAD_REG(0xac0da000);
+ GX_BP_LOAD_REG(0xb00dc400);
+
+ GX_BP_LOAD_REG(0xad0da800);
+ GX_BP_LOAD_REG(0xb10dcc00);
+
+ GX_BP_LOAD_REG(0xae0db000);
+ GX_BP_LOAD_REG(0xb20dd400);
+
+ GX_BP_LOAD_REG(0xaf0db800);
+ GX_BP_LOAD_REG(0xb30ddc00);
+ break;
+ case 1:
+ GX_BP_LOAD_REG(0x8c0d8000);
+ GX_BP_LOAD_REG(0x900dc000);
+
+ GX_BP_LOAD_REG(0x8d0d8800);
+ GX_BP_LOAD_REG(0x910dc800);
+
+ GX_BP_LOAD_REG(0x8e0d9000);
+ GX_BP_LOAD_REG(0x920dd000);
+
+ GX_BP_LOAD_REG(0x8f0d9800);
+ GX_BP_LOAD_REG(0x930dd800);
+
+ GX_BP_LOAD_REG(0xac0da000);
+ GX_BP_LOAD_REG(0xb00de000);
+
+ GX_BP_LOAD_REG(0xad0da800);
+ GX_BP_LOAD_REG(0xb10de800);
+
+ GX_BP_LOAD_REG(0xae0db000);
+ GX_BP_LOAD_REG(0xb20df000);
+
+ GX_BP_LOAD_REG(0xaf0db800);
+ GX_BP_LOAD_REG(0xb30df800);
+
+ break;
+ case 0:
+ default:
+ GX_BP_LOAD_REG(0x8c0d8000);
+ GX_BP_LOAD_REG(0x900dc000);
+
+ GX_BP_LOAD_REG(0x8d0d8400);
+ GX_BP_LOAD_REG(0x910dc400);
+
+ GX_BP_LOAD_REG(0x8e0d8800);
+ GX_BP_LOAD_REG(0x920dc800);
+
+ GX_BP_LOAD_REG(0x8f0d8c00);
+ GX_BP_LOAD_REG(0x930dcc00);
+
+ GX_BP_LOAD_REG(0xac0d9000);
+ GX_BP_LOAD_REG(0xb00dd000);
+
+ GX_BP_LOAD_REG(0xad0d9400);
+ GX_BP_LOAD_REG(0xb10dd400);
+
+ GX_BP_LOAD_REG(0xae0d9800);
+ GX_BP_LOAD_REG(0xb20dd800);
+
+ GX_BP_LOAD_REG(0xaf0d9c00);
+ GX_BP_LOAD_REG(0xb30ddc00);
+
+ break;
+ }
+}
diff --git a/src/dolphin/gx/GXTransform.c b/src/dolphin/gx/GXTransform.c
new file mode 100644
index 00000000..1bf66bbb
--- /dev/null
+++ b/src/dolphin/gx/GXTransform.c
@@ -0,0 +1,316 @@
+#include "dolphin/gx/GXTransform.h"
+#include "dolphin/gx/GX.h"
+#include "dolphin/os/OS.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
+}
+
+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;
+
+ ASSERTMSG(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);
+}
+
+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;
+}
+
+void GXSetProjectionv(f32* proj) {
+ __GXData->projType = proj[0] == 0.0f ? GX_PERSPECTIVE : GX_ORTHOGRAPHIC;
+ Copy6Floats(&proj[1], __GXData->projMtx);
+
+ __GXSetProjection();
+ __GXData->bpSentNot = GX_TRUE;
+}
+
+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
+}
+
+void GXLoadPosMtxImm(Mtx mtx, u32 id) {
+ GX_XF_LOAD_REGS(4 * 3 - 1, id * 4 + GX_XF_MEM_POSMTX);
+ WriteMTXPS4x3(&GXFIFO, 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
+}
+
+void GXLoadNrmMtxImm(Mtx mtx, u32 id) {
+ GX_XF_LOAD_REGS(3 * 3 - 1, id * 3 + GX_XF_MEM_NRMMTX);
+ WriteMTXPS3x3(&GXFIFO, mtx);
+}
+
+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
+}
+
+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(&GXFIFO, mtx);
+ } else {
+ WriteMTXPS4x2(&GXFIFO, mtx);
+ }
+}
+
+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);
+}
+
+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;
+}
+
+void GXGetViewportv(f32* p) {
+ Copy6Floats(&__GXData->vpLeft, p);
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+void GXSetClipMode(GXClipMode mode) {
+ GX_XF_LOAD_REG(GX_XF_REG_CLIPDISABLE, mode);
+ __GXData->bpSentNot = GX_TRUE;
+}
+
+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;
+}
diff --git a/src/m_Do/m_Do_graphic.cpp b/src/m_Do/m_Do_graphic.cpp
index 10618b76..9c84bb00 100644
--- a/src/m_Do/m_Do_graphic.cpp
+++ b/src/m_Do/m_Do_graphic.cpp
@@ -522,7 +522,7 @@ void drawDepth(view_class* view, view_port_class* viewport, int depth) {
GXCopyTex(zbuf, GX_FALSE);
GXSetTexCopySrc(x, y, w, h);
- GXSetTexCopyDst(hw, hh, mDoGph_gInf_c::getFrameBufferTimg()->format, GX_TRUE);
+ GXSetTexCopyDst(hw, hh, (GXTexFmt)mDoGph_gInf_c::getFrameBufferTimg()->format, GX_TRUE);
GXCopyTex(fbbuf, GX_FALSE);
GXInitTexObj(mDoGph_gInf_c::getZbufferTexObj(), zbuf, w, h, GX_TF_IA8, GX_CLAMP, GX_CLAMP, GX_FALSE);
@@ -933,7 +933,7 @@ bool mDoGph_screenCapture() {
setUpRectangle();
GXSetTexCopySrc(centerX - sizeW, centerY - sizeH, sizeW2, sizeH2);
- GXSetTexCopyDst(sizeW, sizeH, mCaptureCaptureFormat, GX_TRUE);
+ GXSetTexCopyDst(sizeW, sizeH, (_GXTexFmt)mCaptureCaptureFormat, GX_TRUE);
DCInvalidateRange(mCaptureCaptureBuffer, mCaptureCaptureSize);
GXCopyTex(mCaptureCaptureBuffer, GX_FALSE);
GXPixModeSync();