diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index 93f46b11b5..dd295243c0 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -595,6 +595,13 @@ static bool AreCoordsRectangleCompatible(const RasterizerState &state, const Cli return true; } +// A rectangle drawn as triangles samples pixel centers, so its first column is (x + 7) >> 4; a sprite's +// is (x + 6) >> 4 (gpu/probe exp30). They differ only for a left edge at 9/16 into a pixel, where the +// triangles must stay triangles (NBA 2K13's menu boxes). Rows and the far edges agree. +bool RectangleCoverageMatchesTriangles(const VertexData &a, const VertexData &b) { + return (std::min(a.screenpos.x, b.screenpos.x) & (SCREEN_SCALE_FACTOR - 1)) != 9; +} + bool DetectRectangleFromStrip(const RasterizerState &state, const ClipVertexData data[4], int *tlIndex, int *brIndex) { if (!IsCoordRectangleCompatible(state, data[0])) return false; diff --git a/GPU/Software/RasterizerRectangle.h b/GPU/Software/RasterizerRectangle.h index 49f2e61c93..172c53ce0a 100644 --- a/GPU/Software/RasterizerRectangle.h +++ b/GPU/Software/RasterizerRectangle.h @@ -24,4 +24,5 @@ namespace Rasterizer { bool DetectRectangleFromFan(const RasterizerState &state, const ClipVertexData *data, int *tlIndex, int *brIndex); bool DetectRectangleFromPair(const RasterizerState &state, const ClipVertexData data[6], int *tlIndex, int *brIndex); bool DetectRectangleThroughModeSlices(const RasterizerState &state, const ClipVertexData data[4]); + bool RectangleCoverageMatchesTriangles(const VertexData &a, const VertexData &b); } diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index cab09aa424..1ae3731a8f 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -1025,7 +1025,7 @@ void TransformUnit::SubmitPrimitive(const void* vertices, const void* indices, G continue; int tl = -1, br = -1; - if (Rasterizer::DetectRectangleFromPair(binner_->State(), buf, &tl, &br)) { + if (Rasterizer::DetectRectangleFromPair(binner_->State(), buf, &tl, &br) && Rasterizer::RectangleCoverageMatchesTriangles(buf[tl].v, buf[br].v)) { Clipper::ProcessRect(buf[tl], buf[br], *binner_); } else { SendTriangle(cullType, &buf[0]); @@ -1159,7 +1159,7 @@ void TransformUnit::SubmitPrimitive(const void* vertices, const void* indices, G // If a strip is effectively a rectangle, draw it as such! int tl = -1, br = -1; - if (Rasterizer::DetectRectangleFromStrip(binner_->State(), data_, &tl, &br)) { + if (Rasterizer::DetectRectangleFromStrip(binner_->State(), data_, &tl, &br) && Rasterizer::RectangleCoverageMatchesTriangles(data_[tl].v, data_[br].v)) { Clipper::ProcessRect(data_[tl], data_[br], *binner_); start_vtx += 2; skip_count = 2; @@ -1228,7 +1228,7 @@ void TransformUnit::SubmitPrimitive(const void* vertices, const void* indices, G } int tl = -1, br = -1; - if (Rasterizer::DetectRectangleFromFan(binner_->State(), data_, &tl, &br)) { + if (Rasterizer::DetectRectangleFromFan(binner_->State(), data_, &tl, &br) && Rasterizer::RectangleCoverageMatchesTriangles(data_[tl].v, data_[br].v)) { Clipper::ProcessRect(data_[tl], data_[br], *binner_); break; }