PNG alpha channel problems

Started by Akril15, Tue 19/02/2013 03:39:43

Previous topic - Next topic

Calin Leafshade

I was only referring to the term itself.

Snarky

OK. I just wanted to make sure that it wasn't misunderstood to mean that additive opacity produces a "correct" result (for reasonable interpretations of "correct").

Crimson Wizard

#22
Quote from: Snarky on Thu 25/04/2013 16:33:17
Anyway, is this really something AGS has to solve? Aren't there already library functions in Allegro or whatever that allows you to combine two graphics with alpha-channels and get the correct result?

Allegro is made as a "wireframe" where you may connect your own callbacks to many of the operations, blending being one of them, so this approach is principally valid.
As for built-in blenders, unfortunately standard Allegro's alpha blender doesn't work, because it copies the resulting pixels with zero alpha value; if drawn this way all the translucent controls will create 100% transparent holes at their places on main gui surface.

Good news though, while examining the Allegro source code and comparing with various CJ's custom blenders I found that I may simply copy default Allegro's alpha blender and modify it so that it will keep alpha value. The result is almost what we need, I think, minus summing the alpha (alpha remains the one of the main gui surface).

Here's code:
Spoiler

Code: cpp

unsigned long _myblender_alpha32(unsigned long x, unsigned long y, unsigned long n)
{
    unsigned long res, g, alpha;

    n = geta32(x);

    if (n)
        n++;

    alpha = y & 0xff000000;

    res = ((x & 0xFF00FF) - (y & 0xFF00FF)) * n / 256 + y;
    y &= 0xFF00;
    x &= 0xFF00;
    g = (x - y) * n / 256 + y;

    res &= 0xFF00FF;
    g &= 0xFF00;

    return res | g | alpha;
}

[close]



//=========================================================
EDIT: how it looks like.
Room background is an AGS editor splash, gui is a yellow rectangle with alpha gradient (lower alpha towards left side), and gui button is poor guy from Laura Bow 2 in sarcofagus (keep forgetting his name, Dr. Carter maybe?). Gui button graphic is divided into 2 parts: left half is translucent and right part is opaque.

Spoiler

Crimson Wizard

#23
I added combined opacity as Snarky suggested, hopefuly I implemented his formula right:
Code: cpp

back_alpha = (255 - (255 - geta32(x)) * (255 - geta32(y)) / 255) << 24;
<...>
return res | g | back_alpha;


Here are the comparisons. The control with left translucent part over translucent gui over room:
Spoiler

The same control over opaque gui:
Spoiler

Does it look OK now?


//---------------------------
Quote
combined_alpha = 1 - (1-front.alpha)*(1-back.alpha) (where front is the gui control and back the gui). That way, two 50% transparent layers on top of each other combine correctly to 75% opacity, rather than 100%.

This way if the control is opaque, the summ will always be opaque regardless of back surface alpha. Is this correct?

HandsFree

Quote from: Crimson Wizard on Wed 24/04/2013 10:41:53
Does anyone know any games where the GUI controls with alpha channel were used?
I don't think it's a secret that the original question was about the King's Quest 4 remake for which we are about to release a short demo.
We took out the sprites that caused a 'hole' in the gui, but we still have the ones where alpha is displayed as opaque black.
We also had to replace the Sierra style speech portraits because the background turned out completely black.

So if this were to be fixed that would be a great help!  8-)

Crimson Wizard

#25
Quote from: HandsFree on Fri 26/04/2013 09:50:31
We took out the sprites that caused a 'hole' in the gui, but we still have the ones where alpha is displayed as opaque black.
IIRC the "holes" are caused by inventory items, because they were not fixed by CJ when he added new alpha blending.
Opaque "alpha" bug happens with other controls (e.g. buttons).
If I'll be able to find proper blending algorythm I will need to apply it to both cases, and it will work identical for all gui sprites.

I asked about games because I wanted to make tests and see that I did not screw anything.

Snarky

Nice work, CW!

Quote from: Crimson Wizard on Fri 26/04/2013 07:08:28
I added combined opacity as Snarky suggested, hopefuly I implemented his formula right:
Code: cpp

back_alpha = (255 - (255 - geta32(x)) * (255 - geta32(y)) / 255) << 24;
<...>
return res | g | back_alpha;

That looks generally right, although I don't know about the left-shift. You're bit-wise OR-ing it together with other values, so I guess it has something to do with getting it into the right part of the return value?

QuoteDoes it look OK now?

It looks OK as far as I can tell, but it's hard to evaluate with such a weird example. I'd probably just try to overlay two 50%-transparent white sprites on a black background, as well as maybe a blue and a green sprite. The other thing you could do is recreate the setup in Photoshop, and then put this on top with blend mode "difference." If the results are identical, the image should be completely black. (Due to rounding errors, every pixel may not be 100% black, though.)

Quote
Quote
combined_alpha = 1 - (1-front.alpha)*(1-back.alpha) (where front is the gui control and back the gui). That way, two 50% transparent layers on top of each other combine correctly to 75% opacity, rather than 100%.

This way if the control is opaque, the summ will always be opaque regardless of back surface alpha. Is this correct?

Yes. If front.alpha is 1 (opaque), the second term goes to 0, and combined_alpha = 1 - 0 = 1, so it's always opaque. The same happens if the gui is opaque (back.alpha = 1). And if one of them is completely transparent, the alpha of the other is used. It all works out.

Crimson Wizard

#27
Editor and engine executables with a fix, if anyone wants to test:
http://www.mediafire.com/?ta43i8g5lvh4qg4
!WARNING! based on 3.3.0 beta, so don't use it with your only real game copy.
There's an extra choice for Alpha gui rendering style in Global settings.

Quote from: Snarky on Fri 26/04/2013 16:27:46
It looks OK as far as I can tell, but it's hard to evaluate with such a weird example. I'd probably just try to overlay two 50%-transparent white sprites on a black background, as well as maybe a blue and a green sprite.

Spoiler



[close]




//------------------------------------------------------
EDIT:
There's a problem with transparent gui parts, this new blender treats magic pink as an actual color, and the result is blending translucent  control parts with with magenta.


//------------------------------------------------------
EDIT2:
Something that worries me is that when I am putting a button with "shadow" (see early posts in this thread for an example) on the translucent gui background, the shadow part becomes brighter rather than darker.

Blackthorne

I'm having a problem with Alpha-Blended sprites as portraits - we have portraits in the game that have no backgrounds - the sprites are alpha blended, and if used as an object, they appear correct with their anti-aliased edges, but as portraits there is artifacting around the edge.


Bt
-----------------------------------
"Enjoy Every Sandwich" - Warren Zevon

http://www.infamous-quests.com

Knox

If we previously used AdditiveOpacity with 3.2 without any problems, what advantages would there be for us to switch to the new MultipliedTranslucence mode in 3.3? (Curious because if I switch to the new mode in 3.3 I get pink around the alphas of certain sprites, so if there aren't any major advantages I might just stay in AdditiveOpacity).

--All that is necessary for evil to triumph is for good men to do nothing.

Crimson Wizard

Quote from: General_Knox on Sat 07/09/2013 23:03:08
If we previously used AdditiveOpacity with 3.2 without any problems, what advantages would there be for us to switch to the new MultipliedTranslucence mode in 3.3?
It is not about advantage, these are two different types of combining alpha values. The "multiplied translucence" was added because in SOME cases "additive opacity" worked weird (check the beginning of this thread to see examples of what I mean).
If "Additive oppacity" works well for you, you may just keep using it.

Quote from: General_Knox on Sat 07/09/2013 23:03:08
Curious because if I switch to the new mode in 3.3 I get pink around the alphas of certain sprites
Hmmm, that may or may not be an error. Can you upload your sprites somewhere and explain how do you combine them?

Knox

#31
Ok as soon as I get home tonight I'll post pics.
EDIT: Got in late tonight, make that tomorrow!
--All that is necessary for evil to triumph is for good men to do nothing.

Monsieur OUXX

Just a useless supportive message, to say that I'm glad (like every average AGS user I suppose) that those things are being perfected: Less and less knowledge in "alpha bugs" is required by users. That's that much less work during early ddesign and final testing!
Thanks a lot Crimson and pals!
 

Knox

#33
Ok, here's an example of the pink alphas with MultipliedTranslucence.

Additive Opacity, Copy Source Color:
Spoiler
[close]

Multiplied Translucence, Blend Source Color:
Spoiler
[close]

How it is setup in the editor so it works well with Additive Opacity:
Inventory window has 3 layers (gInvBackground, gInventory, gInventoryOver)

Z = 0 Background image behind the inventory items
Spoiler
[close]

Z = 1 Inventory items with no background image (work-around to fix alpha issues with Additive Opacity)
Spoiler
[close]

Z = 3 Gui frame that goes over everything to hide inventory item scrolling. A highlight button with an alpha frame gets moved along with the mouse
Spoiler
[close]

If I remove the gui gInvBackground, replace the BackgroundImage of the gInventory to the same sprite (#1000), then I no longer get pink around the inventory items in Multiplied Translucence...however the button btnInv_Hilite's alpha still remains pink.

**Let me know if you want the png files too (which ones), I'll post them aswell.
--All that is necessary for evil to triumph is for good men to do nothing.

Crimson Wizard

#34
Hmm... so, to clarify.
You have 3 GUIs placed atop of each other:
1. gInvBackground, which has an opaque dark-blue background and inventory grid drawn on it.
2. gInventory, which is just a fully transparent (filled with magic pink), and InventoryWindow control.
3. gInventoryOver, which has another grid with transparent "cuts" to allow items from gInventory be seen through; and a button with a 8-point star shaped transparent "hole" (at least that's what I think I see).

My main question is this: which of those sprites have alpha channel and which do not?
I must make a test game and reproduce this behavior to see what's going on and how fixes to engine change the situation.

Knox

#35
Here is the gInvBackground sprite (no transparency/alpha, png)
Spoiler
[close]

Here is the btnInv_Hilite sprite, a highlight frame with shadow (transparency, png)
Spoiler
[close]

Here is the gInventoryOver sprite that goes over everything (transparency, png)
Spoiler
[close]

Here is one of the inventory items (transparency, png)
Spoiler
[close]

gInventory is magic pink, no sprites. Note that if you plug in a sprite into gInventory's background, the pink around the inventory items disappears, but the pink around the btnInv_Hilite remains.

(PS: How do I "collapse" images so they dont take up the whole page?)
--All that is necessary for evil to triumph is for good men to do nothing.

Crimson Wizard

Quote from: General_Knox on Wed 11/09/2013 23:03:13
(PS: How do I "collapse" images so they dont take up the whole page?)

Use [ hide ][ /hide ] tag.

Crimson Wizard

#37
The problem is this: the alpha blending function treats background (Gui) "magic pink" (transparency color) as a normal color and merges foreground (e.g. button)) with it producing corresponding result.
"Additive Opacity" does not do that because it simply discards background RGB values and paints foreground over.

This would be, perhaps, fixed by completely abstaining from using magic pink on your sprites, but it is not so simple... The situation worsens, because AGS converts pixels with alpha=0 into magic pink when the sprite is imported.
This means that all your fully transparent 32-bit pixels become magic pink pixels. This is made to make alpha-sprites compatible with AGS drawing logic.
This is why the button blending still produces pink shades in the above example: the transparent area in the gInventoryOverlay is painted in magic pink in the engine.

The only solution I see is to add a special case to blending function which will deal with magic pink.
The question is, how to deal with it. If the background color is "fully transparent", this means that only the foreground color should be drawn. But if the foreground alpha is less than 1.0, the result should be ForegroundRGB * ForegroundAlpha... is it? This means that the more transparent foreground is, the darker colors this will produce. Probably, this will be the same as if the background color was ARGB 00-00-00-00 (the foreground colors merging with black).
Is this correct/acceptable? Any thoughts on this?

Snarky

#38
Ah damn! My fault. There's something wrong with the formulas I gave earlier; the combined_rgb value calculation assumes the back.rgb is opaque:

Code: AGS
combined_alpha = 1 - (1-front.alpha)*(1-back.alpha);
combined_rgb = front.rgb * front.alpha + back.rgb * (1 - front.alpha);  // This is wrong!


Off the top of my head, I think the correct calculation is more like:

Code: AGS
combined_rgb = (front.rgb * front.alpha + back.rgb * (1 - front.alpha) * back.alpha) / combined_alpha;  // Now verified


Sorry about that! I believe if you switch to this formula, it should also take care of the magic pink problem without any special case code.

Spoiler
Incidentally, this is why many graphics formats store the rgb values premultiplied with the alpha. In that format, that last calculation really does become simply:

Code: AGS
combined_rgb_premult = front.rgb_premult + back.rgb_premult * (1 - front.alpha);
[close]

Edit: I've had a chance to think it over, and also check with Wikipedia (see the final formula in the Description section), and yes, this is the correct formula.

Knox

I came across another bug since upgrading to 3.3 but I guess its related to the same alpha issue you're currently working on (?)

In AGS Draconian r7, I have a mini-game where you cut the grass with a tractor. The room background is the "cut" grass, and over that I placed 12 characters (4 per row, 3 rows) that are zones of "long grass", and 12 characters underneath them for "long grass shadow". None of the sprites are using alpha. When the player goes over one of the zones (character), I drawString with magic pink to "eat through" the character's long grass sprite, revealing the cut grass underneath. I also do the same to the "shadow" character's sprite, only offset to give the illusion of depth. Here is a part of the code:
Code: ags
    
    DrawingSurface *dsCutGrass_A = this.GetDrawingSurface();
    dsCutGrass_A.DrawingColor = COLOR_TRANSPARENT;
    //dsCutGrass_A.DrawCircle(iMowerX+iXzoneAdjust+iRd, iMowerY+iYzoneAdjust+iRd, iMowerRadius);
    dsCutGrass_A.DrawString(iAdjX, iAdjY, eFontMowerCutter, sLt); //M=25% N=50% //O=100%
    dsCutGrass_A.Release();  
   
sLt is "J" in the font "eFontMowerCut" (I replaced the "J" with a circle of cut grass.

Works in Draconian r7:
Spoiler
[close]

Not working in 3.3 (any mode doesn't matter, still get this blue color):
Spoiler
[close]
--All that is necessary for evil to triumph is for good men to do nothing.

SMF spam blocked by CleanTalk