diff --git a/projects/msvc12/GLideN64.vcxproj b/projects/msvc12/GLideN64.vcxproj
index ac3f13a6..ae0e32a2 100644
--- a/projects/msvc12/GLideN64.vcxproj
+++ b/projects/msvc12/GLideN64.vcxproj
@@ -355,6 +355,7 @@
+
@@ -480,6 +481,7 @@
+
diff --git a/projects/msvc12/GLideN64.vcxproj.filters b/projects/msvc12/GLideN64.vcxproj.filters
index 0209945a..ce7cad76 100644
--- a/projects/msvc12/GLideN64.vcxproj.filters
+++ b/projects/msvc12/GLideN64.vcxproj.filters
@@ -338,9 +338,6 @@
Source Files
-
- Source Files
-
Source Files\Graphics
@@ -353,6 +350,12 @@
Source Files
+
+ Source Files\uCodes
+
+
+ Source Files\uCodes
+
@@ -649,11 +652,14 @@
Header Files
-
- Header Files
-
Header Files
+
+ Header Files\uCodes
+
+
+ Header Files\uCodes
+
\ No newline at end of file
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index d89c05a9..e57e0200 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -50,6 +50,7 @@ set(GLideN64_SOURCES
S2DEX2.cpp
S2DEX.cpp
SoftwareRender.cpp
+ T3DUX.cpp
TexrectDrawer.cpp
TextDrawer.cpp
TextureFilterHandler.cpp
diff --git a/src/GBI.cpp b/src/GBI.cpp
index 10d583ea..81792d1a 100644
--- a/src/GBI.cpp
+++ b/src/GBI.cpp
@@ -57,8 +57,10 @@ SpecialMicrocodeInfo specialMicrocodes[] =
{ F3DPD, true, 0x1c4f7869, "Perfect Dark" },
{ Turbo3D, false, 0x2bdcfc8a, "Turbo3D" },
{ F3DEX2CBFD, true, 0x1b4ace88, "Conker's Bad Fur Day" },
- { F3DEX2MM, true, 0xd39a0d4f, "Animal Forest" },
- { S2DEX2, false, 0x2c399dd, "Animal Forest" }
+ { F3DEX2MM, true, 0xd39a0d4f, "Animal Forest" },
+ { S2DEX2, false, 0x2c399dd, "Animal Forest" },
+ { T3DUX, false, 0xbad437f2, "T3DUX vers 0.83 for Toukon Road" },
+ { T3DUX, false, 0xd0a1aa3d, "T3DUX vers 0.85 for Toukon Road 2" }
};
u32 G_RDPHALF_1, G_RDPHALF_2, G_RDPHALF_CONT;
@@ -192,6 +194,7 @@ void GBIInfo::_makeCurrent(MicrocodeInfo * _pCurrent)
case F3DGOLDEN: F3DGOLDEN_Init(); break;
case F3DEX2MM: F3DEX2MM_Init(); break;
case F3DTEXA: F3DTEXA_Init(); break;
+ case T3DUX: F3D_Init(); break;
}
if (gfxContext.isSupported(graphics::SpecialFeatures::NearPlaneClipping)) {
diff --git a/src/GBI.h b/src/GBI.h
index edc435ec..6fbe7e20 100644
--- a/src/GBI.h
+++ b/src/GBI.h
@@ -25,7 +25,8 @@
#define F3DSETA 16
#define F3DEX2MM 17
#define F3DTEXA 18
-#define NONE 19
+#define T3DUX 19
+#define NONE 20
// Fixed point conversion factors
#define FIXED2FLOATRECIP1 0.5f
diff --git a/src/RSP.cpp b/src/RSP.cpp
index 3550c2bb..06a5fca4 100644
--- a/src/RSP.cpp
+++ b/src/RSP.cpp
@@ -6,6 +6,7 @@
#include "N64.h"
#include "F3D.h"
#include "Turbo3D.h"
+#include "T3DUX.h"
#include "VI.h"
#include "Combiner.h"
#include "FrameBuffer.h"
@@ -70,9 +71,14 @@ void RSP_ProcessDList()
depthBufferList().setNotCleared();
- if (GBI.getMicrocodeType() == Turbo3D)
+ switch (GBI.getMicrocodeType()) {
+ case Turbo3D:
RunTurbo3D();
- else {
+ break;
+ case T3DUX:
+ RunT3DUX();
+ break;
+ default:
while (!RSP.halt) {
if ((RSP.PC[RSP.PCi] + 8) > RDRAMSize) {
#ifdef DEBUG
diff --git a/src/T3DUX.cpp b/src/T3DUX.cpp
new file mode 100644
index 00000000..941e0ba9
--- /dev/null
+++ b/src/T3DUX.cpp
@@ -0,0 +1,231 @@
+#include "T3DUX.h"
+#include "N64.h"
+#include "RSP.h"
+#include "RDP.h"
+#include "gSP.h"
+#include "gDP.h"
+#include "DisplayWindow.h"
+
+/******************T3DUX microcode*************************/
+
+struct T3DGlobState
+{
+ u16 pad0;
+ u16 perspNorm;
+ u32 flag;
+ u32 othermode0;
+ u32 othermode1;
+ u32 segBases[16];
+ /* the viewport to use */
+ s16 vsacle1;
+ s16 vsacle0;
+ s16 vsacle3;
+ s16 vsacle2;
+ s16 vtrans1;
+ s16 vtrans0;
+ s16 vtrans3;
+ s16 vtrans2;
+ u32 rdpCmds;
+};
+
+struct T3DState
+{
+ u32 renderState; /* render state */
+
+ u8 dmemVtxAddr;
+ u8 vtxCount; /* number of verts */
+ u8 texmode;
+ u8 geommode;
+
+ u8 dmemVtxAttribsAddr;
+ u8 attribsCount; /* number of colors and texture coords */
+ u8 matrixFlag;
+ u8 triCount; /* how many tris? */
+
+ u32 rdpCmds; /* ptr (segment address) to RDP DL */
+ u32 othermode0;
+ u32 othermode1;
+};
+
+
+struct T3DTriN
+{
+ u8 flag, v2, v1, v0; /* flag is which one for flat shade */
+ u8 pal, v2tex, v1tex, v0tex; /* indexes in texture coords list */
+};
+
+static u32 t32uxSetTileW0 = 0;
+static u32 t32uxSetTileW1 = 0;
+
+static
+void T3DUX_ProcessRDP(u32 _cmds)
+{
+ u32 addr = RSP_SegmentToPhysical(_cmds) >> 2;
+ if (addr != 0) {
+ RSP.bLLE = true;
+ u32 w0 = ((u32*)RDRAM)[addr++];
+ u32 w1 = ((u32*)RDRAM)[addr++];
+ RSP.cmd = _SHIFTR( w0, 24, 8 );
+ while (w0 + w1 != 0) {
+ GBI.cmd[RSP.cmd]( w0, w1 );
+ w0 = ((u32*)RDRAM)[addr++];
+ w1 = ((u32*)RDRAM)[addr++];
+ RSP.cmd = _SHIFTR( w0, 24, 8 );
+ switch (RSP.cmd) {
+ case G_TEXRECT:
+ case G_TEXRECTFLIP:
+ RDP.w2 = ((u32*)RDRAM)[addr++];
+ RDP.w3 = ((u32*)RDRAM)[addr++];
+ break;
+ case G_SETTILE:
+ t32uxSetTileW0 = w0;
+ t32uxSetTileW1 = w1;
+ break;
+ }
+ }
+ RSP.bLLE = false;
+ }
+}
+
+static
+void T3DUX_LoadGlobState(u32 pgstate)
+{
+ const u32 addr = RSP_SegmentToPhysical(pgstate);
+ T3DGlobState *gstate = (T3DGlobState*)&RDRAM[addr];
+ const u32 w0 = gstate->othermode0;
+ const u32 w1 = gstate->othermode1;
+ gDPSetOtherMode( _SHIFTR( w0, 0, 24 ), // mode0
+ w1 ); // mode1
+
+ for (int s = 0; s < 16; ++s)
+ gSPSegment(s, gstate->segBases[s] & 0x00FFFFFF);
+
+ gSPViewport(pgstate + 80);
+
+ T3DUX_ProcessRDP(gstate->rdpCmds);
+}
+
+static
+void T3DUX_LoadObject(u32 pstate, u32 pvtx, u32 ptri, u32 pcol)
+{
+ T3DState *ostate = (T3DState*)&RDRAM[RSP_SegmentToPhysical(pstate)];
+ // TODO: fix me
+ const u32 tile = 0;
+ gSP.texture.tile = tile;
+ gSP.textureTile[0] = &gDP.tiles[tile];
+ gSP.textureTile[1] = &gDP.tiles[(tile + 1) & 7];
+ gSP.texture.scales = 1.0f;
+ gSP.texture.scalet = 1.0f;
+
+ const u32 w0 = ostate->othermode0;
+ const u32 w1 = ostate->othermode1;
+ gDPSetOtherMode( _SHIFTR( w0, 0, 24 ), // mode0
+ w1 ); // mode1
+
+ if ((ostate->matrixFlag & 1) == 0) //load matrix
+ gSPForceMatrix(pstate + sizeof(T3DState));
+
+ gSPClearGeometryMode(G_LIGHTING | G_FOG);
+ gSPSetGeometryMode(ostate->renderState | G_SHADING_SMOOTH | G_SHADE | G_ZBUFFER | G_CULL_BACK);
+
+ if (pvtx != 0) //load vtx
+ gSPT3DUXVertex(pvtx, ostate->vtxCount, pcol);
+
+ T3DUX_ProcessRDP(ostate->rdpCmds);
+
+ if (ptri == 0)
+ return;
+
+ GraphicsDrawer & drawer = dwnd().getDrawer();
+ const u32 coladdr = RSP_SegmentToPhysical(pcol);
+ const T3DTriN * tri = (const T3DTriN*)&RDRAM[RSP_SegmentToPhysical(ptri)];
+ u8 pal = _SHIFTR(t32uxSetTileW1, 20, 4);
+ t32uxSetTileW1 &= 0xFF0FFFFF;
+ const bool flatShading = (ostate->geommode & 0x0F) == 0;
+ const bool texturing = ostate->texmode != 1;
+ f32 flatr, flatg, flatb, flata;
+
+ drawer.setDMAVerticesSize(ostate->triCount * 3);
+ SPVertex * pVtx = drawer.getDMAVerticesData();
+ for (int t = 0; t < ostate->triCount; ++t, ++tri) {
+ if (texturing && tri->pal != 0) {
+ const u32 w1 = t32uxSetTileW1 | (tri->pal << 20);
+ const u32 newPal = _SHIFTR(w1, 20, 4);
+ if (pal != newPal) {
+ drawer.drawDMATriangles(pVtx - drawer.getDMAVerticesData());
+ pVtx = drawer.getDMAVerticesData();
+ pal = newPal;
+ RDP_SetTile(t32uxSetTileW0, w1);
+ }
+ }
+
+ if (tri->v0 >= ostate->vtxCount || tri->v1 >= ostate->vtxCount || tri->v2 >= ostate->vtxCount)
+ continue;
+
+ if (drawer.isClipped(tri->v0, tri->v1, tri->v2))
+ continue;
+
+ if (flatShading) {
+ struct T3DUXColor
+ {
+ u8 a;
+ u8 b;
+ u8 g;
+ u8 r;
+ } color = *(T3DUXColor*)&RDRAM[coladdr + ((tri->flag << 2) & 0x03FC)];
+ flata = _FIXED2FLOAT(color.a, 8);
+ flatb = _FIXED2FLOAT(color.b, 8);
+ flatg = _FIXED2FLOAT(color.g, 8);
+ flatr = _FIXED2FLOAT(color.r, 8);
+ }
+
+ u32 vtxIdx[3] = { tri->v0, tri->v1, tri->v2 };
+ u32 texIdx[3] = { tri->v0tex, tri->v1tex, tri->v2tex };
+ for (u32 v = 0; v < 3; ++v) {
+ *pVtx = drawer.getVertex(vtxIdx[v]);
+
+ if (texturing) {
+ u32 texcoords = *(const u32*)&RDRAM[coladdr + (texIdx[v] << 2)];
+ pVtx->s = _FIXED2FLOAT(_SHIFTR(texcoords, 16, 16), 5);
+ pVtx->t = _FIXED2FLOAT(_SHIFTR(texcoords, 0, 16), 5);
+ } else {
+ pVtx->s = 0.0f;
+ pVtx->t = 0.0f;
+ }
+
+ if (flatShading) {
+ pVtx->r = flatr;
+ pVtx->g = flatg;
+ pVtx->b = flatb;
+ pVtx->a = flata;
+ }
+
+ ++pVtx;
+ }
+ }
+
+ drawer.drawDMATriangles(pVtx - drawer.getDMAVerticesData());
+}
+
+void RunT3DUX()
+{
+ u32 pstate;
+ do {
+ u32 addr = RSP.PC[RSP.PCi] >> 2;
+ const u32 pgstate = ((u32*)RDRAM)[addr++];
+ pstate = ((u32*)RDRAM)[addr++];
+ const u32 pvtx = ((u32*)RDRAM)[addr++];
+ const u32 ptri = ((u32*)RDRAM)[addr++];
+ const u32 pcol = ((u32*)RDRAM)[addr++];
+ //const u32 pstore = ((u32*)RDRAM)[addr];
+ if (pstate == 0) {
+ RSP.halt = 1;
+ break;
+ }
+ if (pgstate != 0)
+ T3DUX_LoadGlobState(pgstate);
+ T3DUX_LoadObject(pstate, pvtx, ptri, pcol);
+ // Go to the next instruction
+ RSP.PC[RSP.PCi] += 24;
+ } while (pstate != 0);
+}
diff --git a/src/T3DUX.h b/src/T3DUX.h
new file mode 100644
index 00000000..587fde42
--- /dev/null
+++ b/src/T3DUX.h
@@ -0,0 +1,6 @@
+#ifndef T3DUX_H
+#define T3DUX_H
+
+void RunT3DUX();
+
+#endif // T3DUX_H
diff --git a/src/gSP.cpp b/src/gSP.cpp
index 338720c7..0f60b69e 100644
--- a/src/gSP.cpp
+++ b/src/gSP.cpp
@@ -1241,6 +1241,68 @@ void gSPCBFDVertex( u32 a, u32 n, u32 v0 )
}
}
+void gSPT3DUXVertex(u32 a, u32 n, u32 ci)
+{
+ const u32 address = RSP_SegmentToPhysical(a);
+ const u32 colors = RSP_SegmentToPhysical(ci);
+
+ struct T3DUXVertex {
+ s16 y;
+ s16 x;
+ u16 flag;
+ s16 z;
+ } *vertex = (T3DUXVertex*)&RDRAM[address];
+
+ struct T3DUXColor
+ {
+ u8 a;
+ u8 b;
+ u8 g;
+ u8 r;
+ } *color = (T3DUXColor*)&RDRAM[colors];
+
+ if ((address + sizeof(T3DUXVertex)* n) > RDRAMSize)
+ return;
+
+ GraphicsDrawer & drawer = dwnd().getDrawer();
+ u32 i = 0;
+#ifdef __VEC4_OPT
+ for (; i < n - (n % 4); i += 4) {
+ u32 v = i;
+ for (int j = 0; j < 4; ++j) {
+ SPVertex & vtx = drawer.getVertex(v + j);
+ vtx.x = vertex->x;
+ vtx.y = vertex->y;
+ vtx.z = vertex->z;
+ vtx.s = 0;
+ vtx.t = 0;
+ vtx.r = _FIXED2FLOAT(color->r, 8);
+ vtx.g = _FIXED2FLOAT(color->g, 8);
+ vtx.b = _FIXED2FLOAT(color->b, 8);
+ vtx.a = _FIXED2FLOAT(color->a, 8);
+ vertex++;
+ color++;
+ }
+ gSPProcessVertex4(v);
+ }
+#endif
+ for (; i < n; ++i) {
+ SPVertex & vtx = drawer.getVertex(i);
+ vtx.x = vertex->x;
+ vtx.y = vertex->y;
+ vtx.z = vertex->z;
+ vtx.s = 0;
+ vtx.t = 0;
+ vtx.r = _FIXED2FLOAT(color->r, 8);
+ vtx.g = _FIXED2FLOAT(color->g, 8);
+ vtx.b = _FIXED2FLOAT(color->b, 8);
+ vtx.a = _FIXED2FLOAT(color->a, 8);
+ gSPProcessVertex(i);
+ vertex++;
+ color++;
+ }
+}
+
void gSPDisplayList( u32 dl )
{
u32 address = RSP_SegmentToPhysical( dl );
diff --git a/src/gSP.h b/src/gSP.h
index c531d81d..98232289 100644
--- a/src/gSP.h
+++ b/src/gSP.h
@@ -153,7 +153,8 @@ void gSPVertex( u32 v, u32 n, u32 v0 );
void gSPCIVertex( u32 v, u32 n, u32 v0 );
void gSPDMAVertex( u32 v, u32 n, u32 v0 );
void gSPCBFDVertex( u32 v, u32 n, u32 v0 );
-void gSPDisplayList( u32 dl );
+void gSPT3DUXVertex(u32 v, u32 n, u32 ci);
+void gSPDisplayList(u32 dl);
void gSPBranchList( u32 dl );
void gSPBranchLessZ( u32 branchdl, u32 vtx, u32 zval );
void gSPBranchLessW( u32 branchdl, u32 vtx, u32 wval );
diff --git a/src/mupen64plus-video-gliden64.mk b/src/mupen64plus-video-gliden64.mk
index 6ab06ec8..1852bf1c 100644
--- a/src/mupen64plus-video-gliden64.mk
+++ b/src/mupen64plus-video-gliden64.mk
@@ -60,6 +60,7 @@ MY_LOCAL_SRC_FILES := \
$(SRCDIR)/S2DEX2.cpp \
$(SRCDIR)/S2DEX.cpp \
$(SRCDIR)/SoftwareRender.cpp \
+ $(SRCDIR)/T3DUX.cpp \
$(SRCDIR)/TexrectDrawer.cpp \
$(SRCDIR)/TextDrawer.cpp \
$(SRCDIR)/TextureFilterHandler.cpp \