Hi,
I made a solution, however it is not the best either for speed either for beauty.
You can use double blitting with setting colorkeys for transparency. In that way the mask should have only two colors: black and white.
Note that you can't use this for images with per pixel alpha (RGBA) only for RGB images.
Other restriction is that it is recommended that the size of the texture and the mask image is the same (if not you should use areas for blitting).
In words, step by step:
- create a surface with the mask. background should be white (255,255,255), the masked parts should be black (0,0,0)
- create or load the texture into a surface
- set a transparency colorkey for the mask for the black color
- blit the mask onto the texture (or onto a copy of the texture). at this point the black parts of the mask haven't blitted to the texture because we set the black color to transparent with the set_colorkey method
- now set the colorkey of the texture (or the copy of the texture) to white. remember that our current texture surface has white and textured parts.
- blit the texture to the screen. the white parts won't be blitted due to we have set it to transparent with the colorkey
Code sample:
#!/usr/bin/python
# -*- coding:utf8 -*-
import pygame, sys
#init pygame
pygame.init()
#init screen
screen=pygame.display.set_mode((800,600))
screen.fill((255,0,255))
#loading the images
texture=pygame.image.load("texture.jpg").convert()
texture_rect=texture.get_rect()
texture_rect.center=(200,300)
mask=pygame.Surface((texture_rect.width,texture_rect.height)) # mask should have only 2 colors: black and white
mask.fill((255,255,255))
pygame.draw.circle(mask,(0,0,0),(texture_rect.width/2,texture_rect.height/2),int(texture_rect.width*0.3))
mask_rect=mask.get_rect()
mask_rect.center=(600,300)
tmp_image=texture.copy() # make a copy of the texture to keep it unchanged for future usage
mask.set_colorkey((0,0,0)) # we want the black colored parts of the mask to be transparent
tmp_image.blit(mask,(0,0)) # blit the mask to the texture. the black parts are transparent so we see the pixels of the texture there
tmp_rect=tmp_image.get_rect()
tmp_rect.center=(400,300)
tmp_image.set_colorkey((255,255,255))
screen.blit(texture,texture_rect)
screen.blit(mask,mask_rect)
screen.blit(tmp_image,tmp_rect)
pygame.display.flip()
while 1:
event=pygame.event.wait()
if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key in [pygame.K_ESCAPE, pygame.K_q]):
sys.exit()
I recommend not to use jpg as mask because of its lossy format, I recommend bmp or png (bmp is better). Remember it not uses alpha so the edges won't be anti-aliased so it is not a nice solution in 2010 :)
Here is the screenshot of the result:
Edit:
Hi again,
I made some tests with the blitting with BLEND_ADD and the results was promising. Here is the code:
import pygame, sys
#init pygame
pygame.init()
#init screen
screen=pygame.display.set_mode((800,600))
screen.fill((255,0,255))
#loading the images
texture=pygame.image.load("texture.jpg").convert_alpha()
texture_rect=texture.get_rect()
texture_rect.center=(200,300)
mask=pygame.image.load("mask2.png").convert_alpha()
mask_rect=mask.get_rect()
mask_rect.center=(600,300)
textured_mask=mask.copy()
textured_rect=textured_mask.get_rect()
textured_rect.center=400,300
textured_mask.blit(texture,(0,0),None,pygame.BLEND_ADD)
screen.blit(texture,texture_rect)
screen.blit(mask,mask_rect)
screen.blit(textured_mask,textured_rect)
pygame.display.flip()
while 1:
event=pygame.event.wait()
if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key in [pygame.K_ESCAPE, pygame.K_q]):
sys.exit()
And the result:
With this solution you can get per pixel alpha texturing. Please note that the mask should be an image with alpha channel so jpg could not be used. The best to use is png.
Texture image (texture.jpg):
Mask image (mask2.png):