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

[pygame] Fubared set_alpha()




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.

I need to copy one RGBA surface onto another RGBA surface. The source surface has per-pixel alpha information (instead of a single byte alpha value for the whole surface). I want to keep that per-pixel alpha information when I blit the source surface into my destination surface, rather than "blending" or using the destination alpha.

The way to do that with SDL is to clear the bit SDL_SRCALPHA bit on the source surface before doing the blit. Here is the SDL documentation:

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

Hence, the SDL_SRCALPHA bit must be cleared for me to do what I want (which, FYI, is render an anti-aliased font created with the SDL TTF library using OpenGL).

Here is the PyGame code that worked successfully before. "source" and "dest" are my RGBA surfaces with per-pixel alpha information:


# Turn off SRCALPHA so the alpha value is copied directly (instead of blending)
source.set_alpha(flags=0)
dest.blit(source, [0, 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

set_alpha() is now designed with both the alpha argument AND the flags argument. To pass the flags argument, one MUST, with the new (broken) API, also pass in an alpha argument.

Well, fine, no biggie, except for this little nugget in the surface.c "set_alpha()" function:

if(alpha_obj && alpha_obj!=Py_None)
{
[...]
hasalpha = 1;
}
if(hasalpha)
flags |= SDL_SRCALPHA;

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, a.k.a. SDL_ALPHA_TRANSPARENT, a.k.a. "Fully Transparent", a.k.a. I'm forced to make my image invisible if I want to clear the SDL_SRCALPHA flag and blit with the per-pixel alpha data.

This is not the desired behaviour, and it makes it impossible to blit one RGBA surface onto another whilst retaining the per-pixel alpha data.

Attached is the patch to fix this bug. It makes my code work again.

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


Thanks,
Derek Simkowiak
--- /home/dereks/PyGame/pygame-1.5.5/src/surface.c	2002-12-02 23:10:45.000000000 -0800
+++ /usr/src/RPM/SOURCES/pygame-1.5.5/src/surface.c	2003-05-09 14:10:49.000000000 -0700
@@ -624,7 +624,7 @@
 	Uint32 flags = 0;
 	PyObject* alpha_obj = NULL, *intobj=NULL;
 	Uint8 alpha;
-	int result, alphaval=0, hasalpha=0;
+	int result, alphaval=0;
 
 	if(!PyArg_ParseTuple(args, "|Oi", &alpha_obj, &flags))
 		return NULL;
@@ -641,10 +641,7 @@
 		}
 		else
 			return RAISE(PyExc_TypeError, "invalid alpha argument");
-		hasalpha = 1;
 	}
-	if(hasalpha)
-		flags |= SDL_SRCALPHA;
 
 	if(alphaval>255) alpha = 255;
 	else if(alphaval<0) alpha = 0;