diff --git a/CHANGES b/CHANGES index 4f546f22f..1cd6cb461 100644 --- a/CHANGES +++ b/CHANGES @@ -3,6 +3,7 @@ Features: - DS GX: Toon shading Bugfixes: - DS GX: Fix vertex texture transformation (fixes mgba.io/i/702) + - DS GX: Automatically normalize winding culling calculations (fixes mgba.io/i/699) Misc: - DS GX: Clean up and unify texture mapping diff --git a/include/mgba-util/math.h b/include/mgba-util/math.h index 3c27bba69..f308b4255 100644 --- a/include/mgba-util/math.h +++ b/include/mgba-util/math.h @@ -53,6 +53,51 @@ static inline unsigned clz32(uint32_t bits) { #endif } +static inline unsigned clz64(uint64_t bits) { +#if defined(__GNUC__) || __clang__ + if (!bits) { + return 64; + } + return __builtin_clzll(bits); +#else + static const int table[256] = { + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + if (bits & 0xFF00000000000000) { + return table[bits >> 56]; + } else if (bits & 0x00FF000000000000) { + return table[bits >> 48] + 8; + } else if (bits & 0x0000FF0000000000) { + return table[bits >> 40] + 16; + } else if (bits & 0x000000FF00000000) { + return table[bits >> 32] + 24; + } else if (bits & 0x00000000FF000000) { + return table[bits >> 24] + 32; + } else if (bits & 0x0000000000FF0000) { + return table[bits >> 16] + 40; + } else if (bits & 0x000000000000FF00) { + return table[bits >> 8] + 48; + } + return table[bits] + 56; +#endif +} + static inline uint32_t toPow2(uint32_t bits) { if (!bits) { return 0; diff --git a/src/ds/gx.c b/src/ds/gx.c index 8e6940d2a..08060f686 100644 --- a/src/ds/gx.c +++ b/src/ds/gx.c @@ -7,6 +7,7 @@ #include #include +#include mLOG_DEFINE_CATEGORY(DS_GX, "DS GX", "ds.gx"); @@ -237,6 +238,7 @@ static bool _clipPolygon(struct DSGX* gx, struct DSGXPolygon* poly) { int64_t ny = 0; int64_t nz = 0; int64_t dot = 0; + int rank = 30; for (v = 0; v < poly->verts; ++v) { struct DSGXVertex* v0 = &gx->pendingVertices[poly->vertIds[v]]; struct DSGXVertex* v1; @@ -251,9 +253,28 @@ static bool _clipPolygon(struct DSGX* gx, struct DSGXPolygon* poly) { v1 = &gx->pendingVertices[poly->vertIds[v + 1 - poly->verts]]; v2 = &gx->pendingVertices[poly->vertIds[v + 2 - poly->verts]]; } - nx = ((int64_t) v0->viewCoord[1] * v2->viewCoord[3] - (int64_t) v0->viewCoord[3] * v2->viewCoord[1]) >> 24; - ny = ((int64_t) v0->viewCoord[3] * v2->viewCoord[0] - (int64_t) v0->viewCoord[0] * v2->viewCoord[3]) >> 24; - nz = ((int64_t) v0->viewCoord[0] * v2->viewCoord[1] - (int64_t) v0->viewCoord[1] * v2->viewCoord[0]) >> 24; + nx = ((int64_t) v0->viewCoord[1] * v2->viewCoord[3] - (int64_t) v0->viewCoord[3] * v2->viewCoord[1]); + ny = ((int64_t) v0->viewCoord[3] * v2->viewCoord[0] - (int64_t) v0->viewCoord[0] * v2->viewCoord[3]); + nz = ((int64_t) v0->viewCoord[0] * v2->viewCoord[1] - (int64_t) v0->viewCoord[1] * v2->viewCoord[0]); + int rx = 64 - clz64(nx >= 0 ? nx : -nx); + int ry = 64 - clz64(ny >= 0 ? ny : -ny); + int rz = 64 - clz64(nz >= 0 ? nz : -nz); + if (ry > rx) { + rx = ry; + } + if (rz > rx) { + rx = rz; + } + if (rx > 30) { + nx >>= rx - 30; + ny >>= rx - 30; + nz >>= rx - 30; + } + if (rx > rank) { + dot >>= rx - rank; + rank = rx; + } + dot += nx * v1->viewCoord[0] + ny * v1->viewCoord[1] + nz * v1->viewCoord[3]; } if (!DSGXPolygonAttrsIsBackFace(poly->polyParams) && dot < 0) {