From 1931fa2f5fea2dc1158f6a9f8d948a73599c79ac Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 16 Oct 2022 16:01:09 -0700 Subject: [PATCH] softgpu: Make triangle fan rect detection generic. --- GPU/Software/RasterizerRectangle.cpp | 63 ++++++++++++++++------------ GPU/Software/RasterizerRectangle.h | 2 +- GPU/Software/TransformUnit.cpp | 2 +- 3 files changed, 39 insertions(+), 28 deletions(-) diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index 5cc40566d617..8d39a2426ab4 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -483,40 +483,51 @@ bool DetectRectangleFromStrip(const RasterizerState &state, const ClipVertexData return false; } -bool DetectRectangleFromFan(const RasterizerState &state, const ClipVertexData *data, int c, int *tlIndex, int *brIndex) { +bool DetectRectangleFromFan(const RasterizerState &state, const ClipVertexData *data, int *tlIndex, int *brIndex) { // Color and Z must be flat. - for (int i = 1; i < c; ++i) { + int tl = 0, br = 0; + for (int i = 1; i < 4; ++i) { if (!AreCoordsRectangleCompatible(state, data[i], data[0])) return false; + + if (data[i].v.screenpos.x <= data[tl].v.screenpos.x && data[i].v.screenpos.y <= data[tl].v.screenpos.y) + tl = i; + if (data[i].v.screenpos.x >= data[br].v.screenpos.x && data[i].v.screenpos.y >= data[br].v.screenpos.y) + br = i; } - // Check for the common case: a single TL-TR-BR-BL. - if (c == 4) { - const auto &pos0 = data[0].v.screenpos, &pos1 = data[1].v.screenpos; - const auto &pos2 = data[2].v.screenpos, &pos3 = data[3].v.screenpos; - if (pos0.x == pos3.x && pos1.x == pos2.x && pos0.y == pos1.y && pos3.y == pos2.y) { - // Looking like yes. Set TL/BR based on y order first... - *tlIndex = pos0.y > pos3.y ? 2 : 0; - *brIndex = pos0.y > pos3.y ? 0 : 2; - // And if it's horizontally flipped, trade to the actual TL/BR. - if (pos0.x > pos1.x) { - *tlIndex ^= 1; - *brIndex ^= 1; - } + *tlIndex = tl; + *brIndex = br; - // Do we need to think about rotation? - if (!state.enableTextures) - return true; + int tr = 1, bl = 1; + for (int i = 0; i < 4; ++i) { + if (i == tl || i == br) + continue; - const auto &textl = data[*tlIndex].v.texturecoords, &textr = data[*tlIndex ^ 1].v.texturecoords; - const auto &texbl = data[*brIndex ^ 1].v.texturecoords, &texbr = data[*brIndex].v.texturecoords; + if (data[i].v.screenpos.x <= data[tl].v.screenpos.x && data[i].v.screenpos.y >= data[tl].v.screenpos.y) + bl = i; + if (data[i].v.screenpos.x >= data[br].v.screenpos.x && data[i].v.screenpos.y <= data[br].v.screenpos.y) + tr = i; + } - if (textl.x == texbl.x && textr.x == texbr.x && textl.y == textr.y && texbl.y == texbr.y) { - // Okay, the texture is also good, but let's avoid rotation issues. - const auto &postl = data[*tlIndex].v.screenpos; - const auto &posbr = data[*brIndex].v.screenpos; - return textl.y < texbr.y && postl.y < posbr.y && textl.x < texbr.x && postl.x < posbr.x; - } + // Must have found each of the coordinates. + if (tl + tr + bl + br != 6) + return false; + + // Note the common case is a single TL-TR-BR-BL. + const auto &postl = data[tl].v.screenpos, &postr = data[tr].v.screenpos; + const auto &posbr = data[br].v.screenpos, &posbl = data[bl].v.screenpos; + if (postl.x == posbl.x && postr.x == posbr.x && postl.y == postr.y && posbl.y == posbr.y) { + // Do we need to think about rotation? + if (!state.enableTextures) + return true; + + const auto &textl = data[tl].v.texturecoords, &textr = data[tr].v.texturecoords; + const auto &texbl = data[bl].v.texturecoords, &texbr = data[br].v.texturecoords; + + if (textl.x == texbl.x && textr.x == texbr.x && textl.y == textr.y && texbl.y == texbr.y) { + // Okay, the texture is also good, but let's avoid rotation issues. + return textl.y < texbr.y && postl.y < posbr.y && textl.x < texbr.x && postl.x < posbr.x; } } diff --git a/GPU/Software/RasterizerRectangle.h b/GPU/Software/RasterizerRectangle.h index 19e4b42b4871..49f2e61c9311 100644 --- a/GPU/Software/RasterizerRectangle.h +++ b/GPU/Software/RasterizerRectangle.h @@ -21,7 +21,7 @@ namespace Rasterizer { void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &range, const RasterizerState &state); bool DetectRectangleFromStrip(const RasterizerState &state, const ClipVertexData data[4], int *tlIndex, int *brIndex); - bool DetectRectangleFromFan(const RasterizerState &state, const ClipVertexData *data, int c, int *tlIndex, int *brIndex); + 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]); } diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index 7d1d28d07d94..fbbdcd391938 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -793,7 +793,7 @@ void TransformUnit::SubmitPrimitive(const void* vertices, const void* indices, G } int tl = -1, br = -1; - if (Rasterizer::DetectRectangleFromFan(binner_->State(), data_, vertex_count, &tl, &br)) { + if (Rasterizer::DetectRectangleFromFan(binner_->State(), data_, &tl, &br)) { Clipper::ProcessRect(data_[tl], data_[br], *binner_); break; }