@@ -5385,6 +5385,17 @@ static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t
53855385 int xEnd = (int )end -> position [0 ];
53865386 if (xStart == xEnd ) return ;
53875387
5388+ // Intercept the span bounds to ensure we don't write before the framebuffer.
5389+ int xLoopStart = (xStart >= 0 )? xStart : 0 ;
5390+ int xLoopEnd = (xEnd <= RLSW .colorBuffer -> width )? xEnd : RLSW .colorBuffer -> width ;
5391+ // Nothing to draw.
5392+ if (xLoopStart >= xLoopEnd ) return ;
5393+
5394+ // Get the current row and skip if outside the framebuffer.
5395+ // Maybe this check is better suited elsewhere?
5396+ int y = (int )start -> position [1 ];
5397+ if (y < 0 || y >= RLSW .colorBuffer -> height ) return ;
5398+
53885399 // Compute the inverse horizontal distance along the X axis
53895400 float dxRcp = sw_rcp (end -> position [0 ] - start -> position [0 ]);
53905401
@@ -5405,40 +5416,42 @@ static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t
54055416#endif
54065417
54075418 // Compute the subpixel distance to traverse before the first pixel
5419+ // Also step further into them to move away from the colorbuffer edge.
54085420 float xSubstep = 1.0f - sw_fract (start -> position [0 ]);
5421+ float dxStart = (float )(xLoopStart - xStart );
5422+ float xOffset = xSubstep + dxStart ;
54095423
5410- // Initializing the interpolation starting values
5411- float w = start -> position [3 ] + dWdx * xSubstep ;
5424+ // Initializing the interpolation starting values.
5425+ float w = start -> position [3 ] + dWdx * xOffset ;
54125426 float color [4 ] = {
5413- start -> color [0 ] + dCdx [0 ]* xSubstep ,
5414- start -> color [1 ] + dCdx [1 ]* xSubstep ,
5415- start -> color [2 ] + dCdx [2 ]* xSubstep ,
5416- start -> color [3 ] + dCdx [3 ]* xSubstep
5427+ start -> color [0 ] + dCdx [0 ]* xOffset ,
5428+ start -> color [1 ] + dCdx [1 ]* xOffset ,
5429+ start -> color [2 ] + dCdx [2 ]* xOffset ,
5430+ start -> color [3 ] + dCdx [3 ]* xOffset
54175431 };
54185432#ifdef SW_ENABLE_DEPTH_TEST
5419- float z = start -> position [2 ] + dZdx * xSubstep ;
5433+ float z = start -> position [2 ] + dZdx * xOffset ;
54205434#endif
54215435#ifdef SW_ENABLE_TEXTURE
5422- float u = start -> texcoord [0 ] + dUdx * xSubstep ;
5423- float v = start -> texcoord [1 ] + dVdx * xSubstep ;
5436+ float u = start -> texcoord [0 ] + dUdx * xOffset ;
5437+ float v = start -> texcoord [1 ] + dVdx * xOffset ;
54245438#endif
54255439
54265440 // Pre-calculate the starting pointers for the framebuffer row
5427- int y = (int )start -> position [1 ];
5428- int baseOffset = y * RLSW .colorBuffer -> width + xStart ;
5441+ int baseOffset = y * RLSW .colorBuffer -> width + xLoopStart ;
54295442 uint8_t * cPtr = (uint8_t * )(RLSW .colorBuffer -> pixels ) + baseOffset * SW_FRAMEBUFFER_COLOR_SIZE ;
54305443#ifdef SW_ENABLE_DEPTH_TEST
54315444 uint8_t * dPtr = (uint8_t * )(RLSW .depthBuffer -> pixels ) + baseOffset * SW_FRAMEBUFFER_DEPTH_SIZE ;
54325445#endif
54335446
54345447#define SW_AFFINE_BLOCK 16
54355448
5436- int x = xStart ;
5437- while (x < xEnd )
5449+ int x = xLoopStart ;
5450+ while (x < xLoopEnd )
54385451 {
54395452 // Clamp last block to remaining pixels
54405453 int blockEnd = x + SW_AFFINE_BLOCK ;
5441- if (blockEnd > xEnd ) blockEnd = xEnd ;
5454+ if (blockEnd > xLoopEnd ) blockEnd = xLoopEnd ;
54425455 float blockLenF = (float )(blockEnd - x );
54435456 float blockLenRcp = sw_rcp (blockLenF );
54445457
@@ -5673,6 +5686,14 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b,
56735686 int xMax = (int )br -> position [0 ];
56745687 int yMax = (int )br -> position [1 ];
56755688
5689+ // Exit early if no pixels to draw. Use these later for loop boundaries
5690+ int yLoopMin = (yMin >= 0 )? yMin : 0 ;
5691+ int xLoopMin = (xMin >= 0 )? xMin : 0 ;
5692+ int yLoopMax = (yMax <= RLSW .colorBuffer -> height )? yMax : RLSW .colorBuffer -> height ;
5693+ int xLoopMax = (xMax <= RLSW .colorBuffer -> width )? xMax : RLSW .colorBuffer -> width ;
5694+
5695+ if (yLoopMin >= yLoopMax || xLoopMin >= xLoopMax ) return ;
5696+
56765697 float w = (float )(xMax - xMin );
56775698 float h = (float )(yMax - yMin );
56785699 if ((w <= 0 ) || (h <= 0 )) return ;
@@ -5726,21 +5747,44 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b,
57265747 uint8_t * dPixels = RLSW .depthBuffer -> pixels ;
57275748#endif
57285749
5729- for (int y = yMin ; y < yMax ; y ++ )
5750+ // Calculate the distance the in-bounds boundary is from the quad's edges, only on the left and top.
5751+ float dxMin = (float )(xLoopMin - xMin );
5752+ float dyMin = (float )(yLoopMin - yMin );
5753+
5754+ // Correct our start by how far we clipped outside the framebuffer.
5755+ cRow [0 ] += dCdx [0 ]* dxMin + dCdy [0 ]* dyMin ;
5756+ cRow [1 ] += dCdx [1 ]* dxMin + dCdy [1 ]* dyMin ;
5757+ cRow [2 ] += dCdx [2 ]* dxMin + dCdy [2 ]* dyMin ;
5758+ cRow [3 ] += dCdx [3 ]* dxMin + dCdy [3 ]* dyMin ;
5759+ #ifdef SW_ENABLE_DEPTH_TEST
5760+ zRow += dZdy * dyMin + dZdx * dxMin ;
5761+ #endif
5762+ #ifdef SW_ENABLE_TEXTURE
5763+ uRow += dUdy * dyMin + dUdx * dxMin ;
5764+ vRow += dVdy * dyMin + dVdx * dxMin ;
5765+ #endif
5766+
5767+ for (int y = yLoopMin ; y < yLoopMax ; y ++ )
57305768 {
5731- int baseOffset = y * stride + xMin ;
5769+ int baseOffset = y * stride + xLoopMin ;
57325770 uint8_t * cPtr = cPixels + baseOffset * SW_FRAMEBUFFER_COLOR_SIZE ;
57335771 #ifdef SW_ENABLE_DEPTH_TEST
57345772 uint8_t * dPtr = dPixels + baseOffset * SW_FRAMEBUFFER_DEPTH_SIZE ;
5773+ // Copy the cursors so we increment them ourselves without destroying the offset maths.
57355774 float z = zRow ;
57365775 #endif
57375776 #ifdef SW_ENABLE_TEXTURE
57385777 float u = uRow ;
57395778 float v = vRow ;
57405779 #endif
5741- float color [4 ] = { cRow [0 ], cRow [1 ], cRow [2 ], cRow [3 ] };
5780+ float color [4 ] = {
5781+ cRow [0 ],
5782+ cRow [1 ],
5783+ cRow [2 ],
5784+ cRow [3 ]
5785+ };
57425786
5743- for (int x = xMin ; x < xMax ; x ++ )
5787+ for (int x = xLoopMin ; x < xLoopMax ; x ++ )
57445788 {
57455789 float srcColor [4 ] = { color [0 ], color [1 ], color [2 ], color [3 ] };
57465790
@@ -5779,6 +5823,7 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b,
57795823 #ifdef SW_ENABLE_DEPTH_TEST
57805824 discard :
57815825 #endif
5826+ // We move one pixel over without touching the original "start offset"
57825827 color [0 ] += dCdx [0 ];
57835828 color [1 ] += dCdx [1 ];
57845829 color [2 ] += dCdx [2 ];
@@ -5801,6 +5846,9 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b,
58015846 cPtr += SW_FRAMEBUFFER_COLOR_SIZE ;
58025847 }
58035848
5849+ // The for loop is clamped to the right side of the screen.
5850+ // However, these cursor start vars are still on the left.
5851+ // That's fine. We just need to advance to the next row.
58045852 cRow [0 ] += dCdy [0 ];
58055853 cRow [1 ] += dCdy [1 ];
58065854 cRow [2 ] += dCdy [2 ];
0 commit comments