diff --git a/GPU/Software/Clipper.cpp b/GPU/Software/Clipper.cpp index 1ab91015e..eb181ce61 100644 --- a/GPU/Software/Clipper.cpp +++ b/GPU/Software/Clipper.cpp @@ -176,10 +176,10 @@ void ProcessRect(const VertexData& v0, const VertexData& v1) } // Four triangles to do backfaces as well. Two of them will get backface culled. - ProcessTriangle(*topleft, *topright, *bottomright); - ProcessTriangle(*bottomright, *topright, *topleft); - ProcessTriangle(*bottomright, *bottomleft, *topleft); - ProcessTriangle(*topleft, *bottomleft, *bottomright); + ProcessTriangle(*topleft, *topright, *bottomright, buf[3]); + ProcessTriangle(*bottomright, *topright, *topleft, buf[3]); + ProcessTriangle(*bottomright, *bottomleft, *topleft, buf[3]); + ProcessTriangle(*topleft, *bottomleft, *bottomright, buf[3]); } else { // through mode handling VertexData buf[4]; @@ -271,10 +271,17 @@ void ProcessLine(VertexData& v0, VertexData& v1) Rasterizer::DrawLine(data[0], data[1]); } -void ProcessTriangle(VertexData& v0, VertexData& v1, VertexData& v2) -{ +void ProcessTriangle(VertexData& v0, VertexData& v1, VertexData& v2, const VertexData &provoking) { if (gstate.isModeThrough()) { - Rasterizer::DrawTriangle(v0, v1, v2); + // In case of cull reordering, make sure the right color is on the final vertex. + if (gstate.getShadeMode() == GE_SHADE_FLAT) { + VertexData corrected2 = v2; + corrected2.color0 = provoking.color0; + corrected2.color1 = provoking.color1; + Rasterizer::DrawTriangle(v0, v1, corrected2); + } else { + Rasterizer::DrawTriangle(v0, v1, v2); + } return; } @@ -339,14 +346,19 @@ void ProcessTriangle(VertexData& v0, VertexData& v1, VertexData& v2) return; } - for (int i = 0; i+3 <= numIndices; i+=3) - { - if(indices[i] != SKIP_FLAG) - { + for (int i = 0; i + 3 <= numIndices; i += 3) { + if (indices[i] != SKIP_FLAG) { VertexData data[3] = { *Vertices[indices[i]], *Vertices[indices[i+1]], *Vertices[indices[i+2]] }; data[0].screenpos = TransformUnit::ClipToScreen(data[0].clippos); data[1].screenpos = TransformUnit::ClipToScreen(data[1].clippos); data[2].screenpos = TransformUnit::ClipToScreen(data[2].clippos); + + if (gstate.getShadeMode() == GE_SHADE_FLAT) { + // So that the order of clipping doesn't matter... + data[2].color0 = provoking.color0; + data[2].color1 = provoking.color1; + } + Rasterizer::DrawTriangle(data[0], data[1], data[2]); } } diff --git a/GPU/Software/Clipper.h b/GPU/Software/Clipper.h index e0926e624..d00262001 100644 --- a/GPU/Software/Clipper.h +++ b/GPU/Software/Clipper.h @@ -23,7 +23,7 @@ namespace Clipper { void ProcessPoint(VertexData& v0); void ProcessLine(VertexData& v0, VertexData& v1); -void ProcessTriangle(VertexData& v0, VertexData& v1, VertexData& v2); +void ProcessTriangle(VertexData& v0, VertexData& v1, VertexData& v2, const VertexData &provoking); void ProcessRect(const VertexData& v0, const VertexData& v1); } diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index e72e9a85c..f8081ec8d 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -342,12 +342,12 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, GEPrimitiveTy case GE_PRIM_TRIANGLES: { if (!gstate.isCullEnabled() || gstate.isModeClear()) { - Clipper::ProcessTriangle(data[0], data[1], data[2]); - Clipper::ProcessTriangle(data[2], data[1], data[0]); + Clipper::ProcessTriangle(data[0], data[1], data[2], data[2]); + Clipper::ProcessTriangle(data[2], data[1], data[0], data[2]); } else if (!gstate.getCullMode()) { - Clipper::ProcessTriangle(data[2], data[1], data[0]); + Clipper::ProcessTriangle(data[2], data[1], data[0], data[2]); } else { - Clipper::ProcessTriangle(data[0], data[1], data[2]); + Clipper::ProcessTriangle(data[0], data[1], data[2], data[2]); } break; } @@ -413,7 +413,8 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, GEPrimitiveTy vreader.Goto(vtx); } - data[(data_index++) % 3] = ReadVertex(vreader); + int provoking_index = (data_index++) % 3; + data[provoking_index] = ReadVertex(vreader); if (outside_range_flag) { // Drop all primitives containing the current vertex skip_count = 2; @@ -427,14 +428,14 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, GEPrimitiveTy } if (!gstate.isCullEnabled() || gstate.isModeClear()) { - Clipper::ProcessTriangle(data[0], data[1], data[2]); - Clipper::ProcessTriangle(data[2], data[1], data[0]); + Clipper::ProcessTriangle(data[0], data[1], data[2], data[provoking_index]); + Clipper::ProcessTriangle(data[2], data[1], data[0], data[provoking_index]); } else if ((!gstate.getCullMode()) ^ ((data_index - 1) % 2)) { // We need to reverse the vertex order for each second primitive, // but we additionally need to do that for every primitive if CCW cullmode is used. - Clipper::ProcessTriangle(data[2], data[1], data[0]); + Clipper::ProcessTriangle(data[2], data[1], data[0], data[provoking_index]); } else { - Clipper::ProcessTriangle(data[0], data[1], data[2]); + Clipper::ProcessTriangle(data[0], data[1], data[2], data[provoking_index]); } } break; @@ -466,7 +467,8 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, GEPrimitiveTy vreader.Goto(vtx); } - data[2 - ((data_index++) % 2)] = ReadVertex(vreader); + int provoking_index = 2 - ((data_index++) % 2); + data[provoking_index] = ReadVertex(vreader); if (outside_range_flag) { // Drop all primitives containing the current vertex skip_count = 2; @@ -480,14 +482,14 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, GEPrimitiveTy } if (!gstate.isCullEnabled() || gstate.isModeClear()) { - Clipper::ProcessTriangle(data[0], data[1], data[2]); - Clipper::ProcessTriangle(data[2], data[1], data[0]); + Clipper::ProcessTriangle(data[0], data[1], data[2], data[provoking_index]); + Clipper::ProcessTriangle(data[2], data[1], data[0], data[provoking_index]); } else if ((!gstate.getCullMode()) ^ ((data_index - 1) % 2)) { // We need to reverse the vertex order for each second primitive, // but we additionally need to do that for every primitive if CCW cullmode is used. - Clipper::ProcessTriangle(data[2], data[1], data[0]); + Clipper::ProcessTriangle(data[2], data[1], data[0], data[provoking_index]); } else { - Clipper::ProcessTriangle(data[0], data[1], data[2]); + Clipper::ProcessTriangle(data[0], data[1], data[2], data[provoking_index]); } } break;