Long story short, I need to do alpha blending in javascript because I want aliased graphics ( which AA can't be turned off here ) and webGL is not currently an option. Don't judge me. :D
Interesting to note, my result is producing a similar phenomenon to one that I observe in the native canvas when alpha blending, so I don't feel too bad about it, but I'm just trying to get my head around what's happening here.
The example is on KA to make it easier to twiddle.
Here is my method:
// sanity check
// https://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending
// var sA = alpha ( sRGBA ) / 255;
// var dA = alpha ( dRGBA ) / 255;
// var rA = sA + dA * ( 1 - sA );
// var pRGB = [ red ( sRGBA ), green ( sRGBA ), blue ( sRGBA ) ].map ( function ( e ) {
// return e * sA;
// } );
// var rRGBA = [ red ( dRGBA ), green ( dRGBA ), blue ( dRGBA ) ].map ( function ( e, i ) {
// return Math.round ( ( pRGB [ i ] + e * dA * ( 1 - sA ) ) / rA );
// } );
// rRGBA.push ( Math.round ( rA * 255 ) );
// println ( rRGBA );
// horrible bit hack and lookup
var blendAlpha = ( function () {
// lookup table for division
var aDiv = ( function () {
return this.Function ( "return new Uint32Array(256);" )();
} ) ();
// Aout = 0 => RGBout = 0
for ( var i = 1; i < 256; i = i + 1 ) {
aDiv [ i ] = 257 * 255 / i;
}
return function ( sRGBA, dRGBA ) {
sRGBA = sRGBA >>> 0;
dRGBA = dRGBA >>> 0;
var s = ( 1 + ( sRGBA >>> 24 ) ) >>> 0, d = ( 1 + ( dRGBA >>> 24 ) ) >>> 0,
a = ( s + d - ( s * d >>> 8 ) - 1 ) >>> 0,
ia = ( 257 - s ) >>> 0,
RB = 0xff00ff >>> 0,
G = 0xff00 >>> 0,
rb = (
( s * ( sRGBA & RB ) >>> 8 & RB >>> 0 ) +
( ( d * ( dRGBA & RB ) >>> 8 & RB >>> 0 ) * ia >>> 8 & RB >>> 0 )
) * aDiv [ a ] >>> 8 & RB >>> 0,
g = (
( s * ( sRGBA & G ) >>> 8 & G >>> 0 ) +
( ( d * ( dRGBA & G ) >>> 8 & G >>> 0 ) * ia >>> 8 & G >>> 0 )
) * aDiv [ a ] >>> 8 & G >>> 0;
return rb | g | a << 24 >>> 0;
};
} ) ();
And here is what I see with a low alpha source color and a transparent destination:
source destination result native
======================================================
0,127,0,0 0,0,0,0 0,0,0,1 0,0,0,0
0,127,0,1 0,0,0,0 0,0,0,2 0,0,0,1
0,127,0,2 0,0,0,0 0,85,0,3 0,128,0,2
0,127,0,3 0,0,0,0 0,63,0,4 0,85,0,3
0,127,0,4 0,0,0,0 0,102,0,5 0,128,0,4
0,127,0,5 0,0,0,0 0,85,0,6 0,102,0,5
0,127,0,6 0,0,0,0 0,109,0,7 0,128,0,6
0,127,0,7 0,0,0,0 0,95,0,8 0,109,0,7
0,127,0,8 0,0,0,0 0,113,0,9 0,128,0,8
0,127,0,9 0,0,0,0 0,102,0,10 0,113,0,9
Otherwise the resulting values are ballpark/acceptable, e.g. higher up in the alpha range on the source.
I believe the bifurcation is a result of the way I am doing the division step, but I'm not sure exactly.
Does anybody have a better idea of what's going on here or have dealt with this kind of issue before?
I don't care at the moment if my method is faulty/crappy. I'll deal with that later, just curious about the weird/unexpected bifurcation. I would have expected a stair step, or something like that, but not this.