pygame-community / pygame-ce

🐍🎮 pygame - Community Edition is a FOSS Python library for multimedia applications (like games). Built on top of the excellent SDL library.
https://pyga.me
763 stars 120 forks source link

A way to replace multiple Surface colors #2929

Open itzpr3d4t0r opened 1 week ago

itzpr3d4t0r commented 1 week ago

With the recent addition of transform.hsl() (#2398) we now have 5 ways to interact with pixels from a surface, that are:

While these options cover most needs, there's still room for improvement. Specifically, there's no built-in, easy, and fast way to replace all occurrences of one color with another on a surface:

These methods either compromise performance, ease of use or miss the point completely. Therefore, I propose adding a new method/function that can replace a set of colors with another set of corresponding colors:

So you could have something like this:

# would replace all red pixels with green and black with white
surf.replace_colors([((255, 0, 0), (0, 255, 0)), ((0, 0, 0), (255, 255, 255))]  

Which could be a really cool addition to quickly change the look of your sprites and an easy way.

My internal tests show that a custom C implementation of this feature would be:

There have also been discussions about the need for these operations, indicating a genuine demand for such a feature: https://discord.com/channels/772505616680878080/1245854714504024104

damusss commented 1 week ago

I agree, this sounds like a very useful feature. I personally think it would be a better fit as an in place surface method in line with set_at or fill (that returns the surface because I think new methods should do that, or not if we want to keep consistency with the rest of the methods). I can literally remember an old project of mine where this feature would have saved me the get/set_at slow loop, so I vibe with it a lot.

Starbuck5 commented 1 week ago

This already exists? https://pyga.me/docs/ref/pixelarray.html#pygame.PixelArray.replace

itzpr3d4t0r commented 6 days ago

Didn't see that coming but it doesn't allow you to change more than one color per call (which tbh is a more realistic usecase), that means that it will run trhough the surface pixels N times instead of one with a better implementation.

Like I've compared this function using PixelArray to replace 3 colors with my custom avx implementation and these are the results:

def py_replace_colors_PixelArray(surface, colors):
    arr = PixelArray(surface)
    for old, new in colors:
        arr.replace(old, new)
    arr.close()

image

I believe this to be more convenient, but if it's really a burden to add more functionality to surface or transform we could expand Pixelarray.replace to support multiple colors.