xxSirFartAlotxx
xxSirFartAlotxx

Reputation: 404

Blitting text with pygame2.1 not working correctly

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.enter image description here


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()

enter image description here

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

Answers (2)

Rabbid76
Rabbid76

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

Hugh Perkins
Hugh Perkins

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.

Option 1: change fill command

as 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.

Option 2: fix broken alpha value

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)

Option 3: use sdl2 blitter

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?

Addendum: Checking win for alpha channel

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

Related Questions