[BUG+FIX] Blitting wrong alpha values (Burnings and IImage)

You discovered a bug in the engine, and you are sure that it is not a problem of your code? Just post it in here. Please read the bug posting guidelines first.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: [BUG+FIX] Blitting wrong alpha values (Burnings and IIma

Post by CuteAlien »

The alpha calculation is not yet correct (the one using 8-byte values), the calculation posted doesn't scale the destination alpha by some factor but just gives it huge values. I've not much experience doing calculations which try to avoid float-values, so help welcome. Otherwise I'll try to figure it out over next days.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
burningreggae
Posts: 66
Joined: Wed Oct 04, 2006 2:07 pm

Re: [BUG+FIX] Blitting wrong alpha values (Burnings and IIma

Post by burningreggae »

you can use this code snippet to modify PixelBlend32

Code: Select all

 
inline u32 PixelBlend32 ( const u32 c2, const u32 c1 )
..
    //return (c1 & 0xFF000000) | rb | xg; // glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO)
    u32 sa = c1 >> 24;
    u32 da = c2 >> 24;
    return (da + (((sa-da)*alpha)>>8))<<24 | rb | xg; //glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
 
burningreggae
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: [BUG+FIX] Blitting wrong alpha values (Burnings and IIma

Post by CuteAlien »

Sorry, also doesn't look correct to me.

My test:

Code: Select all

 
#include <irrlicht.h>
#include <iostream>
 
using namespace irr;
 
#ifdef _MSC_VER
#pragma comment(lib, "Irrlicht.lib")
#endif
 
inline u32 PixelBlend32( const u32 c2, const u32 c1 )
{
    // alpha test
    u32 alpha = c1 & 0xFF000000;
 
    if ( 0 == alpha )
        return c2;
 
    if ( 0xFF000000 == alpha )
    {
        return c1;
    }
 
    alpha >>= 24;
 
    // add highbit alpha, if ( alpha > 127 ) alpha += 1;
    alpha += ( alpha >> 7);
 
    u32 srcRB = c1 & 0x00FF00FF;
    u32 srcXG = c1 & 0x0000FF00;
 
    u32 dstRB = c2 & 0x00FF00FF;
    u32 dstXG = c2 & 0x0000FF00;
 
 
    u32 rb = srcRB - dstRB;
    u32 xg = srcXG - dstXG;
 
    rb *= alpha;
    xg *= alpha;
    rb >>= 8;
    xg >>= 8;
 
    rb += dstRB;
    xg += dstXG;
 
    rb &= 0x00FF00FF;
    xg &= 0x0000FF00;
 
    u32 sa = c1 >> 24;
    u32 da = c2 >> 24;
    return (da + (((sa-da)*alpha)>>8))<<24 | rb | xg;
}
 
void compare(u32 a2, u32 a1)
{
    video::SColor col2(a2,0,0,0);
    video::SColor col1(a1,0,0,0);
 
    float s = float(a1)/255.f;
    float d = float(a2)/255.f;
    u32 blendAlpha = (s + d*(1-s)) * 255.f;
 
    std::cout << blendAlpha << " or " << video::SColor(PixelBlend32(col2.color, col1.color)).getAlpha() <<  " for:" << a2 << ":" << a1 << "\n";
}
 
int main(int argc, char *argv[])
{
    compare(254,100);
    compare(0,100);
    compare(100,254);
    compare(100,0);
    compare(200,100);
    compare(127,100);
    compare(60,100);
    compare(2,100);
    compare(200,200);
    compare(127,200);
    compare(60,200);
    compare(2,200);
 
    return 0;
}
 
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
chronologicaldot
Competition winner
Posts: 688
Joined: Mon Sep 10, 2012 8:51 am

Re: [BUG+FIX] Blitting wrong alpha values (Burnings and IIma

Post by chronologicaldot »

@burningreggae - I'm afraid that won't work because the alpha already has a high bit added to it, line 363.

Code: Select all

 
...
// add highbit alpha, if ( alpha > 127 ) alpha += 1;
    alpha += ( alpha >> 7);
...
 
But again, your code doesn't catch the alpha-value overflow, causing alphas that add to greater than 255 to appear as their additive value minus 255, which in many cases is almost zero.

If we're going to do this by-the-book, then the correct code should be:

Code: Select all

 
    u32 sa = c1 >> 24;
    u32 da = c2 >> 24;
    u32 alphaSum = (sa + (255-sa)*da/255);
    alphaSum = (0x000000FF*((alphaSum & 0xFFFFFF00) > 0)) | (alphaSum & 0x000000FF);
    return (alphaSum << 24) | rb | xg;
 
I tested this and got the correct blending for my test case. I ran your tests on it, cuteAlien, and got the current results. And the results of my actual image test were correct.

Note: The 255 factor in "255 - sa" comes from the Wikipedia article that uses "1" referring to "full scale", as it says in the article.
burningreggae
Posts: 66
Joined: Wed Oct 04, 2006 2:07 pm

Re: [BUG+FIX] Blitting wrong alpha values (Burnings and IIma

Post by burningreggae »

Mhmm, you are using a wrong blendfunction formula in function compare AND a integer division with always 0.

Code: Select all

 
//blending formula  rA = (sA*sA) + (dA*(1-sA))
u32 blendAlpha = (s + d*(1-s)) * 255.f; // ->wrong. should be (s*s + d(1-s)
//and
u32 alphaSum = (sa + (255-sa)*da/255) ////<- da/255 will be always 0 (integer)
 
that's why your test code get's the same wrong values;-) two failures make a wrong positive...

ad hightbit_alpha.

Code: Select all

 
u32 alpha = sa + ( sa >> 7 ); // stretch [0;255] to [0;256] to avoid division by 255. use division 256 == shr 8
 
is this a better explanation?. This is Fixpoint 24.8 or (fix8) Alpha is expanded for values [128;255] so that a original alpha of 255 (full opaque) stays opaque. The goal is to avoid a costly integer division (28-102 cycle latency) and use maximal two shr instead. ( 6 cycle) https://software.intel.com/sites/defaul ... atency.pdf. This code is more than 15 years (i'm getting ) old and still a cpu can't do a integer division in 1 cycle...

So and now i see a problem in my code i posted, but it worked with my irrlicht version and compiler setings. (vs2013). in theory it shouldn't

Code: Select all

 
    u32 sa = c1 >> 24;
    u32 da = c2 >> 24;
    return (da + (((sa-da)*alpha)>>8))<<24 | rb | xg; //u32 must be s32 for (sa-da) and alpha!
 
So i post a code which works for unsigned, but uses 2 multiplication instead of 1 and 2 shift's instead of 1.

Code: Select all

 
    u32 alpha = sa + ( sa >> 7 ); // stretch [0;255] to [0;256] to avoid division by 255. use division 256 == shr 8
    u32 blendAlpha_fix8 = (sa*alpha + da*(256-alpha))>>8;
    return blendAlpha_fix8 << 24 | rb | xg;
 
burningreggae
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: [BUG+FIX] Blitting wrong alpha values (Burnings and IIma

Post by CuteAlien »

burningreggae wrote:

Code: Select all

 
//blending formula  rA = (sA*sA) + (dA*(1-sA))
u32 blendAlpha = (s + d*(1-s)) * 255.f; // ->wrong. should be (s*s + d(1-s)
 
Not sure why it should now be (s*s + d(1-s)). I thought we use the wikipedia-version (s + d*(1-s)). I mean I get how the other one fits the rest of the calculations (I think I mentioned that one my mail probably? Can't check right now as I'm on wrong system). And I don't know why Wikipedia arrived on the other formula. Sorry, I don't know which one is "more" correct in which situation.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
burningreggae
Posts: 66
Joined: Wed Oct 04, 2006 2:07 pm

Re: [BUG+FIX] Blitting wrong alpha values (Burnings and IIma

Post by burningreggae »

i was posting the equivalent resultAlpha for opengl glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
instead of using the current glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO).

This Wikipedia article https://en.wikipedia.org/wiki/Alpha_compositing
is talking about Porter-Duff Composition which is not modeled by standard OpenGL. NV_blend_equation_advanced maybe.
The Wikipedia article refers to mixing two tranparent images -> division by out_a which can't be solved in a linear blender -> hence premultiplied alpha.

So, regarding to the original problem. I believe the thread openener want's to blend two images as seen in photoshop.
This wouldn't be solved anyway with changing the final alpha of PixelBlend
You may have a look at https://gamedev.stackexchange.com/quest ... gl-trouble

That's all i can tell about it...
So at least the bug is no bug...
burningreggae
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: [BUG+FIX] Blitting wrong alpha values (Burnings and IIma

Post by CuteAlien »

@burningreggae: OK, thanks a lot! (also for the info about integer divisions - I knew they were still slower, but didn't really expect it to be still that much).

@chronologicaldot: Would that one work for you?
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
chronologicaldot
Competition winner
Posts: 688
Joined: Mon Sep 10, 2012 8:51 am

Re: [BUG+FIX] Blitting wrong alpha values (Burnings and IIma

Post by chronologicaldot »

@burningreggae - In case you've forgotten, multiplication takes precedence over division in C++ . It's one of those bizarre features of the language. So actually, I was and still am getting the correct values because the number is enlargened before being divided.

Second, I don't know where you got the "blendAlpha" because that's not in my code as far as I can see.

My beef with adding the high-bit is that it becomes a "rough" approximation because you aren't using the correct scale. However, it might work anyways, so I guess I'd be ok with it. I'll try it out and see what I get for results. As long as it doesn't leave artifacts, I'd be happy with it.

@CuteAlien - If you mean "I want blending like in Photoshop" then I suppose yes.

EDIT:
@burningreggae - Just tried out your latest code, but it still has an artifact, which you can see around the edges of the red object (a car) in this image.
Image

Summary: I guess the issue is the meaning of the word "blend" in this context, which isn't very clear. The blending in OpenGL seems to follow its own invented set of rules for blending. On the other hand, that obviously not what people like me (and that guy in the link burningreggae posted) are expecting. And since there isn't a "true OpenGL" way of "blending according to expectations", the question becomes whether to follow the non-feature of OpenGL or perform by expectation. I'd prefer the latter or at the very least some mechanism that would allow me to get it.

EDIT:
@burningreggae - I found what was wrong. You multiplied s2 by "alpha". I think you meant 256 (which is how it would come out mathematically when moving it around). When I switched it out, I got the desired blending.

Code: Select all

 
    alpha = sa + ( sa >> 7 ); // stretch [0;255] to [0;256] to avoid division by 255. use division 256 == shr 8
    u32 blendAlpha_fix8 = (sa*256 + da*(256-alpha))>>8;
    return blendAlpha_fix8 << 24 | rb | xg;
 
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: [BUG+FIX] Blitting wrong alpha values (Burnings and IIma

Post by CuteAlien »

chronologicaldot wrote:Second, I don't know where you got the "blendAlpha" because that's not in my code as far as I can see.
That was from my test-code for comparison (using the wikipedia algorithm).
chronologicaldot wrote: @CuteAlien - If you mean "I want blending like in Photoshop" then I suppose yes.
I mean - would it help you to apply the patch like that or not. I don't have a use-case myself where I could say which one is best. It makes sense to me on a theoretical level to change the alpha, but I can't tell if that solution works in your case.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
chronologicaldot
Competition winner
Posts: 688
Joined: Mon Sep 10, 2012 8:51 am

Re: [BUG+FIX] Blitting wrong alpha values (Burnings and IIma

Post by chronologicaldot »

Ah, I see. Sorry, I misunderstood for moment.

Applying the patch would help. Part of the reason is the fact that it's tied to IImage, via which I originally found the bizarre results. But at the same time, I was expecting that blending with images would be the same as rendering to the screen anyways.

EDIT:
@burningreggae - I reread your post. And mixed myself up. My "summary" in my previous post should've been the concluding thought, not my "256 fix" for your code, which you stated you said wasn't OpenGL. My apologies for misinterpreting your post, and that, after I had read it correctly the first time. Silly me.
Last edited by chronologicaldot on Tue Dec 05, 2017 7:50 pm, edited 1 time in total.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: [BUG+FIX] Blitting wrong alpha values (Burnings and IIma

Post by CuteAlien »

You edited your post after I posted mine - and it seems to show that you still run into an error. And then you posted modified code once more. So I'm still not sure which patch to apply now? In this case it's not obvious which solution is correct, but if I risk changing this (making the function slower and potentially messing up people's code relying on the old behavior) then it should at least really fix your case correctly or the change becomes pointless :-)

(edit: I still consider adding another implementation of this algorithm and keeping it downward compatible as well, but that's another topic once we found a solution working for your case)
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
chronologicaldot
Competition winner
Posts: 688
Joined: Mon Sep 10, 2012 8:51 am

Re: [BUG+FIX] Blitting wrong alpha values (Burnings and IIma

Post by chronologicaldot »

Yeah, sorry about that. I keep trying to "spare forum posts", but I guess I should just post a new one every time. It's a forum-etiquette habit from posting on other boards.

My first edit was where I was trying to run the code posted by burningreggae, whereby he used s*s - (256-d)*alpha. This version didn't give me the correct blending, so I changed in the second edit to show what my "fix" was. My fix made it more like the Wikipedia version again, and it works out that way mathematically as far as ratios (and if you ignore the fudge factor of using 256 instead of 255). My second edit, the code I last posted, blending the two images correctly. However, I want to test and see if it'll blend multiple partially-transparent images together.

And yes, I'll put that in a separate post and not edit this one. Sorry about that.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: [BUG+FIX] Blitting wrong alpha values (Burnings and IIma

Post by CuteAlien »

Lol, np, I edit 90% of my posts as well ;-)
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
burningreggae
Posts: 66
Joined: Wed Oct 04, 2006 2:07 pm

Re: [BUG+FIX] Blitting wrong alpha values (Burnings and IIma

Post by burningreggae »

hihi. weird posts. i also replied but it disappeared! (long posting.. talking about fixpoint,accuracy,and performance]

@chronologicaldot: sorry!. test code from cutealien. but yes. we are talking about different formulas.
pixelblend32 should follow "visual acceptable" 8bit-opengl and needs good runtime performance because it's used in 2d and 3d,
a new 32bit per channel offline blend mode could follow adobe rules..;-)
cheers!
burningreggae
Post Reply