Reputation: 404
I’m having some problems trying to blit text with pygame2.1.
Here’s some reproducible code:
import pygame
pygame.init()
win = pygame.display.set_mode((500, 500))
font = pygame.font.SysFont("Arial", 50)
text = font.render("Test", True, (255, 255, 255))
text_rect = text.get_rect(center=(250, 250))
run = True
while run:
for e in pygame.event.get():
if e.type == pygame.QUIT:
run = False
win.fill(0)
win.blit(text, text_rect)
pygame.display.update()
Blitting directly on the main window doesen’t seem to function as expected.
But strangely enough, blitting the text on a second surface, and then blitting the surface itself on the main window does work!
import pygame
pygame.init()
win = pygame.display.set_mode((500, 500))
surf2 = pygame.Surface((400, 400))
font = pygame.font.SysFont("Arial", 50)
text = font.render("Test", True, (255, 255, 255))
text_rect = text.get_rect(center=(200, 200))
run = True
while run:
for e in pygame.event.get():
if e.type == pygame.QUIT:
run = False
win.fill(0)
surf2.fill((128, 128, 128))
surf2.blit(text, text_rect)
win.blit(surf2, (50, 50))
pygame.display.update()
I don’t get why that’s the case. Is it a bug in pygame, or just a problem with my computer?
Upvotes: 1
Views: 229
Reputation: 210878
The problem is not with the text, it is with pygame.Surface.fill
. Replace
win.fill(0)
win.fill((0, 0, 0))
This is a known bug in the MacOS version of Pygame 2.1.0 and will be fixed in Pygame 2.1.1.
See Fix weird MacOS display surf weirdness #2859.
Upvotes: 1
Reputation: 8582
So, the issue is that alpha blending is kind of broken in the default blitter, i.e. using special_flags=0
, the default. With the default blitter, if the destination surface has an alpha value of 0, then the source value will be used anyway even if the source's alpha value is 0.
Now, when you use win.fill(0)
, this doesn't just set r, g, b values to 0, but also the alpha value. Now, the text is a transparent alpha surface, that you blit onto this surface. But since the alpha of the target surface is 0 (because of the fill), so the alpha values of the source text surface are entirely ignored, and it just gets blitted on as a solid white rectangle.
There are a few fixes possible.
fill
commandas alluded to in another answer: don't use .fill(0)
, but use e.g. .fill((0, 0, 0))
. This way, you don't set the alpha value too.
Fix the broken alpha value on the target surface by doing:
win.fill((0, 0, 0, 255), text_rect, pygame.BLEND_RGBA_MAX)
This will increase alpha everywhere on the window, without changing any of the colors.
Or if you want, you can do this just for the text rectangle:
win.fill((0, 0, 0, 255), text_rect, pygame.BLEND_RGBA_MAX)
replace:
win.blit(text, text_rect)
with:
win.blit(text, text_rect, special_flags=pygame.BLEND_ALPHA_SDL2)
Since this also is about 4 times faster, in an informal test on my Macbook Air, using 1080p surfaces, this might be a good option?
As for why the screen even has an alpha channel, when only the source surface should affect writing stuff, I'm not sure. But you can see it has one, by running:
print('win has srcalpha', win.get_flags() & pygame.SRCALPHA)
Since the output is non-zero, you can see that win
has an alpha channel:
win has srcalpha 65536
Upvotes: 1