Saturday, July 9, 2011

wxwidgets has no alpha channel

A few months after I ported the Alter Aeon client to the wxWidgets toolkit, I decided I wanted to add alpha overlay support to the automap and main window.

Encouragingly enough, this appeared to be trivially supported: wxColor included an alpha value, bitmaps could be defined as having an alpha channel, etc. Pretty much everything looked good to go, so I started experimenting with it.

Alas, it was not to be. It turns out that there are precisely three places where the alpha channel is used:

1) loading a PNG from PNG data that has an alpha channel,
2) drawing a bitmap containing alpha channel data using wxDC::DrawBitmap, and
3) wxDC::DrawText, which politely draws text on top of the underlying pixels.

For all other locations, there simply should have been this assert:

wxASSERT("Alpha channel is stubbed here and works on precisely zero platforms ever, ha ha, the joke is on you")

After upgrading to wx 2.9 and a pile of scouting around, I came across wx/rawbmp.h, which has some direct access functions that allow access to the alpha channel. With this, I managed to get alpha channel working - but there were other problems with 2.9, so I downgraded back to stable, 2.8.12.

The alpha channel code that worked under 2.9 works properly under wx 2.8.12 in wxMAC and wxGTK, but apparently isn't implemented under Win32, which happens to be my main development platform.

Rather than bash my skull repeatedly against the wall, I did what any sane developer would do: throw out the broken toolkit module, and write one that works. In the end, I ended up with a wxBitmap derived class that has drawing functions that actually work properly and support alpha channel drawing when I need them to.

However, there's a problem with this as well, which I'll detail in a later post.


Anonymous said...

What you should have actually tried was using wxGraphicsContext/wxGCDC which supports alpha-channel.

Dennis Towne said...

I did actually look at wxGraphicsContext before writing my own graphics library. However, I have a lot of code that already makes use of the standard wxDC drawing functions, and I just wanted my existing stuff to work without having to port the entire world to a new drawing toolkit. It's not like I'm trying to do space-age art here; I just want to draw some pixels in well defined locations with or without transparency.

There is also the major concern that if I did port everything to the wxGraphicsContext routines, some fundamental part of it will be broken on one of my platforms.

Writing my own means that it will work the same everywhere. And so far, it has.