Alphablit between surfaces

Hi,

I am unsure about alpha blits…
I have got two 32bit surfaces, both with the SRC_ALPHA flag set. The target
surface is completely opaque the source surface contains some
semi-transparency. (alpha channel neither 0x00 nor 0xFF)
But when blitting the source into the target surface the alpha information of
the source surface is completely ignored - it is treated as completely opaque.
This is independant of the content of the target surface …
When I blit the source surface directly to the screen surface for example all
alpha information is correctly treated.

Is this intended behavior or am I doing something wrong ?–
Karsten-O. Laux
@Karsten_Laux

I have got two 32bit surfaces, both with the SRC_ALPHA flag set. The target
surface is completely opaque the source surface contains some
semi-transparency. (alpha channel neither 0x00 nor 0xFF)
But when blitting the source into the target surface the alpha information of
the source surface is completely ignored - it is treated as completely opaque.

I think you can only blit a surface with alpha onto one without.
32-bit RGBA-RGBA blits preserve the source alpha channel

I am unsure about alpha blits…
I have got two 32bit surfaces, both with the SRC_ALPHA flag set. The target
surface is completely opaque the source surface contains some
semi-transparency. (alpha channel neither 0x00 nor 0xFF)

You probably want to write a custom alpha blending function for your
application. Go ahead and use the existing code as a guide, and take
into account both source and destination alpha.

See ya!
-Sam Lantinga, Lead Programmer, Loki Entertainment Software

Sam Lantinga wrote:

I am unsure about alpha blits…
I have got two 32bit surfaces, both with the SRC_ALPHA flag set. The target
surface is completely opaque the source surface contains some
semi-transparency. (alpha channel neither 0x00 nor 0xFF)

You probably want to write a custom alpha blending function for your
application. Go ahead and use the existing code as a guide, and take
into account both source and destination alpha.

See ya!
-Sam Lantinga, Lead Programmer, Loki Entertainment Software

I have worked out the math to blend two alpha-ed surfaces: It might be a little
while before I’m able to integrate it into the SDL codebase. I would appreciate
some test code (if you have it) to validate my changes while I make them. I am
including below a macro that should provide the desired result… It is
unfortunately much more complicated than the traditional alpha-blend. Any
suggestions (especially on how to optimize this algorythm) are welcome.

For reference:

sR, sG, sB, and sA are the source color
dR, dG, dB, and dA are the destination color
Adiv and Abits indicate alpha-channel size such that Adiv= ( 2^Abits) -1

#define DOUBLE_ALPHA_BLEND(sR, sG, sB, sA, Adiv, Abits, dR, dG, dB,
dA)
{
dR =
((((dR)-((sR)+(((dR)(dA))/(Adiv))))(sA))+((Adiv)(sR)))/((Adiv)-(((dA)(sA))/(Adiv)));

dG =
((((dG)-((sG)+(((dG)(dA))/(Adiv))))(sA))+((Adiv)(sG)))/((Adiv)-(((dA)(sA))/(Adiv)));

dB =
((((dB)-((sB)+(((dB)(dA))/(Adiv))))(sA))+((Adiv)(sB)))/((Adiv)-(((dA)(sA))/(Adiv)));

dA = ((dA)*(sA))/(Adiv);
}

  dR =

((((dR)-((sR)+(((dR)(dA))/(Adiv))))(sA))+((Adiv)(sR)))/((Adiv)-(((dA)(sA))/(Adiv)));
dA = ((dA)*(sA))/(Adiv);

You are using SDL’s inverted view of alpha (transparency, not opacity
as is the convention); this is fine for now but SDL might change its
definition soon, for compatibility with openGL if nothing else.

Otherwise it looks correct, except for a division by zero when both
pixels are transparent (that has to be special-cased). The nasty
division comes from the recovery of alpha, and is not be needed at all
if we are prepared to work with premultiplied alpha from the result.
Images with premultiplied alpha can be blended onto each other more
efficiently, and to opaque destination images with no performance
penalty (other than writing the extra code). Since SDL has not done
any alpha compositioning, premultiplied alpha has not been worth the
effort.

There is plenty of room for micro-optimisations. In the SDL code, we
usually use shifts instead of division by (2**n-1). Some people use a
power series expansion that is cheaper than a full division, but SDL
is primarily for games, and there a right shift is usually good enough
even if there is a small error. More optimisation can come from
rearranging the expression above, and then from treating several
colour components in parallel. The RLE-alpha code exploits several of
these possibilities.

Mattias Engdeg?rd wrote:

  dR =

((((dR)-((sR)+(((dR)(dA))/(Adiv))))(sA))+((Adiv)(sR)))/((Adiv)-(((dA)(sA))/(Adiv)));
dA = ((dA)*(sA))/(Adiv);

You are using SDL’s inverted view of alpha (transparency, not opacity
as is the convention); this is fine for now but SDL might change its
definition soon, for compatibility with openGL if nothing else.

Yes… I was aware of this… worst case replace all alpha values with (Adiv-value)… (BTW,
I thought that this backwards convention was odd when I first started working with SDL
alpha…)

Otherwise it looks correct, except for a division by zero when both
pixels are transparent (that has to be special-cased). The nasty
division comes from the recovery of alpha, and is not be needed at all
if we are prepared to work with premultiplied alpha from the result.
Images with premultiplied alpha can be blended onto each other more
efficiently, and to opaque destination images with no performance
penalty (other than writing the extra code). Since SDL has not done
any alpha compositioning, premultiplied alpha has not been worth the
effort.

As far as the division by zero, you’re totally correct, and I hadn’t thought of that. I had
been thinking of greaking out Adiv and 0 as special cases for performance benifit anyway
though. As far as premultiplied alpha, I’m going to admit that I’m not sure how that works,
so I can’t comment on it… nor can I implemnt support for it without knowing more…

There is plenty of room for micro-optimisations. In the SDL code, we
usually use shifts instead of division by (2**n-1). Some people use a
power series expansion that is cheaper than a full division, but SDL
is primarily for games, and there a right shift is usually good enough
even if there is a small error. More optimisation can come from
rearranging the expression above, and then from treating several
colour components in parallel. The RLE-alpha code exploits several of
these possibilities.

For positive integers, I’ve found that (x-1)<<(n) is a much closer approximation of
(x)/(2**n -1) than (x)<<(n)… Unfortunately it breaks down badly for 0 and negatives… If
we special-case 0 and don’t have any negatives, this should work fine… My biggest concern
with this was I didn’t know how the error would compound, and wanted a pure implementation
to start with. I also thought about partial evaluation, but didn’t want to introduce any
variables in a macro… maybe I should re-consider.

Thanks for all your input,

-Loren

Loren Osborn wrote:

For positive integers, I’ve found that (x-1)<<(n) is a much closer approximation of
(x)/(2**n -1) than (x)<<(n)… Unfortunately it breaks down badly for 0 and negatives…

Doh!!! I haven’t played with this for about 2 months now… I just remembered why this didn’t
seem to make sense: I meant (x+1)<<(n) is a much closer approximation of (x)/(2**n -1) than
(x)<<(n)…
And this doesn’t break down for 0, although, it does for negatives…

I feel dumb now…

Best regards,

-Loren

Loren Osborn wrote:

Loren Osborn wrote:

For positive integers, I’ve found that (x-1)<<(n) is a much closer approximation of
(x)/(2**n -1) than (x)<<(n)… Unfortunately it breaks down badly for 0 and negatives…

Doh!!! I haven’t played with this for about 2 months now… I just remembered why this didn’t
seem to make sense: I meant (x+1)<<(n) is a much closer approximation of (x)/(2**n -1) than
(x)<<(n)…
And this doesn’t break down for 0, although, it does for negatives…

Darn, I’m batting 1000 today… (Note to self: do not attempt to form coherent thoughts before
removing cobwebs from head!!!)

Okay… One last time: For two integers (a) and (b) in the range of 0 to (2**n-1) :

((a+1)(b))>>n seems to be a closer approximation of (ab)/(2**n-1) than (a*b)>>n .

In fact when evaluated in a rounding-down fashion which is typical of integer math, this
approximation exibhits a “nearest-neighbor” behavior on the low end of the scale.

Appologies,

-Loren

Okay… One last time: For two integers (a) and (b) in the range of 0 to (2**n-1) :

((a+1)(b))>>n seems to be a closer approximation of (ab)/(2**n-1) than (a*b)>>n .

Proof? (I doubt it) If e.g. a == 0 you run into serious trouble! I guess
you wanted something like (ab+1) which is non optimal too. (ab) >> n
is what you want. You can’t get around the fact that you deal with
integers of fixed accuracy without making assumptions you don’t want to
make.

In fact when evaluated in a rounding-down fashion which is typical of integer math, this

Truncation is what happens if you shift - with negative numbers e.g. this is
rounding up :wink:

approximation exibhits a “nearest-neighbor” behavior on the low end of the scale.

No.On Wed, Jul 26, 2000 at 10:52:04AM -0700, Loren Osborn wrote:


Daniel Vogel
Programmer
Loki Entertainment Software

Can you guys take the alpha blending discussion offline?
Be sure and let Yorick know the final results, as he’s working on the
alpha blending code.

Thanks!
-Sam Lantinga, Lead Programmer, Loki Entertainment Software

Daniel Vogel wrote:

Okay… One last time: For two integers (a) and (b) in the range of 0 to (2**n-1) :

((a+1)(b))>>n seems to be a closer approximation of (ab)/(2**n-1) than (a*b)>>n .

Proof? (I doubt it) If e.g. a == 0 you run into serious trouble! I guess
you wanted something like (ab+1) which is non optimal too. (ab) >> n
is what you want. You can’t get around the fact that you deal with
integers of fixed accuracy without making assumptions you don’t want to
make.

With my track record today, I may very well be wrong,
but let me give you some proof by example. Let me go
ahead and prove the extremes, and if you can find a
counter example, I’ll crawl back under my rock. For
an example let’s say 8 bit numbers… so the extremes
will be 0 and 255. Two extremes for two variables
gives us 4 cases… (I’m not saying proof by example
is proof, just that I haven’t seen evidence to the
contrary).

(for n=8)
Desired result: Current Approximation: Suggested approximation:


(ab)/(2**n-1) (ab)/(2n) (error) ((a+1)*b)/(2n) (error)
=============== ====================== ========================

Case 1: a=0 ; b=0
00/255 = 0 00/256 = 0 ( 0 ) 1*0/256 = 0 ( 0 )

Case 2: a=255 ; b=0
2550/255 = 0 2550/256 = 0 ( 0 ) 256*0/256 = 0 ( 0 )

Case 3: a=0 ; b=255 (remember truncation) vvv
0255/255 = 0 0255/256 = 0 ( 0 ) 1*255/256 = 0 ( 0 )

Case 4: a=255; b=255
255255/255 = 255 255255/256 = 254 ( 1 ) 256*255/256 = 255 ( 0 )

Remember this is just an example using the
extremes… I’d like to know if you can
find examples where this works badly…
I mentioned below that it does rounding
rather weird… As always, suggestions
are welcome…

In fact when evaluated in a rounding-down fashion which is typical of integer math, this

Truncation is what happens if you shift - with negative numbers e.g. this is
rounding up :wink:

I said quite explicitly we’re dealing with POSITIVE
numbers between 0 and (2**n-1)… Come to think
of it, 0 isn’t positive… I meant non-negative…

approximation exibhits a “nearest-neighbor” behavior on the low end of the scale.

No.

Yup… Your right here… realized it about 5 minutes
after I posted: The true behavior is closer to rounding
up on the low end of the scale, rounding to nearest
neighbor in the middle, and rounding down at the top
of the scale. Still I think a rounding error is better
behavior than an outright wrong answer.

Best regards,

-Loren> On Wed, Jul 26, 2000 at 10:52:04AM -0700, Loren Osborn wrote:

Every other value ;-)On Wed, Jul 26, 2000 at 12:01:18PM -0700, Loren Osborn wrote:

Remember this is just an example using the
extremes… I’d like to know if you can
find examples where this works badly…


Daniel Vogel
Programmer
Loki Entertainment Software

If you wish. I usually press reply and assume it is sent to the original
sender only instead of the mailing list so I tend to mess up replies :wink:

That reminds me, isn’t this meant as a SDL developers list?On Wed, Jul 26, 2000 at 12:27:20PM -0700, Sam Lantinga wrote:

Can you guys take the alpha blending discussion offline?


Daniel Vogel
Programmer
Loki Entertainment Software

That reminds me, isn’t this meant as a SDL developers list?
Heh, depends:) Developers using SDL or developers developing SDL?:slight_smile:

MartinOn Wed, 26 Jul 2000, Daniel Vogel wrote:

On Wed, Jul 26, 2000 at 12:27:20PM -0700, Sam Lantinga wrote:

Bother! said Pooh, as he put a pin in the Piglet doll.