Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does one stretch an image to the shape of a polygon in Pygame?

Tags:

python

pygame

Alternatively, how does one fill a polygon in Pygame with an image?

I've tried searching documentation but didn't turn up much, so I'm asking here to see if I missed out anything. I can use transformation matrices if needed.

Here's an example of what I want to achieve: Example

like image 836
Ignis Incendio Avatar asked Oct 17 '25 13:10

Ignis Incendio


2 Answers

You might be looking for pygame's alternative drawing functions from pygame.gfxdraw, what your looking is textured polygon

Note: You need to import it separately as gfxdraw doesn't import as default so you need to import it separately e.g.

import pygame
import pygame.gfxdraw
like image 120
GreenJon902 Avatar answered Oct 20 '25 03:10

GreenJon902


I think the concept you are looking for is a bitmap mask. Using a special blending mode, pygame.BLEND_RGBA_MULT, we can blend the contents of two surfaces together. Here, by blending, I mean that we can simply multiply the color values of two corresponding pixels together to get the new color value. This multiplication is done on normalized RGB colors, so white (which is (255, 255, 255) would actually be converted to (1.0, 1.0, 1.0), then multiplication between the masking surface and the masked surface's pixels would be performed, and then you would convert back to the non-normalized RGB colors.

In this case, all that means is that we need to draw the polygon to one surface, draw the image of interest to another surface, and blend the two together and render the final result to the screen. Here is the code that does just that:

import pygame
import sys

(width, height) = (800, 600)
pygame.init()
screen = pygame.display.set_mode((width, height))
image = pygame.image.load("test.png").convert_alpha()
masked_result = image.copy()

white_color = (255, 255, 255)
polygon = [(0, 0), (800, 600), (0, 600)]

mask_surface = pygame.Surface((width, height))
pygame.draw.polygon(mask_surface, white_color, polygon)
pygame.draw.aalines(mask_surface, white_color, True, polygon)#moderately helps with ugly aliasing
masked_result.blit(mask_surface, (0, 0), None, pygame.BLEND_RGBA_MULT)

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
    screen.blit(masked_result, (0, 0))
    pygame.display.update()

The result looks like this using a simple triangle as the mask. Polygonally-masked Image

Some things to note:

  • This answer is based off of this, which you might be interested in if you want more complicated masks than polygons (such as pretty bitmap masks).
  • This solution is not using the pygame.mask module!
  • I have not fully tested this code yet, but I suspect that this will only work for convex polygons, which may be a significant limitation. I am not sure if pygame can draw concave polygons, but I know PyOpenGL can using stencil buffer tricks or tesselation. Let me know if you are interested in that approach instead.
  • While I have attempted to get rid of aliasing, the results are still not completely satisfactory.
like image 36
CodeSurgeon Avatar answered Oct 20 '25 03:10

CodeSurgeon



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!