[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [pygame] Fubared set_alpha()



Derek Simkowiak wrote:
I just fired up some code I wrote about a year ago. The PyGame API has changed and now I can't see how to make my PyGame code work again.
Derek, wow you've been through a big process here. in the end i've got more questions and want to make sure this is all straight. it sounds like what you are wanting to do should be the default behavior. first we'll create some text with pixel alpha, and xfer that to another surface.

>>> from pygame import *
>>> init()
(6, 0)
>>> f=font.Font(None,20)
>>> s1 = f.render('P',1,(128,64,32))
>>> s2 = Surface(s1.get_size(), SRCALPHA, 32)
>>> s1.get_masks(), s2.get_masks()
((16711680, 65280, 255, -16777216), (16711680, 65280, 255, -16777216))
>>> s2.blit(s1, (0,0))
<rect(0, 0, 9, 18)>

now we can test several of the pixel values, they should be the same (including the alpha levels)

>>> s1.get_at((4,4)), s2.get_at((4,4))
((128, 64, 32, 255), (128, 64, 32, 255))
>>> s1.get_at((0,0)), s2.get_at((0,0))
((0, 0, 0, 0), (0, 0, 0, 0))
>>> s1.get_at((7,7)), s2.get_at((7,7))
((128, 64, 32, 240), (128, 64, 32, 240))

looks good. now what is unfortunately causing you trouble is that the blitting does try to blend, so if we blit this again you can see the values will not match..

>>> s2.blit(s1, (0,0))
<rect(0, 0, 9, 18)>
>>> s1.get_at((7,7)), s2.get_at((7,7))
((128, 64, 32, 240), (127, 63, 31, 255))

this should be easy enough to solve by clearing the destination first. but it is an extra step, so perhaps not the best.


RGBA->RGBA without SDL_SRCALPHA
The RGBA data is copied to the destination surface. If SDL_SRCCOLORKEY is set, only the pixels not matching the colorkey value are copied.
this is the case that is now broken. this should be enabled again for sure. the whole problem comes down to the fact that SDL support for pixel alphas is pretty weak in my opinion. pygame is trying to help SDL out by covering a few special cases. first SDL will just crash if you blit a SRCALPHA to an 8bit surface. in this case pygame temporarily disables the SRCALPHA. the other problem is when blitting to a destination with SRCALPHA, none of SDL's blitters set the destination SRCALPHA (well, all except the one you've just pointed out). in this case pygame hijacks the blit with it's own built-in blit functions that actually do what you want. this is what has changed and is throwing off your desired effect.


source.set_alpha(flags=0)
But the new and "improved" API does not use the named argument "flags". The above code results in this error:
TypeError: set_alpha() takes no keyword arguments
this should never have worked. adding keyword arguments to C functions is an extra step i have not taken on any of the pygame functions.

So, unless I pass in an alpha value that is PyNone, SDL_SRCALPHA automatically gets set for me.
"Fine", you say, "just pass in an alpha argument of None and the flags will be left alone". Except that when the alpha argument is None, the value passed to the underlying SDL_SetAlpha() is a default of zero
ah, this is a potentially strange, but no one has been snubbed by it before now. still, it seems it shouldn't effect anything in SDL since if there is no SDL_SRCALPHA flag, SDL ignores all surface and pixel alpha values. in your case, if the surface does have pixel alphas, then the surface alpha is entirely ignored anyway. i'm trying to guess if this is what is the real problem.

Attached is the patch to fix this bug.  It makes my code work again.
but i can't argue with that. ahh, unless.. (/me checks code..)
ok, it is also a bit of a 'bug/wierdness' in my custom blitter codes. it actually is using the surface alpha value, even with no SRCALPHA flag.


And now in venting mode, it took me several hours to find and correct this (highly frustrating and very well-hidden) bug. Everytime something like this happens to me it's a matter of some developer deciding he knows better than me what arguments I wanted to pass in. There are two other places in surface.c where flags are "automagically" set. Please, remove that "feature" and just give me SDL from Python. (End venting mode.)
derek, sorry this bit ya. in the end here's what set me off on the wrong path. You've found another case where SDL's destination alpha blitting code is surprising. here's the final(?) set of cases.

solid source : SDL IGNORES DEST ALPHA
colorkey source : SDL IGNORES DEST ALPHA
pixalpha source : SDL IGNORES DEST ALPHA
surfalpha source: SDL IGNORES DEST ALPHA
and just when i thought i had the pattern all figured out, you find the exception to the rule...
pixalpha without SDL_SRCALPHA: SDL COPIES SRC ALPHA

the fact that the set_alpha(None) disables the alpha flag and sets the surface alpha is a strange situation, but it only reveals a bug in my own custom pygame blitters now. if the blit was passed to SDL in this case you would still be ok.


in any event, i find dealing with the SDL flags in pygame pretty lame. the only reason for the extra 'flags' value in the set_alpha() function is so users can try to optimize with the SDL_RLEACCEL flag as well. but i suppose it could be abused in other ways as well.


i've got this all fixed up in pygame cvs now (phew, first checkin in a month)