diff --git a/CHANGES b/CHANGES index e75b7a6cd..e547ab843 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,7 @@ medusa alpha 3 (Future) Features: - DS GX: Toon shading - DS GX: Clear depth + - DS GX: Position test Bugfixes: - DS GX: Fix vertex texture transformation (fixes mgba.io/i/702) - DS GX: Automatically normalize winding culling calculations (fixes mgba.io/i/699) diff --git a/src/ds/gx.c b/src/ds/gx.c index 3e664e8f2..5ffe3b8ca 100644 --- a/src/ds/gx.c +++ b/src/ds/gx.c @@ -485,10 +485,7 @@ static int16_t _dot3(int32_t x0, int32_t y0, int32_t z0, int32_t x1, int32_t y1, return a; } -static void _emitVertex(struct DSGX* gx, uint16_t x, uint16_t y, uint16_t z) { - if (gx->vertexMode < 0 || gx->vertexIndex == DS_GX_VERTEX_BUFFER_SIZE || gx->polygonIndex == DS_GX_POLYGON_BUFFER_SIZE) { - return; - } +static void _posTest(struct DSGX* gx, int16_t x, int16_t y, int16_t z) { gx->currentVertex.coord[0] = x; gx->currentVertex.coord[1] = y; gx->currentVertex.coord[2] = z; @@ -496,6 +493,13 @@ static void _emitVertex(struct DSGX* gx, uint16_t x, uint16_t y, uint16_t z) { gx->currentVertex.viewCoord[1] = _dotViewport(&gx->currentVertex, &gx->clipMatrix.m[1]); gx->currentVertex.viewCoord[2] = _dotViewport(&gx->currentVertex, &gx->clipMatrix.m[2]); gx->currentVertex.viewCoord[3] = _dotViewport(&gx->currentVertex, &gx->clipMatrix.m[3]); +} + +static void _emitVertex(struct DSGX* gx, uint16_t x, uint16_t y, uint16_t z) { + if (gx->vertexMode < 0 || gx->vertexIndex == DS_GX_VERTEX_BUFFER_SIZE || gx->polygonIndex == DS_GX_POLYGON_BUFFER_SIZE) { + return; + } + _posTest(gx, x, y, z); if (DSGXTexParamsGetCoordTfMode(gx->currentPoly.texParams) == 0) { gx->currentVertex.vs = gx->currentVertex.st[0]; @@ -1244,6 +1248,25 @@ static void _fifoRun(struct mTiming* timing, void* context, uint32_t cyclesLate) gxstat = DSRegGXSTATClearTestBusy(gxstat); gxstat = DSRegGXSTATTestFillBoxTestResult(gxstat, _boxTest(gx)); break; + case DS_GX_CMD_POS_TEST: { + int16_t x = gx->activeEntries[0].params[0]; + x |= gx->activeEntries[0].params[1] << 8; + int16_t y = gx->activeEntries[0].params[2]; + y |= gx->activeEntries[0].params[3] << 8; + int16_t z = gx->activeEntries[1].params[0]; + z |= gx->activeEntries[1].params[1] << 8; + _posTest(gx, x, y, z); + gx->p->memory.io9[DS9_REG_POS_RESULT_0 >> 1] = gx->currentVertex.viewCoord[0] & 0xFFFF; + gx->p->memory.io9[DS9_REG_POS_RESULT_1 >> 1] = gx->currentVertex.viewCoord[0] >> 16; + gx->p->memory.io9[DS9_REG_POS_RESULT_2 >> 1] = gx->currentVertex.viewCoord[1] & 0xFFFF; + gx->p->memory.io9[DS9_REG_POS_RESULT_3 >> 1] = gx->currentVertex.viewCoord[1] >> 16; + gx->p->memory.io9[DS9_REG_POS_RESULT_4 >> 1] = gx->currentVertex.viewCoord[2] & 0xFFFF; + gx->p->memory.io9[DS9_REG_POS_RESULT_5 >> 1] = gx->currentVertex.viewCoord[2] >> 16; + gx->p->memory.io9[DS9_REG_POS_RESULT_6 >> 1] = gx->currentVertex.viewCoord[3] & 0xFFFF; + gx->p->memory.io9[DS9_REG_POS_RESULT_7 >> 1] = gx->currentVertex.viewCoord[3] >> 16; + gxstat = DSRegGXSTATClearTestBusy(gxstat); + break; + } default: mLOG(DS_GX, STUB, "Unimplemented GX command %02X:%02X %02X %02X %02X", entry.command, entry.params[0], entry.params[1], entry.params[2], entry.params[3]); break; @@ -1469,6 +1492,10 @@ static void DSGXWriteFIFO(struct DSGX* gx, struct DSGXEntry entry) { gxstat = DSRegGXSTATFillTestBusy(gxstat); gxstat = DSRegGXSTATClearBoxTestResult(gxstat); gx->p->memory.io9[DS9_REG_GXSTAT_LO >> 1] = gxstat; + } else if (entry.command == DS_GX_CMD_POS_TEST) { + DSRegGXSTAT gxstat = gx->p->memory.io9[DS9_REG_GXSTAT_LO >> 1]; + gxstat = DSRegGXSTATFillTestBusy(gxstat); + gx->p->memory.io9[DS9_REG_GXSTAT_LO >> 1] = gxstat; } if (!gx->swapBuffers && !mTimingIsScheduled(&gx->p->ds9.timing, &gx->fifoEvent)) { mTimingSchedule(&gx->p->ds9.timing, &gx->fifoEvent, cycles); diff --git a/src/ds/io.c b/src/ds/io.c index 69439423e..fba77d441 100644 --- a/src/ds/io.c +++ b/src/ds/io.c @@ -856,6 +856,14 @@ uint16_t DS9IORead(struct DS* ds, uint32_t address) { case DS9_REG_TOON_TABLE_1F: case DS9_REG_GXSTAT_LO: case DS9_REG_GXSTAT_HI: + case DS9_REG_POS_RESULT_0: + case DS9_REG_POS_RESULT_1: + case DS9_REG_POS_RESULT_2: + case DS9_REG_POS_RESULT_3: + case DS9_REG_POS_RESULT_4: + case DS9_REG_POS_RESULT_5: + case DS9_REG_POS_RESULT_6: + case DS9_REG_POS_RESULT_7: case DS9_REG_CLIPMTX_RESULT_00: case DS9_REG_CLIPMTX_RESULT_01: case DS9_REG_CLIPMTX_RESULT_02: