File melonds_PR2060.patch of Package melonds

From 920cc6bb9161429bec5c0c1498fdd674dd60cf4d Mon Sep 17 00:00:00 2001
From: Jaklyy <102590697+Jaklyy@users.noreply.github.com>
Date: Sat, 18 May 2024 14:51:31 -0400
Subject: [PATCH 1/5] implement handling for glitched polygon edge cases

---
 src/GPU3D.cpp      | 46 +++++++++++++++++++++++++++++++++++----
 src/GPU3D.h        | 15 ++++++++++++-
 src/GPU3D_Soft.cpp | 54 +++++++++++++++++++++++++++++++---------------
 src/GPU3D_Soft.h   | 14 +++++-------
 4 files changed, 98 insertions(+), 31 deletions(-)

diff --git a/src/GPU3D.cpp b/src/GPU3D.cpp
index 44561dfa8e..4746a7fa79 100644
--- a/src/GPU3D.cpp
+++ b/src/GPU3D.cpp
@@ -449,6 +449,8 @@ void GPU3D::DoSavestate(Savestate* file) noexcept
 
         file->Var32(&poly->NumVertices);
 
+        file->VarArray(poly->SlopePosition, sizeof(s32)*10*2);
+
         file->VarArray(poly->FinalZ, sizeof(s32)*10);
         file->VarArray(poly->FinalW, sizeof(s32)*10);
         file->Bool32(&poly->WBuffer);
@@ -487,7 +489,7 @@ void GPU3D::DoSavestate(Savestate* file) noexcept
                     poly->Degenerate = true;
             }
 
-            if (poly->YBottom > 192) poly->Degenerate = true;
+            if (poly->YBottom > 192 && !poly->Translucent) poly->Degenerate = true;
         }
     }
 
@@ -1098,8 +1100,10 @@ void GPU3D::SubmitPolygon() noexcept
     }
 
     // compute screen coordinates
-
-    for (int i = clipstart; i < nverts; i++)
+    // hardware does this pass for shared vertices in polygon strips, even though it was already done for them last polygon
+    // however it doesn't recalculate all of the previous polygon's internal info (used for determining how to rasterize it)
+    // despite potentially changing their coordinates if a viewport change occured mid-strip...
+    for (int i = (UpdateLastPoly ? 0 : clipstart); i < nverts; i++)
     {
         Vertex* vtx = &clippedvertices[i];
 
@@ -1245,6 +1249,31 @@ void GPU3D::SubmitPolygon() noexcept
             NumVertices += 2;
         }
 
+        // if a viewport command was submitted mid-polygon strip the "true" coords and sort order of a vertex in the last polygon can be changed retroactively
+        if (UpdateLastPoly)
+        {
+            // update final coords and sortkey to match new vertex coordinates
+            // yes, *only* those values... this causes the polygon to be rasterized in an extremely glitchy manner
+            poly->Vertices[0]->FinalPosition[0] = clippedvertices[0].FinalPosition[0];
+            poly->Vertices[0]->FinalPosition[1] = clippedvertices[0].FinalPosition[1];
+            poly->Vertices[1]->FinalPosition[0] = clippedvertices[1].FinalPosition[0];
+            poly->Vertices[1]->FinalPosition[1] = clippedvertices[1].FinalPosition[1];
+            
+            s32 ytop = 192, ybot = 0;
+            Vertex** lastpolyvtx = LastStripPolygon->Vertices;
+            for (int i = 0; i < LastStripPolygon->NumVertices; i++)
+            {                
+                if (lastpolyvtx[i]->FinalPosition[1] < ytop)
+                    ytop = lastpolyvtx[i]->FinalPosition[1];
+                if (lastpolyvtx[i]->FinalPosition[1] > ybot)
+                    ybot = lastpolyvtx[i]->FinalPosition[1];
+            }
+            LastStripPolygon->SortKey = (ybot << 8) | ytop;
+            if (LastStripPolygon->Translucent) LastStripPolygon->SortKey |= 0x10000;
+
+            // clear update flag
+            UpdateLastPoly = false;
+        }
         poly->NumVertices += 2;
     }
 
@@ -1266,6 +1295,7 @@ void GPU3D::SubmitPolygon() noexcept
     }
 
     // determine bounds of the polygon
+    // including where slopes begin and end
     // also determine the W shift and normalize W
     // normalization works both ways
     // (ie two W's that span 12 bits or less will be brought to 16 bits)
@@ -1292,6 +1322,10 @@ void GPU3D::SubmitPolygon() noexcept
             vbot = i;
         }
 
+        // these values are used to determine where to begin/end slopes
+        poly->SlopePosition[i][0] = vtx->FinalPosition[0];
+        poly->SlopePosition[i][1] = vtx->FinalPosition[1];
+
         u32 w = (u32)vtx->Position[3];
         if (w == 0) poly->Degenerate = true;
 
@@ -1303,7 +1337,7 @@ void GPU3D::SubmitPolygon() noexcept
     poly->YTop = ytop; poly->YBottom = ybot;
     poly->XTop = xtop; poly->XBottom = xbot;
 
-    if (ybot > 192) poly->Degenerate = true;
+    if (ybot > 192 && !poly->Translucent) poly->Degenerate = true;
 
     poly->SortKey = (ybot << 8) | ytop;
     if (poly->Translucent) poly->SortKey |= 0x10000;
@@ -2039,6 +2073,7 @@ void GPU3D::ExecuteCommand() noexcept
             VertexNumInPoly = 0;
             NumConsecutivePolygons = 0;
             LastStripPolygon = NULL;
+            UpdateLastPoly = false;
             CurPolygonAttr = PolygonAttr;
             break;
 
@@ -2073,6 +2108,9 @@ void GPU3D::ExecuteCommand() noexcept
             Viewport[3] = (191 - (entry.Param >> 24)) & 0xFF;             // y1
             Viewport[4] = (Viewport[2] - Viewport[0] + 1) & 0x1FF;          // width
             Viewport[5] = (Viewport[1] - Viewport[3] + 1) & 0xFF;           // height
+
+            // set a flag that tells the next polygon to emulate a bug with polygon strips
+            if (LastStripPolygon) UpdateLastPoly = true;
             break;
 
         case 0x72: // vec test
diff --git a/src/GPU3D.h b/src/GPU3D.h
index f5446f345d..f5705c1ffd 100644
--- a/src/GPU3D.h
+++ b/src/GPU3D.h
@@ -39,8 +39,13 @@ struct Vertex
 
     // final vertex attributes.
     // allows them to be reused in polygon strips.
-
+    
+    // with sw renderer FinalPosition is primarily used for calculating the slope of a polygon (not where it begins/ends)
+    // (it does get used to determine where slopes should start and end with the gl renderers)
+    // the initial set of coordinates gets updated by the next polygon in a strip
+    // which can cause rendering issues if they wind up different than their initial value (due to a viewport change)
     s32 FinalPosition[2];
+
     s32 FinalColor[3];
 
     // hi-res position (4-bit fractional part)
@@ -55,6 +60,13 @@ struct Polygon
     Vertex* Vertices[10];
     u32 NumVertices;
 
+    // essentially a per-polygon copy of its vertices' coordinates
+    // (not 100% sure why they do it like this? but a glitch requires this for proper behavior, so we gotta do it too)
+    // unlike each vertices' final position variable, it is *not* updated by the next polygon in a polygon strip
+    // it is used by the software renderer to determine where to begin/end each slope
+    // TODO: track hires versions of this for the hardware renderers to use?
+    s32 SlopePosition[10][2];
+
     s32 FinalZ[10];
     s32 FinalW[10];
     bool WBuffer;
@@ -272,6 +284,7 @@ class GPU3D
     u32 RenderClearAttr2 = 0;
 
     bool RenderFrameIdentical = false; // not part of the hardware state, don't serialize
+    bool UpdateLastPoly = false; // used to track whether the next polygon should update the previous one's vtx coordinates (as a small optimization)
 
     bool AbortFrame = false;
 
diff --git a/src/GPU3D_Soft.cpp b/src/GPU3D_Soft.cpp
index a8da14cda6..3203e10ab0 100644
--- a/src/GPU3D_Soft.cpp
+++ b/src/GPU3D_Soft.cpp
@@ -595,7 +595,7 @@ void SoftRenderer::SetupPolygonLeftEdge(SoftRenderer::RendererPolygon* rp, s32 y
 {
     Polygon* polygon = rp->PolyData;
 
-    while (y >= polygon->Vertices[rp->NextVL]->FinalPosition[1] && rp->CurVL != polygon->VBottom)
+    while ((y >= polygon->SlopePosition[rp->NextVL][1]) && rp->CurVL != polygon->VBottom)
     {
         rp->CurVL = rp->NextVL;
 
@@ -613,8 +613,18 @@ void SoftRenderer::SetupPolygonLeftEdge(SoftRenderer::RendererPolygon* rp, s32 y
         }
     }
 
+    // note: if the end or current position in a slope is above the start point
+    // it seems to seek forwards(?) until the value overflows at 256
+    // this can be emulated by just adding 256 to them
+    if (y < polygon->Vertices[rp->CurVL]->FinalPosition[1])
+        y += 256;
+
+    s32 y1 = polygon->Vertices[rp->NextVL]->FinalPosition[1];
+    if (y1 < polygon->Vertices[rp->CurVL]->FinalPosition[1])
+        y1 += 256;
+
     rp->XL = rp->SlopeL.Setup(polygon->Vertices[rp->CurVL]->FinalPosition[0], polygon->Vertices[rp->NextVL]->FinalPosition[0],
-                              polygon->Vertices[rp->CurVL]->FinalPosition[1], polygon->Vertices[rp->NextVL]->FinalPosition[1],
+                              polygon->Vertices[rp->CurVL]->FinalPosition[1], y1,
                               polygon->FinalW[rp->CurVL], polygon->FinalW[rp->NextVL], y);
 }
 
@@ -622,7 +632,7 @@ void SoftRenderer::SetupPolygonRightEdge(SoftRenderer::RendererPolygon* rp, s32
 {
     Polygon* polygon = rp->PolyData;
 
-    while (y >= polygon->Vertices[rp->NextVR]->FinalPosition[1] && rp->CurVR != polygon->VBottom)
+    while ((y >= polygon->SlopePosition[rp->NextVR][1]) && rp->CurVR != polygon->VBottom)
     {
         rp->CurVR = rp->NextVR;
 
@@ -640,8 +650,18 @@ void SoftRenderer::SetupPolygonRightEdge(SoftRenderer::RendererPolygon* rp, s32
         }
     }
 
+    // note: if the end or current position in a slope is above the start point
+    // it seems to seek forwards(?) until the value overflows at 256
+    // this can be emulated by just adding 256 to them
+    if (y < polygon->Vertices[rp->CurVR]->FinalPosition[1])
+        y += 256;
+
+    s32 y1 = polygon->Vertices[rp->NextVR]->FinalPosition[1];
+    if (y1 < polygon->Vertices[rp->CurVR]->FinalPosition[1])
+        y1 += 256;
+
     rp->XR = rp->SlopeR.Setup(polygon->Vertices[rp->CurVR]->FinalPosition[0], polygon->Vertices[rp->NextVR]->FinalPosition[0],
-                              polygon->Vertices[rp->CurVR]->FinalPosition[1], polygon->Vertices[rp->NextVR]->FinalPosition[1],
+                              polygon->Vertices[rp->CurVR]->FinalPosition[1], y1,
                               polygon->FinalW[rp->CurVR], polygon->FinalW[rp->NextVR], y);
 }
 
@@ -678,18 +698,18 @@ void SoftRenderer::SetupPolygon(SoftRenderer::RendererPolygon* rp, Polygon* poly
         int i;
 
         i = 1;
-        if (polygon->Vertices[i]->FinalPosition[0] < polygon->Vertices[vtop]->FinalPosition[0]) vtop = i;
-        if (polygon->Vertices[i]->FinalPosition[0] > polygon->Vertices[vbot]->FinalPosition[0]) vbot = i;
+        if (polygon->SlopePosition[i][0] < polygon->SlopePosition[vtop][0]) vtop = i;
+        if (polygon->SlopePosition[i][0] > polygon->SlopePosition[vbot][0]) vbot = i;
 
         i = nverts - 1;
-        if (polygon->Vertices[i]->FinalPosition[0] < polygon->Vertices[vtop]->FinalPosition[0]) vtop = i;
-        if (polygon->Vertices[i]->FinalPosition[0] > polygon->Vertices[vbot]->FinalPosition[0]) vbot = i;
+        if (polygon->SlopePosition[i][0] < polygon->SlopePosition[vtop][0]) vtop = i;
+        if (polygon->SlopePosition[i][0] > polygon->SlopePosition[vbot][0]) vbot = i;
 
         rp->CurVL = vtop; rp->NextVL = vtop;
         rp->CurVR = vbot; rp->NextVR = vbot;
 
-        rp->XL = rp->SlopeL.SetupDummy(polygon->Vertices[rp->CurVL]->FinalPosition[0]);
-        rp->XR = rp->SlopeR.SetupDummy(polygon->Vertices[rp->CurVR]->FinalPosition[0]);
+        rp->XL = rp->SlopeL.SetupDummy(polygon->SlopePosition[rp->CurVL][0]);
+        rp->XR = rp->SlopeR.SetupDummy(polygon->SlopePosition[rp->CurVR][0]);
     }
     else
     {
@@ -723,12 +743,12 @@ void SoftRenderer::RenderShadowMaskScanline(const GPU3D& gpu3d, RendererPolygon*
 
     if (polygon->YTop != polygon->YBottom)
     {
-        if (y >= polygon->Vertices[rp->NextVL]->FinalPosition[1] && rp->CurVL != polygon->VBottom)
+        if ((y >= polygon->SlopePosition[rp->NextVL][1] || y == polygon->Vertices[rp->CurVL]->FinalPosition[1]) && rp->CurVL != polygon->VBottom)
         {
             SetupPolygonLeftEdge(rp, y);
         }
 
-        if (y >= polygon->Vertices[rp->NextVR]->FinalPosition[1] && rp->CurVR != polygon->VBottom)
+        if ((y >= polygon->SlopePosition[rp->NextVR][1] || y == polygon->Vertices[rp->CurVR]->FinalPosition[1]) && rp->CurVR != polygon->VBottom)
         {
             SetupPolygonRightEdge(rp, y);
         }
@@ -833,10 +853,10 @@ void SoftRenderer::RenderShadowMaskScanline(const GPU3D& gpu3d, RendererPolygon*
     else if (y == polygon->YBottom-1) yedge = 0x8;
     int edge;
 
+    if (xstart < 0) xstart = 0; // negative values are clamped to 0 before interpolation is determined
     s32 x = xstart;
     Interpolator<0> interpX(xstart, xend+1, wl, wr);
 
-    if (x < 0) x = 0;
     s32 xlimit;
 
     // for shadow masks: set stencil bits where the depth test fails.
@@ -948,12 +968,12 @@ void SoftRenderer::RenderPolygonScanline(const GPU& gpu, RendererPolygon* rp, s3
 
     if (polygon->YTop != polygon->YBottom)
     {
-        if (y >= polygon->Vertices[rp->NextVL]->FinalPosition[1] && rp->CurVL != polygon->VBottom)
+        if ((y >= polygon->SlopePosition[rp->NextVL][1] || y == polygon->Vertices[rp->CurVL]->FinalPosition[1]) && rp->CurVL != polygon->VBottom)
         {
             SetupPolygonLeftEdge(rp, y);
         }
 
-        if (y >= polygon->Vertices[rp->NextVR]->FinalPosition[1] && rp->CurVR != polygon->VBottom)
+        if ((y >= polygon->SlopePosition[rp->NextVR][1] || y == polygon->Vertices[rp->CurVR]->FinalPosition[1]) && rp->CurVR != polygon->VBottom)
         {
             SetupPolygonRightEdge(rp, y);
         }
@@ -1082,11 +1102,11 @@ void SoftRenderer::RenderPolygonScanline(const GPU& gpu, RendererPolygon* rp, s3
     if (y == polygon->YTop)           yedge = 0x4;
     else if (y == polygon->YBottom-1) yedge = 0x8;
     int edge;
-
+    
+    if (xstart < 0) xstart = 0; // negative values are clamped to 0 before interpolation is determined
     s32 x = xstart;
     Interpolator<0> interpX(xstart, xend+1, wl, wr);
 
-    if (x < 0) x = 0;
     s32 xlimit;
 
     s32 xcov = 0;
diff --git a/src/GPU3D_Soft.h b/src/GPU3D_Soft.h
index 45b2c53999..6c3833f4d9 100644
--- a/src/GPU3D_Soft.h
+++ b/src/GPU3D_Soft.h
@@ -129,6 +129,7 @@ class SoftRenderer : public Renderer3D
         constexpr void SetX(s32 x)
         {
             x -= x0;
+            if (x > xdiff) x = xdiff; // may or may not be correct
             this->x = x;
             if (xdiff != 0 && !linear)
             {
@@ -284,7 +285,7 @@ class SoftRenderer : public Renderer3D
             // instead, 1/y is calculated and then multiplied by x
             // TODO: this is still not perfect (see for example x=169 y=33)
             if (ylen == 0)
-                Increment = 0;
+                Increment = xlen<<18; // this case should only be triggered by glitched polygons
             else if (ylen == xlen && xlen != 1)
                 Increment = 0x40000;
             else
@@ -315,8 +316,6 @@ class SoftRenderer : public Renderer3D
 
             dx += (y - y0) * Increment;
 
-            s32 x = XVal();
-
             int interpoffset = (Increment >= 0x40000) && (side ^ Negative);
             Interp.Setup(y0-interpoffset, y1-interpoffset, w0, w1);
             Interp.SetX(y);
@@ -324,17 +323,16 @@ class SoftRenderer : public Renderer3D
             // used for calculating AA coverage
             if (XMajor) xcov_incr = (ylen << 10) / xlen;
 
-            return x;
+            return XVal();
         }
 
         constexpr s32 Step()
         {
-            dx += Increment;
+            dx = dx + Increment & 0xFFFFFFF; // seems to be a 28 bit integer
             y++;
 
-            s32 x = XVal();
             Interp.SetX(y);
-            return x;
+            return XVal();
         }
 
         constexpr s32 XVal() const
@@ -343,8 +341,6 @@ class SoftRenderer : public Renderer3D
             if (Negative) ret = x0 - (dx >> 18);
             else          ret = x0 + (dx >> 18);
 
-            if (ret < xmin) ret = xmin;
-            else if (ret > xmax) ret = xmax;
             return ret;
         }
 

From 8eaf303cd4602a53e92a61c5f2b4c4415c8c86d8 Mon Sep 17 00:00:00 2001
From: Jaklyy <102590697+Jaklyy@users.noreply.github.com>
Date: Sat, 18 May 2024 19:08:35 -0400
Subject: [PATCH 2/5] partially fix continuing a polygon strip after a swap
 buffers

no glitchy polygon flickering yet
not sure what's up with that
---
 src/GPU3D.cpp | 16 ++++++++++++++++
 src/GPU3D.h   |  1 +
 2 files changed, 17 insertions(+)

diff --git a/src/GPU3D.cpp b/src/GPU3D.cpp
index 4746a7fa79..0c4804acc7 100644
--- a/src/GPU3D.cpp
+++ b/src/GPU3D.cpp
@@ -1236,6 +1236,19 @@ void GPU3D::SubmitPolygon() noexcept
         {
             poly->Vertices[0] = reusedvertices[0];
             poly->Vertices[1] = reusedvertices[1];
+
+            // null vertices poly invalidation:
+            // 1. Start a polygon strip
+            // 2. Submit at least one polygon
+            // 3. Swap buffers
+            // 4. Don't send a begin command
+            // 4. submit a new polygon (1 vertex for tri, 2 for quad)
+            // 5. if the new polygon reuses vertices, it will be "degenerate" due to them being null pointers (theory)
+            if (NullVertices)
+            {
+                poly->Degenerate = true;
+                NullVertices -= (PolygonMode - 1); // subt. 1 if tri strip, subt. 2 if quad strip.
+            }
         }
         else
         {
@@ -2075,6 +2088,7 @@ void GPU3D::ExecuteCommand() noexcept
             LastStripPolygon = NULL;
             UpdateLastPoly = false;
             CurPolygonAttr = PolygonAttr;
+            NullVertices = 0;
             break;
 
         case 0x41: // end polygons
@@ -2097,6 +2111,8 @@ void GPU3D::ExecuteCommand() noexcept
             PolygonPipeline = 0;
             VertexSlotCounter = 0;
             VertexSlotsFree = 1;
+            // previous polygon's vertices will be counted as "null" if a buffer swap occurs
+            if (PolygonMode >= 2) NullVertices = 2;
             break;
 
         case 0x60: // viewport x1,y1,x2,y2
diff --git a/src/GPU3D.h b/src/GPU3D.h
index f5705c1ffd..e520118ca1 100644
--- a/src/GPU3D.h
+++ b/src/GPU3D.h
@@ -322,6 +322,7 @@ class GPU3D
     u32 VertexNumInPoly = 0;
     u32 NumConsecutivePolygons = 0;
     Polygon* LastStripPolygon = nullptr;
+    u32 NullVertices = 0;
     u32 NumOpaquePolygons = 0;
 
     Vertex VertexRAM[6144 * 2] {};

From b363f959edd2275fad79d62a74062b700ceca722 Mon Sep 17 00:00:00 2001
From: Jaklyy <102590697+Jaklyy@users.noreply.github.com>
Date: Wed, 22 May 2024 06:11:46 -0400
Subject: [PATCH 3/5] help

---
 src/GPU3D_Soft.cpp | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/GPU3D_Soft.cpp b/src/GPU3D_Soft.cpp
index 3203e10ab0..da53c6c61c 100644
--- a/src/GPU3D_Soft.cpp
+++ b/src/GPU3D_Soft.cpp
@@ -691,27 +691,27 @@ void SoftRenderer::SetupPolygon(SoftRenderer::RendererPolygon* rp, Polygon* poly
         rp->NextVR = rp->CurVR + 1;
         if (rp->NextVR >= nverts) rp->NextVR = 0;
     }
-
+    /*
     if (ybot == ytop)
     {
         vtop = 0; vbot = 0;
         int i;
 
         i = 1;
-        if (polygon->SlopePosition[i][0] < polygon->SlopePosition[vtop][0]) vtop = i;
-        if (polygon->SlopePosition[i][0] > polygon->SlopePosition[vbot][0]) vbot = i;
+        if (polygon->Vertices[i]->FinalPosition[0] < polygon->Vertices[vtop]->FinalPosition[0]) vtop = i;
+        if (polygon->Vertices[i]->FinalPosition[0] > polygon->Vertices[vbot]->FinalPosition[0]) vbot = i;
 
         i = nverts - 1;
-        if (polygon->SlopePosition[i][0] < polygon->SlopePosition[vtop][0]) vtop = i;
-        if (polygon->SlopePosition[i][0] > polygon->SlopePosition[vbot][0]) vbot = i;
+        if (polygon->Vertices[i]->FinalPosition[0] < polygon->Vertices[vtop]->FinalPosition[0]) vtop = i;
+        if (polygon->Vertices[i]->FinalPosition[0] > polygon->Vertices[vbot]->FinalPosition[0]) vbot = i;
 
         rp->CurVL = vtop; rp->NextVL = vtop;
         rp->CurVR = vbot; rp->NextVR = vbot;
 
-        rp->XL = rp->SlopeL.SetupDummy(polygon->SlopePosition[rp->CurVL][0]);
-        rp->XR = rp->SlopeR.SetupDummy(polygon->SlopePosition[rp->CurVR][0]);
+        rp->XL = rp->SlopeL.SetupDummy(polygon->Vertices[rp->CurVL]->FinalPosition[0]);
+        rp->XR = rp->SlopeR.SetupDummy(polygon->Vertices[rp->CurVR]->FinalPosition[0]);
     }
-    else
+    else*/
     {
         SetupPolygonLeftEdge(rp, ytop);
         SetupPolygonRightEdge(rp, ytop);

From 37755a50d0b4d27d06651d77b4a41e93ca15910f Mon Sep 17 00:00:00 2001
From: Jaklyy <102590697+Jaklyy@users.noreply.github.com>
Date: Thu, 23 May 2024 10:50:47 -0400
Subject: [PATCH 4/5] fix some more overflow behavior, and 0tall line polys

---
 src/GPU3D_Soft.cpp | 69 ++++++++++++++++++++++++++++++++++++++++------
 src/GPU3D_Soft.h   |  2 +-
 2 files changed, 61 insertions(+), 10 deletions(-)

diff --git a/src/GPU3D_Soft.cpp b/src/GPU3D_Soft.cpp
index da53c6c61c..7313392658 100644
--- a/src/GPU3D_Soft.cpp
+++ b/src/GPU3D_Soft.cpp
@@ -691,8 +691,10 @@ void SoftRenderer::SetupPolygon(SoftRenderer::RendererPolygon* rp, Polygon* poly
         rp->NextVR = rp->CurVR + 1;
         if (rp->NextVR >= nverts) rp->NextVR = 0;
     }
-    /*
-    if (ybot == ytop)
+    
+    // 0px tall line polygons are checked for at rasterization, this matters for when viewports are updated mid-polygon-strip
+    // therefore we need to check if the last two vertices are actually still at the same y axis as the others
+    if ((ybot == ytop) && (ybot == polygon->Vertices[nverts-1]->FinalPosition[1]) && (ybot == polygon->Vertices[nverts-2]->FinalPosition[1]) && (ybot == polygon->Vertices[nverts-3]->FinalPosition[1]))
     {
         vtop = 0; vbot = 0;
         int i;
@@ -711,10 +713,31 @@ void SoftRenderer::SetupPolygon(SoftRenderer::RendererPolygon* rp, Polygon* poly
         rp->XL = rp->SlopeL.SetupDummy(polygon->Vertices[rp->CurVL]->FinalPosition[0]);
         rp->XR = rp->SlopeR.SetupDummy(polygon->Vertices[rp->CurVR]->FinalPosition[0]);
     }
-    else*/
+    else
     {
-        SetupPolygonLeftEdge(rp, ytop);
-        SetupPolygonRightEdge(rp, ytop);
+        s32 y = ytop;
+        if (y < polygon->Vertices[rp->CurVL]->FinalPosition[1])
+            y += 256;
+
+        s32 y1 = polygon->Vertices[rp->NextVL]->FinalPosition[1];
+        if (y1 < polygon->Vertices[rp->CurVL]->FinalPosition[1])
+            y1 += 256;
+
+        rp->XL = rp->SlopeL.Setup(polygon->Vertices[rp->CurVL]->FinalPosition[0], polygon->Vertices[rp->NextVL]->FinalPosition[0],
+                                  polygon->Vertices[rp->CurVL]->FinalPosition[1], y1,
+                                  polygon->FinalW[rp->CurVL], polygon->FinalW[rp->NextVL], y, polygon->WBuffer);
+        
+        y = ytop;
+        if (y < polygon->Vertices[rp->CurVR]->FinalPosition[1])
+            y += 256;
+
+        y1 = polygon->Vertices[rp->NextVR]->FinalPosition[1];
+        if (y1 < polygon->Vertices[rp->CurVR]->FinalPosition[1])
+            y1 += 256;
+
+        rp->XR = rp->SlopeR.Setup(polygon->Vertices[rp->CurVR]->FinalPosition[0], polygon->Vertices[rp->NextVR]->FinalPosition[0],
+                                  polygon->Vertices[rp->CurVR]->FinalPosition[1], y1,
+                                  polygon->FinalW[rp->CurVR], polygon->FinalW[rp->NextVR], y, polygon->WBuffer);
     }
 }
 
@@ -852,8 +875,22 @@ void SoftRenderer::RenderShadowMaskScanline(const GPU3D& gpu3d, RendererPolygon*
     if (y == polygon->YTop)           yedge = 0x4;
     else if (y == polygon->YBottom-1) yedge = 0x8;
     int edge;
-
-    if (xstart < 0) xstart = 0; // negative values are clamped to 0 before interpolation is determined
+    // CHECKME: should the unclamped values be used for timings?
+    // negative values are clamped to 0 before interpolation is done
+    if (xstart < 0) 
+    {
+        l_edgelen += xstart;
+        if (l_edgelen < 1) l_edgelen = 1;
+        xstart = 0;
+    }
+    s32 x = xstart;
+    //xend += 1; dont forget to fix that later-
+    // too big values are clamped to 511 before interpolation is done
+    if (xend > 511)
+    {
+        r_edgelen += 256 - xend;
+        xend = 511;
+    }
     s32 x = xstart;
     Interpolator<0> interpX(xstart, xend+1, wl, wr);
 
@@ -1102,8 +1139,22 @@ void SoftRenderer::RenderPolygonScanline(const GPU& gpu, RendererPolygon* rp, s3
     if (y == polygon->YTop)           yedge = 0x4;
     else if (y == polygon->YBottom-1) yedge = 0x8;
     int edge;
-    
-    if (xstart < 0) xstart = 0; // negative values are clamped to 0 before interpolation is determined
+    // CHECKME: should the unclamped values be used for timings?
+    // negative values are clamped to 0 before interpolation is done
+    if (xstart < 0) 
+    {
+        l_edgelen += xstart;
+        if (l_edgelen < 1) l_edgelen = 1;
+        xstart = 0;
+    }
+    s32 x = xstart;
+    //xend += 1; dont forget to fix that
+    // too big values are clamped to 511 before interpolation is done
+    if (xend > 511)
+    {
+        r_edgelen += 256 - xend;
+        xend = 511;
+    }
     s32 x = xstart;
     Interpolator<0> interpX(xstart, xend+1, wl, wr);
 
diff --git a/src/GPU3D_Soft.h b/src/GPU3D_Soft.h
index 6c3833f4d9..d50b606084 100644
--- a/src/GPU3D_Soft.h
+++ b/src/GPU3D_Soft.h
@@ -341,7 +341,7 @@ class SoftRenderer : public Renderer3D
             if (Negative) ret = x0 - (dx >> 18);
             else          ret = x0 + (dx >> 18);
 
-            return ret;
+            return ret << 21 >> 21; // treated as a signed 11 bit integer (for some reason)
         }
 
         template<bool swapped>

From 9560282c48a253cfe60755b1ded2a494cfd1609b Mon Sep 17 00:00:00 2001
From: Jaklyy <102590697+Jaklyy@users.noreply.github.com>
Date: Sun, 26 May 2024 12:30:47 -0400
Subject: [PATCH 5/5] fix build

---
 src/GPU3D_Soft.cpp | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/src/GPU3D_Soft.cpp b/src/GPU3D_Soft.cpp
index 7313392658..c351ae5e3e 100644
--- a/src/GPU3D_Soft.cpp
+++ b/src/GPU3D_Soft.cpp
@@ -725,7 +725,7 @@ void SoftRenderer::SetupPolygon(SoftRenderer::RendererPolygon* rp, Polygon* poly
 
         rp->XL = rp->SlopeL.Setup(polygon->Vertices[rp->CurVL]->FinalPosition[0], polygon->Vertices[rp->NextVL]->FinalPosition[0],
                                   polygon->Vertices[rp->CurVL]->FinalPosition[1], y1,
-                                  polygon->FinalW[rp->CurVL], polygon->FinalW[rp->NextVL], y, polygon->WBuffer);
+                                  polygon->FinalW[rp->CurVL], polygon->FinalW[rp->NextVL], y);
         
         y = ytop;
         if (y < polygon->Vertices[rp->CurVR]->FinalPosition[1])
@@ -737,7 +737,7 @@ void SoftRenderer::SetupPolygon(SoftRenderer::RendererPolygon* rp, Polygon* poly
 
         rp->XR = rp->SlopeR.Setup(polygon->Vertices[rp->CurVR]->FinalPosition[0], polygon->Vertices[rp->NextVR]->FinalPosition[0],
                                   polygon->Vertices[rp->CurVR]->FinalPosition[1], y1,
-                                  polygon->FinalW[rp->CurVR], polygon->FinalW[rp->NextVR], y, polygon->WBuffer);
+                                  polygon->FinalW[rp->CurVR], polygon->FinalW[rp->NextVR], y);
     }
 }
 
@@ -891,7 +891,6 @@ void SoftRenderer::RenderShadowMaskScanline(const GPU3D& gpu3d, RendererPolygon*
         r_edgelen += 256 - xend;
         xend = 511;
     }
-    s32 x = xstart;
     Interpolator<0> interpX(xstart, xend+1, wl, wr);
 
     s32 xlimit;
@@ -1155,7 +1154,6 @@ void SoftRenderer::RenderPolygonScanline(const GPU& gpu, RendererPolygon* rp, s3
         r_edgelen += 256 - xend;
         xend = 511;
     }
-    s32 x = xstart;
     Interpolator<0> interpX(xstart, xend+1, wl, wr);
 
     s32 xlimit;
openSUSE Build Service is sponsored by