How To Efficiently Mask A Surface In Pygame
Solution 1:
It is hard to tell where is the bottleneck in you program. Probably it is draw.circle
. Try with my code, it implements my own circle drawing algorithm (note, it is not precise circle). Tested with pygame 1.9.2 on Windows, quite slow computer - Atom 1.6 GHz, and it gives me around 40 milliseconds (see DT in code). Then try your implementation and see if it is faster or slower. It would be interesting to compare. BTW, what about using colorkey?
defcircle(r, x0, y0, dest, value):
x1 = int(r / math.sqrt(2))
h = []
x = x1
while(1):
x += 1if x == r:
h.append(ch/3)
break
ch = int(math.sqrt(r**2-x**2))
h.append(ch)
p = 0
dest[x0-x1:x0+x1+1, y0-x1:y0+x1+1] = value
while p < len(h):
dest[x0+x1+p+1, y0-h[p]:y0+h[p]+1] = value
dest[x0-x1-p-1, y0-h[p]:y0+h[p]+1] = value
dest[x0-h[p]:x0+h[p]+1, y0-x1-p-1] = value
dest[x0-h[p]:x0+h[p]+1, y0+x1+p+1] = value
p += 1defput_alpha(Dest, Src): # write alpha values
ref = pygame.surfarray.pixels_alpha (Dest)
numpy.copyto(ref, Src)
del ref
Layer = pygame.Surface ((w,h),flags = pygame.SRCALPHA)
Layer.fill(0xff4B432E)
Mask = numpy.zeros((w,h), dtype = numpy.uint8)
Mask[:] = 255
cur_time = pygame.time.get_ticks()
old_time = cur_time
circle(125, 400, 300, Mask, 125)
circle(75, 400, 300, Mask, 255)
put_alpha(Layer, Mask)
cur_time = pygame.time.get_ticks()
DT = cur_time - old_time
print DT
Update: First, the custom circle function acts ca 5 times slower than pygame's, so it is not what can slow things down. I've sumed up some performance results with various variants. First, make sure you use 24 bit surfaces everywhere, unless you want full 256 grades of transparency, this alone can give better results. If you run following example the output must give "24 32 24". Those are bit depths of corresponding surfaces. This would be optimal for this particular case.
pygame.init()
w = 800
h = 600
DISP = pygame.display.set_mode((w, h), 0, 24)
clock = pygame.time.Clock( )
Noise = pygame.Surface ((w,h))
Noise.fill((110,0,10))
color24bit = (169, 163, 144) # r g b
color = (169, 163, 144, 255) # r g b a
color_a = (169, 163, 144, 112) # r g b a
Layer = pygame.Surface ((w,h), flags = pygame.SRCALPHA)
Layer.fill(color) # ( 169, 163, 144, 255)
Layer_colorkey = pygame.Surface ((w,h))
Layer_colorkey.fill(color24bit)
color_key = (50, 50, 50)
Layer_colorkey.set_colorkey(color_key)
print Noise.get_bitsize(), Layer.get_bitsize(), Layer_colorkey.get_bitsize()
Mask = numpy.zeros((w,h), dtype = numpy.uint8)
Mask[:] = 255
t=0
cur_time = pygame.time.get_ticks()
old_time = cur_time
# 1. blit with per-pixel alpha and custom Mask array
while t < 0:
circle(296, 400, 300, Mask, 112)
circle(15, 400, 300, Mask, 255)
put_alpha(Layer, Mask)
Noise.blit(Layer,(0,0))
DISP.blit(Noise,(0,0))
t += 1
# 2. blit with per-pixel alpha and draw functions
while t < 0:
pygame.draw.circle(Layer, color_a, (400,300), 296, 0)
pygame.draw.circle(Layer, color, (400,300), 15, 0)
Noise.blit(Layer,(0,0))
DISP.blit(Noise,(0,0))
t += 1
# 3. blit with colorkey
while t < 1:
pygame.draw.circle(Layer_colorkey, color_key, (400,300), 296, 0)
pygame.draw.circle(Layer_colorkey, color, (400,300), 15, 0)
Noise.blit(Layer_colorkey,(0,0))
DISP.blit(Noise,(0,0))
t += 1
cur_time = pygame.time.get_ticks()
DT = cur_time - old_time
print "time:", DT
Conclusion: 1. Full alpha with applied custom Mask array: slowest, but you have full control of the mask form and can make cool effects with transparency. 2. Full alpha + just use built-in draw functions, just define color with needed alpha value. A litle bit faster (ITPC), but no direct control over color values. 3. Normal 24 bit surface with colorkey. 2x faster than above, but no custom transparency.
Post a Comment for "How To Efficiently Mask A Surface In Pygame"