4

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

Braiam
  • 1
  • 11
  • 47
  • 78
Ignis Incendio
  • 190
  • 1
  • 10
  • where did you found polygon with image in PyGame ??? Or maybe you mean OpenGL. – furas Nov 19 '16 at 02:15
  • @furas Huh? No, I'm pretty sure I meant PyGame. – Ignis Incendio Nov 19 '16 at 04:13
  • Seeing your updates and image, **that** might be tougher to do in pygame alone. You might want to try taking a look at [this](http://stackoverflow.com/a/14178717/2588654) answer using PIL. You can load the image in PIL/pillow, perform the transformation there, and then convert the PIL image to a pygame image. Alternatively, you can use PyOpenGL with Pygame, and you can pass in arbitrary transformation matrices to rotate your image however, but that would mean losing a lot of the other niceties of pygame's SDL rendering model. Let me know if this helps or if it is still unclear. – CodeSurgeon Nov 19 '16 at 04:47
  • @user2588654 Oh, alright. That's good to know, I was prepared to hear that. – Ignis Incendio Nov 19 '16 at 05:44
  • chicken man, no discussion. – sam-pyt Jun 23 '19 at 19:13

2 Answers2

2

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
1

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.
Community
  • 1
  • 1
CodeSurgeon
  • 2,435
  • 2
  • 15
  • 36
  • Thanks for the answer, and I think it'll be handy in the future. However, that wasn't what I was asking about. I meant stretching the image, not cutting it off. If my question was unclear, I apologise. I'll add a picture to illustrate what I mean. – Ignis Incendio Nov 19 '16 at 04:15
  • Yes a picture is 1000 words, so definitely add one! I was not completely sure about what you meant in your initial question. – CodeSurgeon Nov 19 '16 at 04:18