Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » [A5] Blending

Credits go to Edgar Reynaldo for helping out!
This thread is locked; no one can reply to it. rss feed Print
[A5] Blending
weapon_S
Member #7,859
October 2006
avatar

Hi, everybody! I have some 'gradients' I make with al_put_pixel [1]. I use a very straight-forward subtraction, and I assume I could (easily[2]) rewrite it to use a blender. Blenders will (try to) use hardware acceleration, right?
A few of the basics confuse me though...

  • al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA) Will have a pixel be influenced more by a destination pixel, when that destination pixel's alpha is lower...??? This is standard ???

  • Pre-multiplied alpha. I understand the scenario[3] where you 'blit' while 'using alpha'; and by doing it twice you 'apply' the alpha (erroneously) twice. I have no idea what this has to do with pre-multiplied alpha. Ex_premulalpha is confusing as heck. AFAICT a regular[4] bitmap is created. And when that bitmap is enlarged using linear filtering pre-multiplied alpha is used[5]. So, in contrast to what the example says, all bitmaps are using pre-multiplied alpha; but some use the correct blending mode for pre-multiplied-alpha images. But then the latter two 'ignore' the source alpha, and use 1 ??? With correct results...? Destination alpha is max; so destination pixels shouldn't contribute anywhere the the 'blit' is happening?

On the wiki is an outdated blending tutorial... Any help, please?
P.S. I'm currently even struggling with simple additions, so please be patient and clear.

References

  1. Locked bitmap and all. No complaints here.
  2. Create a bitmap with alpha gradient; al_clear_to_color excluding the gradient; al_set_blender(AL_DST_MINUS_SRC, ALLEGRO_ALPHA, ALLEGRO_ONE); untested.
  3. Mentioned at the end of <code>al_set_new_bitmap_flags</code>.
  4. I mean without the ALLEGRO_NO_PREMULTIPLIED_ALPHA flag. Wait... the transparent areas are black.
  5. That is the semi-transparent pixels are filled in with colours multiplied by the pixel's alpha value
Edgar Reynaldo
Member #8,592
May 2007
avatar

Weapon_S said:

al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA) Will have a pixel be influenced more by a destination pixel, when that destination pixel's alpha is lower...???
This is standard ???

ALLEGRO_INVERSE_ALPHA

src = 1 - sa
dst = 1 - sa

So when dst is ALLEGRO_INVERSE_ALPHA, you can replace all the 'dst's in the formulas below with 1 - sa :

Quote:

ALLEGRO_ADD

r = dr * dst + sr * src
g = dg * dst + sg * src
b = db * dst + sb * src
a = da * dst + sa * src

ALLEGRO_DEST_MINUS_SRC

r = dr * dst - sr * src
g = dg * dst - sg * src
b = db * dst - sb * src
a = da * dst - sa * src

ALLEGRO_SRC_MINUS_DEST

r = sr * src - dr * dst
g = sg * src - dg * dst
b = sb * src - db * dst
a = sa * src - da * dst

Weapon_S said:

but some use the correct blending mode for pre-multiplied-alpha images. But then the latter two 'ignore' the source alpha, and use 1 ??? With correct results...? Destination alpha is max; so destination pixels shouldn't contribute anywhere the the 'blit' is happening?

ALLEGRO_ONE is used because all the pixels in the image have already been scaled by the alpha value, so it should now be ignored. Destination alpha never matters unless you are using one of the special new blenders in A5.1 with al_set_separate_blender. (Edit - Actually, I don't think destination alpha is ever used.)

weapon_S
Member #7,859
October 2006
avatar

Thanks, Edgar.
:) last time I looked into it it took me weeks to notice it said 'sa' instead of 'sd'. Now everything makes sense again. ;)
So pre-multiplied means: replacing the use of the alpha channel with a additive operation is facilitated by reducing a pixel's value based on its alpha... I still don't fully understand. I'll look into it.
'Clearing' without touching alpha channel can't be done... but I'll work around it.

Edgar Reynaldo
Member #8,592
May 2007
avatar

weapon_S said:

So pre-multiplied means: replacing the use of the alpha channel with a additive operation is facilitated by reducing a pixel's value based on its alpha... I still don't fully understand. I'll look into it.

Take the green component for example. Say you have fully bright green (255) and half opaque alpha (127). If you 'pre-multiply' the alpha, then you get (255*127)/255 { (sg*sa)/255 } for the resulting green component, or roughly 127. Now to draw that half opaque, fully bright color of green, you must use additive blending (ALLEGRO_ADD , ALLEGRO_ONE , ALLEGRO_INVERSE_ALPHA) (the default) and add that 127 to (dg*(255-sa)) to get the result.

Quote:

'Clearing' without touching alpha channel can't be done... but I'll work around it.

It can with shaders... You'll need 5.1 though, or else lock a bitmap region and alter the pixel values directly.

Or you can use al_set_separate_blender :

void al_set_separate_blender(int op, int src, int dst,
   int alpha_op, int alpha_src, int alpha_dst)

I think it would be

al_set_separate_blender(op , src , dst , ALLEGRO_ADD , ALLEGRO_ZERO , ALLEGRO_ONE);

That would let you draw anything onto a destination bitmap without affecting its alpha value.

weapon_S
Member #7,859
October 2006
avatar

Premultiplied is clear now. :) The contribution of the source is 'pre-calculated', by subtracting a proportionate amount; then the contribution of the destination is calculated using the alpha of the source (also subtracting a proportionate amount).
For the 'clear-except-alpha-channel workaround' I have two options:

#SelectExpand
1//Very pseudo code 2ALLEGRO_BITMAP* alpha_mask; //Black with alpha pattern 3 4// 1. 5ALLEGRO_BITMAP* buffer2; //No premultiply alpha 6 7set_target_bmp(buffer2); 8clear_to_color(color, zero_alpha); 9set_blender(add, one, one); 10draw_bmp(alpha_mask); 11set_target(final_target); 12set_blender(for final target); 13draw_bmp(buffer2); 14 15// 2. 16set_target(alpha_mask); 17set_separate_blender(add, one, zero, add, zero, one); 18rectfill(completely, color); 19set_target(final_target); 20set_blender(for final target); 21draw_bmp(buffer2)' 22

Clearly option #2 is smaller and doesn't use an extra buffer, but my gut says #1 uses faster operations. I.e. the rectfill with blender would take some more time. It is very much an edge case (in my mind), and I'd like to see how they compare in practice.

or else lock a bitmap region and alter the pixel values directly.

This looks at least faster than using a blender and drawing a filled rectangle... No wait; HW accel is out of the question then... but then you can resort to fast CPU instructions... and then it gets out of my league :P
IMHO interesting to compare, but I've lost my USB stick ATM...

BTW could anybody comment on the hardware acceleration part? The manual is silent and the source is confusing.

Thomas Fjellstrom
Member #476
June 2000
avatar

Allegro 4 doesn't do a lot of hardware acceleration to begin with. The best you can normally expect is hardware accelerated plain blits. I don't think any of the platforms support anything fancier than that with their 2D apis (and even if they do, the drivers for people's hardware probably won't or will implement it with the 3d hardware...).

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

weapon_S
Member #7,859
October 2006
avatar

While the pseudo code was posted, omitting the 'al' prefix, my concerns are about Allegro 5.
I will interpret this answer as: "Allegro 5 should do most things via hardware." :) Thanks for the answer.

Thomas Fjellstrom
Member #476
June 2000
avatar

weapon_S said:

I will interpret this answer as: "Allegro 5 should do most things via hardware." Thanks for the answer.

It will at least try. If you do anything on a locked bitmap, you fall back to software.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

weapon_S
Member #7,859
October 2006
avatar

The function I was looking for was al_draw_tinted_bitmap. ::) 5.1 adds some options that might make me reconsider the precise way I'm doing things now.
Profiling suggests using al_draw_filled_rectangle is faster, and furthermore doesn't take (as much) penalties from using bigger bitmaps, compared to using al_clear_to_color and a blit. In hindsight, makes perfect sense.

Go to: