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 \