[a5 rc4] anomalous blending
Mark Oates

Since switching to RC4 (from 4.9.22) I noticed my images were not blending the same as they were before while in different opacities. I recreated the problem thusly:

  • blue background (or any color background)

  • The top is a single white bitmap that fades from transparent to opaque.

  • The bottom is a donkey image being drawn several times from no opacity to full opacity.


this is default with no function call to change the blender:
the gradient appears correct, but, the donkey is being drawn additive when at 0 opacity.

This is after a call to al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA); to 'draw it normally'.
Now the donkey appears to drawn correctly, but the gradient reveals that as the opacity decreases, there is a bump in darkness, so much that the white overlayed on the blue makes the blue darker.


It looks like the change happened somewhere between RC1 and RC3, I don't have a copy of RC2 that I could test it out with. Under RC1, it seems like the blending is correct.

While in default:


Here's my code:

1#include <allegro5\allegro5.h> 2#include <allegro5\allegro_image.h> 3#include <allegro5\allegro_color.h> 4 5 6void main() 7{ 8 al_init(); 9 al_install_keyboard(); 10 al_init_image_addon(); 11 12 ALLEGRO_DISPLAY *display = al_create_display(1024, 768); 13 14 ALLEGRO_BITMAP *b = al_load_bitmap("not_sure.png"); 15 ALLEGRO_BITMAP *b2 = al_load_bitmap("donk3.png"); 16 ALLEGRO_BITMAP *background = al_load_bitmap("background.png"); 17 if (!b) return; 18 19 ALLEGRO_COLOR color = al_map_rgba_f(1, 1, 1, 1); 20 21 // comment/uncomment as necessary 22 //al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA); 23 //al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); 24 25 do 26 { 27 al_clear_to_color(al_color_name("darkblue")); 28 29 al_draw_tinted_bitmap(b, color, 100, 100, 0); 30 al_draw_bitmap(b, 100, 200, 0); 31 32 33 for (int i=0; i<=5; i++) 34 { 35 color = al_map_rgba_f(1, 1, 1, i*0.2f); 36 al_draw_tinted_bitmap(b2, color, -50+i*175, 400, 0); 37 } 38 39 al_flip_display(); 40 } while (true); 41}

I also attached the two images I used. I also tried al_set_new_display_flags(ALLEGRO_OPENGL); but it made no difference.

Matthew Leverton

Sorry, didn't really even read your post. 8-)

Is this a pre-multiplied alpha thing? There's a bitmap flag to disable that.

Mark Oates

Why would I, by default, want an image at 0 opacity to be visible?

this appears to make things normal again:

// load images heaurh 

How 'bout we add al_set_display_flags(ALLEGRO_DISPLAY_NOT_UPSIDE_DOWN) while we're at it? ;D

Matthew Leverton

There's a confusing explanation at al_set_new_bitmap_flags().

Personally, I wouldn't have changed Allegro to work this way by default, even if it is better to those who know what they are doing.

Mark Oates

Images that you intend to be additive shouldn't have alpha data in them, regardless.

It seems to me that it's an attempt to make additive images with alpha work with alpha, which they shouldn't.

I vote we change it back. :-/

[edit] or at least make the default behavior as described above.

Matthew Leverton

Images that you intend to be additive shouldn't have alpha data in them, regardless.

I agree; it just seems weird from my perspective as a casual 2D game programmer.

I don't mind Allegro supporting pre-multiplied alpha, but I would make it opt-in via ALLEGRO_PREMULTIPLIED_ALPHA. And I think (ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA) makes for a better default blending mode.

Anyway, I assume this was discussed on the AD mailing list. You could search it to find all the reasoning behind making this the default mode.


The problem with ADD/ALPHA/INVERSE is mainly that it breaks when you turn filtering on (and also when you draw to intermediate alpha bitmaps). I got convinced that it's a better idea to have ADD/ONE/INVERSE by default when I read Shawn Hargreave's explanations [1] [2] why he changed the default blending mode in XNA 4 to just that (breaking all older XNA code by doing so :P).

The easiest explanation to justify the change is to just say it's the way both OpenGL and DirectX do blending - except for the special case of completely unfiltered blitting directly to a non-alpha target you won't be happy with non-premultiplied alpha.

The donkey seems to be drawn correctly. If you do this:

al_set_blender(ADD, ONE, INVERSE);
al_draw_tinted_bitmap(donkey, {1, 1, 1, 0}, x, y, 0);

Then it means the source alpha is 0 for every pixel due to the tinting, so you fully keep the blue background and then just add the r/g/b values in the source to it. To draw the donkey completely transparent, instead do this:

al_set_blender(ADD, ONE, INVERSE);
al_draw_tinted_bitmap(donkey, {0, 0, 0, 0}, x, y, 0);

To draw it at exactly 50% of its normal transparency, do this:

al_set_blender(ADD, ONE, INVERSE);
al_draw_tinted_bitmap(donkey, {0.5, 0.5, 0.5, 0.5}, x, y, 0);

This last version above may look similar to using the version below (assuming no premultiplied alpha below):

al_set_blender(ADD, ALPHA, INVERSE);
al_draw_tinted_bitmap(donkey, {1, 1, 1, 0.5}, x, y, 0);

However this will break completely when you turn on filtering. Look at ex_filter and ex_premul_alpha to see why this will probably matter in most games.

With premultiplied alpha you can do anything you can with non-premultiplied just as easily (for tinted drawing, simply multiply the r,g,b values you pass with the alpha yourself) but, the big advantage, things won't randomly break when you turn on filtering (or draw to an intermediate bitmap). It also will be like other libraries do it (XNA, OpenGL, DirectX, and likely also things like Flash or HTML5 which do filtering by default and so have little choice).

Mark Oates

Alright, I'm down. 8-)

It sure is wack at first, and I wouldn't have recommended changing it in an RC ( :-X ), but it does solve more problems at the cost of (r*a, g*a, b*a) in tinting.

So everything has the same appearance as before, except:

  • by default, the mode is al_set_blender(ADD, ONE, INVERSE); Not a big deal but:

  • you must tint your bitmaps by multiplying the color components by the alpha component (r*a, g*a, b*a); otherwise the images will appear additive blended at 0 opacity.

  • alpha is essentially discarded in this mode.

We gain:

  • ability to draw on off-screen bitmaps with correct blending. (this I am very much in favor of, had problems with that in the past.)

  • filtering will not cause issues.

  • alpha-type cutout images will not have white borders.

  • in additive blending mode (ADD, ONE, ONE) alpha is preserved. So before (ADD, ALPHA, INVERSE), fading out an additive image meant interpolating the colors with black instead of changing the alpha. This is still the case, but it's now what you do for your regular blending, too.

Leave everything in default, and all you have to do differently is:

  • all your tinting colors must have their individual color components by multiplied by the alpha. eg al_map_rgba_f(1.0*alpha, 0.93*alpha, 0.2*alpha, alpha);


[edit] perhaps a PREMULTIPLIED_TINTING may be helpful?

[edit2] hmmm... subtractive blending is a challenge, now.


[edit2] hmmm... subtractive blending is a challenge, now.

I never tried it or thought about it, but is it really much different? In fact as long as bitmaps you blend additivly/subtractivly contain no alpha, nothing at all should change.

Thread #606101. Printed from Allegro.cc