From 8e348b87e939510439af3f506be1f29b5694cbf1 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Tue, 22 Dec 2020 13:31:34 -0800 Subject: [PATCH 1/2] Software: Fix line-width effects --- .../Core/VideoBackends/Software/Clipper.cpp | 64 +++++++++++-------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/Source/Core/VideoBackends/Software/Clipper.cpp b/Source/Core/VideoBackends/Software/Clipper.cpp index 67712fa9da..1378b57472 100644 --- a/Source/Core/VideoBackends/Software/Clipper.cpp +++ b/Source/Core/VideoBackends/Software/Clipper.cpp @@ -331,18 +331,36 @@ void ProcessTriangle(OutputVertexData* v0, OutputVertexData* v1, OutputVertexDat } } -static void CopyVertex(OutputVertexData* dst, const OutputVertexData* src, float dx, float dy, - unsigned int sOffset) +constexpr std::array LINE_PT_TEX_OFFSETS = { + 0, 1 / 16.f, 1 / 8.f, 1 / 4.f, 1 / 2.f, 1, 1, 1, +}; + +static void CopyLineVertex(OutputVertexData* dst, const OutputVertexData* src, int px, int py, + bool apply_line_offset) { - dst->screenPosition.x = src->screenPosition.x + dx; - dst->screenPosition.y = src->screenPosition.y + dy; + const float line_half_width = bpmem.lineptwidth.linesize / 12.0f; + + dst->projectedPosition = src->projectedPosition; + dst->screenPosition.x = src->screenPosition.x + px * line_half_width; + dst->screenPosition.y = src->screenPosition.y + py * line_half_width; dst->screenPosition.z = src->screenPosition.z; dst->normal = src->normal; dst->color = src->color; - // todo - s offset dst->texCoords = src->texCoords; + + if (apply_line_offset && LINE_PT_TEX_OFFSETS[bpmem.lineptwidth.lineoff] != 0) + { + for (u32 coord_num = 0; coord_num < xfmem.numTexGen.numTexGens; coord_num++) + { + if (bpmem.texcoords[coord_num].s.line_offset) + { + dst->texCoords[coord_num].x += (bpmem.texcoords[coord_num].s.scale_minus_1 + 1) * + LINE_PT_TEX_OFFSETS[bpmem.lineptwidth.lineoff]; + } + } + } } void ProcessLine(OutputVertexData* lineV0, OutputVertexData* lineV1) @@ -365,37 +383,33 @@ void ProcessLine(OutputVertexData* lineV0, OutputVertexData* lineV1) PerspectiveDivide(v0); PerspectiveDivide(v1); - float dx = v1->screenPosition.x - v0->screenPosition.x; - float dy = v1->screenPosition.y - v0->screenPosition.y; + const float dx = v1->screenPosition.x - v0->screenPosition.x; + const float dy = v1->screenPosition.y - v0->screenPosition.y; - float screenDx = 0; - float screenDy = 0; + int px = 0; + int py = 0; + // GameCube/Wii's line drawing algorithm is a little quirky. It does not + // use the correct line caps. Instead, the line caps are vertical or + // horizontal depending the slope of the line. + // FIXME: What does real hardware do when line is at a 45-degree angle? + + // Note that py or px are set positive or negative to ensure that the triangles are drawn ccw. if (fabsf(dx) > fabsf(dy)) - { - if (dx > 0) - screenDy = bpmem.lineptwidth.linesize / -12.0f; - else - screenDy = bpmem.lineptwidth.linesize / 12.0f; - } + py = (dx > 0) ? -1 : 1; else - { - if (dy > 0) - screenDx = bpmem.lineptwidth.linesize / 12.0f; - else - screenDx = bpmem.lineptwidth.linesize / -12.0f; - } + px = (dy > 0) ? 1 : -1; OutputVertexData triangle[3]; - CopyVertex(&triangle[0], v0, screenDx, screenDy, 0); - CopyVertex(&triangle[1], v1, screenDx, screenDy, 0); - CopyVertex(&triangle[2], v1, -screenDx, -screenDy, bpmem.lineptwidth.lineoff); + CopyLineVertex(&triangle[0], v0, px, py, false); + CopyLineVertex(&triangle[1], v1, px, py, false); + CopyLineVertex(&triangle[2], v1, -px, -py, true); // ccw winding Rasterizer::DrawTriangleFrontFace(&triangle[2], &triangle[1], &triangle[0]); - CopyVertex(&triangle[1], v0, -screenDx, -screenDy, bpmem.lineptwidth.lineoff); + CopyLineVertex(&triangle[1], v0, -px, -py, true); Rasterizer::DrawTriangleFrontFace(&triangle[0], &triangle[1], &triangle[2]); } From fcd3efa1ae92e0d3343a4fdb904b3400747a38c7 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Tue, 22 Dec 2020 15:00:40 -0800 Subject: [PATCH 2/2] Software: Implement points --- .../Core/VideoBackends/Software/Clipper.cpp | 47 +++++++++++++++++++ Source/Core/VideoBackends/Software/Clipper.h | 2 + .../Core/VideoBackends/Software/SetupUnit.cpp | 1 + 3 files changed, 50 insertions(+) diff --git a/Source/Core/VideoBackends/Software/Clipper.cpp b/Source/Core/VideoBackends/Software/Clipper.cpp index 1378b57472..4c4e0db52d 100644 --- a/Source/Core/VideoBackends/Software/Clipper.cpp +++ b/Source/Core/VideoBackends/Software/Clipper.cpp @@ -415,6 +415,53 @@ void ProcessLine(OutputVertexData* lineV0, OutputVertexData* lineV1) } } +static void CopyPointVertex(OutputVertexData* dst, const OutputVertexData* src, bool px, bool py) +{ + const float point_radius = bpmem.lineptwidth.pointsize / 12.0f; + + dst->projectedPosition = src->projectedPosition; + dst->screenPosition.x = src->screenPosition.x + (px ? 1 : -1) * point_radius; + dst->screenPosition.y = src->screenPosition.y + (py ? 1 : -1) * point_radius; + dst->screenPosition.z = src->screenPosition.z; + + dst->normal = src->normal; + dst->color = src->color; + + dst->texCoords = src->texCoords; + + const float point_offset = LINE_PT_TEX_OFFSETS[bpmem.lineptwidth.pointoff]; + if (point_offset != 0) + { + for (u32 coord_num = 0; coord_num < xfmem.numTexGen.numTexGens; coord_num++) + { + const auto coord_info = bpmem.texcoords[coord_num]; + if (coord_info.s.point_offset) + { + if (px) + dst->texCoords[coord_num].x += (coord_info.s.scale_minus_1 + 1) * point_offset; + if (py) + dst->texCoords[coord_num].y += (coord_info.t.scale_minus_1 + 1) * point_offset; + } + } + } +} + +void ProcessPoint(OutputVertexData* center) +{ + // TODO: This isn't actually doing any clipping + PerspectiveDivide(center); + + OutputVertexData ll, lr, ul, ur; + + CopyPointVertex(&ll, center, false, false); + CopyPointVertex(&lr, center, true, false); + CopyPointVertex(&ur, center, true, true); + CopyPointVertex(&ul, center, false, true); + + Rasterizer::DrawTriangleFrontFace(&ll, &ul, &lr); + Rasterizer::DrawTriangleFrontFace(&ur, &lr, &ul); +} + bool CullTest(const OutputVertexData* v0, const OutputVertexData* v1, const OutputVertexData* v2, bool& backface) { diff --git a/Source/Core/VideoBackends/Software/Clipper.h b/Source/Core/VideoBackends/Software/Clipper.h index d19bbedf7b..ea7bf1e4eb 100644 --- a/Source/Core/VideoBackends/Software/Clipper.h +++ b/Source/Core/VideoBackends/Software/Clipper.h @@ -14,6 +14,8 @@ void ProcessTriangle(OutputVertexData* v0, OutputVertexData* v1, OutputVertexDat void ProcessLine(OutputVertexData* v0, OutputVertexData* v1); +void ProcessPoint(OutputVertexData* v); + bool CullTest(const OutputVertexData* v0, const OutputVertexData* v1, const OutputVertexData* v2, bool& backface); diff --git a/Source/Core/VideoBackends/Software/SetupUnit.cpp b/Source/Core/VideoBackends/Software/SetupUnit.cpp index 3cdbbee614..0d4d7446ab 100644 --- a/Source/Core/VideoBackends/Software/SetupUnit.cpp +++ b/Source/Core/VideoBackends/Software/SetupUnit.cpp @@ -167,4 +167,5 @@ void SetupUnit::SetupLineStrip() void SetupUnit::SetupPoint() { + Clipper::ProcessPoint(m_VertPointer[0]); }