pygame-ce icon indicating copy to clipboard operation
pygame-ce copied to clipboard

Artifacts when drawing polygons with multiple contours

Open lordmauve opened this issue 9 months ago • 8 comments
trafficstars

I'm experimenting with drawing polygons with multiple contours, such as text and hollow shapes.

To do this I'm connecting one polygon to the next with a zero-width strip, e.g.

polys = [
    [(-80, 80), (80, 80), (80, -80), (-80, -80)],
    [(100, -100), (100, 100), (-100, 100), (-100, -100)]
]
closed = [[*poly, poly[0]] for poly in polys]
chained = []
for poly in closed:
    if chained:
        chained.extend(poly + [chained[-1]])
    else:
        chained.extend(poly)
pygame.draw.polygon(screen, (255, 0, 0), chained)

In OpenGL etc this would work without artifacts (but a different approach is needed to cut holes).

Using pygame.draw.polygon() I see artifacts (behind "Hello, World" and crossing the cog):

Image

Using pygame.gfxdraw.filled_polygon() gives a very similar result:

Image

I am able to get the expected rendering by checking x_intersect[i] != x_intersect[i+1] at https://github.com/pygame-community/pygame-ce/blob/c0f0c74788c6d9230ed3f4d5f78b731968173fe8/src_c/draw.c#L3212-L3214

and removing code at https://github.com/pygame-community/pygame-ce/blob/c0f0c74788c6d9230ed3f4d5f78b731968173fe8/src_c/draw.c#L3227-L3235

However this changes the behaviour for other polygons in a way that is not backwards-compatible. I also implemented a completely floating point version using round() that may be more accurate but pygame.draw.lines() does not match up (there are gaps) but I think maybe perceptually it's a bit better with moving/rotating polygons?

I notice there are many issues and PRs about polygon rendering: #172, #3005, #2208

What approach might make most sense for a PR for this issue? Some options:

  • Change pygame.draw.polygon() to always do this.
  • Add pygame.draw.multi_contour_polygon() that also includes the chaining code above (in C)
  • Add a kwarg like fine=True to pygame.draw.polygon() and conditionally skip the sections of code I highlighted above
  • Pursue floating point versions of these drawing algorithms.

lordmauve avatar Feb 16 '25 12:02 lordmauve