GUIs with alpha-masked buttons - how does it REALLY work?

Started by naltimari, Wed 14/05/2008 07:46:49

Previous topic - Next topic

naltimari

To me, transparency in GUIs is the most confusing aspect of AGS as of now. I dont fully grasp the way AGS does GUIs with transparency yet, so I decided to write this post to see if someone can shed some light on this subject.

I know the first 'stepping stone' is to apply a background which has an alpha channel, but what I want to clarify is what happens when you want other images on top of it, like transparent buttons, mouseovers, etc.

This is what I found, so far (I will correct any wrong information in future posts):


  • When you import a sprite, there is an option to use the 'top-left pixel' as transparency, and this, as I understand it, RE-WRITES some pixels as magenta in the RGB channels of the sprite. So, you should only choose 'Leave as is' when you're dealing with alpha-masked sprites. Note: If there is an alpha channel in the file, and we specifically told AGS to use it, why should we bother? :-[

  • any sprites which DON'T have an alpha channel will INHERIT the transparency from the background ??? The ones that DO have an alpha channel get their transparency used. If you think this is strange, keep reading...

  • the REAL tricky part is when alpha-masked sprites OVERLAP inside the GUI... well... I couldn't figure out exactly how this works... I *think* the RGB bits of the sprites (including the background) are drawn on a RGB buffer, from 'backmost' to 'frontmost', while the alpha bits gets drawn to a SEPARATE 8-bit buffer. Then, the two buffers are assembled to form a 32 bit image which is sent to the GUI.
I hope CJ can clarify the last statement, since I'm not sure...

Pumaman

Quote from: naltimari on Wed 14/05/2008 07:46:49
  • When you import a sprite, there is an option to use the 'top-left pixel' as transparency, and this, as I understand it, RE-WRITES some pixels as magenta in the RGB channels of the sprite. So, you should only choose 'Leave as is' when you're dealing with alpha-masked sprites.
This is true, however if the sprite has an alpha channel then the alpha is used instead of the RGB transparency for display purposes. However, when AGS is calculating whether an object is under the mouse and things like that, it still uses the RGB transparency value. Therefrore, ideally the RGB-transparent area and the 100%-alpha area on the sprite should be the same.

Quote
  • any sprites which DON'T have an alpha channel will INHERIT the transparency from the background ??? The ones that DO have an alpha channel get their transparency used. If you think this is strange, keep reading...
  • the REAL tricky part is when alpha-masked sprites OVERLAP inside the GUI... well... I couldn't figure out exactly how this works... I *think* the RGB bits of the sprites (including the background) are drawn on a RGB buffer, from 'backmost' to 'frontmost', while the alpha bits gets drawn to a SEPARATE 8-bit buffer. Then, the two buffers are assembled to form a 32 bit image which is sent to the GUI.
When drawing GUIs, AGS renders the GUI internally to a temporary bitmap, which it keeps in memory. This temporary bitmap is then drawn to the screen every game loop. If it has an alpha channel, it will be drawn as such.

But what this means is that when the GUI controls are being drawn, they are being drawn onto a temporary bitmap and not onto the screen itself. If the image being drawn to the temporary bitmap has an alpha channel then it will be copied, if not then the alpha value that is already there will remain.

I appreciate that this is rather confusing, because intuitively you'd expect the background to be drawn to the screen with its alpha channel, followed by the controls afterwards with their individual alpha values.

The reason AGS works this way is for performance reasons, but I might do some experimentation to see whether on modern PC's this is still an issue.

freshpaint

So does this mean that when I import a sprite with an alpha channel, I should NOT use "Leave as is" as the option?  That I should chose one of the image corners as the "transparent" color too?


Pumaman

It depends what you use the sprite for, but if you want it to work with Pixel-Perfect Click Detection then yes, choose a valid transparency setting.

EDIT: Also if you're using it as a GUI button or something, then because the rendering to the temporary bitmap is not done using the alpha channel it would need a valid transparent area to render correctly.

freshpaint

Incredible!  It works!  Thanks, everyone.

To sum up: I have an inventory gui created with background transparency (color = 0), an alpha blended sprite as background image, and my inventory sprites imported WITH alpha channel AND saying that top left pixel is transparent.  Inventory items show up correctly, regardless of whether they were imported with or without alpha channel.

Will see if importing saying top left pixel is transparent also solves my overlay problem (was showing up with black background too).

EDIT: the alpha sprite shows up correctly on the original default inventory too.  So the trick is simply never to import with "leave as is" if there are any transparent areas.

naltimari

Quote from: Pumaman on Wed 14/05/2008 19:35:52
Therefrore, ideally the RGB-transparent area and the 100%-alpha area on the sprite should be the same.

I do my transparent sprites in Photoshop, usually on single layer, with no background layer, and save it as a PNG file. If I open the PNG in The Gimp, or even Firefox, the transparent areas dont show, like it should be, so I guess there's nothing wrong with this method.

However, I noticed that in AGS, the transparent areas DO SHOW, if the sprite is inside a GUI, and if you chose 'leave as-is' in the import settings. I coded up a real quick and dirty game ('borrowed' from SSH's QueueBGSpeech module demo, IIRC) to show the results. Since the sprites are there, and the originals (the PNG files) are in the zip, you can compare the 'ins' and 'outs'.

You can download it from here: http://www.i9acao.com.br/ags/AlphaMaskGUIs.zip

I did this because maybe there is some bug hiding in AGS somewhere, which nobody has bumped into yet because using alpha-masked buttons on GUIs is rare, I guess.

Please pay special attention to the two characters, male and female, which are alpha-masked and overlapped inside the GUI. There is shadow underneath their feet, and the center of the shadow spot has a 'hole' when the sprites are place inside the GUI.

Also, the area where she overlaps the male character has 'wiped out' the pixels from the sprite behind her! Isn't this strange?

Quote
But what this means is that when the GUI controls are being drawn, they are being drawn onto a temporary bitmap and not onto the screen itself.

Ok, but it seems that the alpha masks are not being used like they should when the sprites are drawn on the off-screen bitmap.

Quote
I appreciate that this is rather confusing, because intuitively you'd expect the background to be drawn to the screen with its alpha channel, followed by the controls afterwards with their individual alpha values. The reason AGS works this way is for performance reasons, but I might do some experimentation to see whether on modern PC's this is still an issue.

I understand, and I'm sure there are workaround to these situations, I mean, I can always change my GUI, but my intent is to point out some strange behaviour that was overlooked.

naltimari

Quote from: naltimari on Fri 16/05/2008 07:02:32
You can download it from here: http://www.i9acao.com.br/ags/AlphaMaskGUIs.zip



Ok, I decided to post a snapshot of it for your convenience...  ;)

The window on the top-left, with the black embossed border, is the GUI. The black frame is the background sprite, and it has an alpha mask suited to make the interior semi-transparent and the borders opaque. All the elements inside the GUI (apart from the text labels) are buttons with images applied to them.

Noteworthy stuff:

1. The leftmost 'check-mark' inside the GUI has artifacts around it, which don't show on the next two versions to the right, even thought all of the three were imported from the SAME png file. The only difference was the import method;

2. The female character has an alpha-mask to provide a shadow beneath her feet; note that, right in the middle of the shadow spot, there is a 'hole' which does not show in the 'object version' of the sprite. The same happens to the male character.

3. Note that the character sprites 'overwrote' the pixels in the border of the GUI (the opaque area) to black, BUT kept the transparent areas of the background intact ???

4. The same 'pixel overwriting' happens at the area in which the female 'overlaps' the male character, inside the GUI. Compare this to how they (correctly) behave in their 'object version', at the bottom of the room.

I cant help but feel ???...

Any comments are welcome.

naltimari

I forgot the mention this in the last post - the GUI is draggable, as well as all the controls inside it.

I thought that maybe this 'feature' would help to diagnose the problem.

JpSoft

What i learned until now (fixing a trouble like this, you can read that in the begineers forums) is:

- If you do not assign an image to the buttons, the button will ALWAYS show solid; the same to sliders and text inside labels in a translucent GUI.

- When the game is runing in a colour depth less that 32 bits, any alpha channel will be show invisible; it could give terrible results for the GUI. (to fix this, i set GUI background color > 0, so it will be visible in a low colour depth systems, and translucent in 32 bit mode, avoiding you to include extra routines)

I will try the same you did and will let you now.

Jp

Snarky

Quote from: naltimari on Fri 16/05/2008 21:17:33
1. The leftmost 'check-mark' inside the GUI has artifacts around it, which don't show on the next two versions to the right, even thought all of the three were imported from the SAME png file. The only difference was the import method;

So can't you just not use that import method, then?

Quote from: naltimari on Fri 16/05/2008 21:17:33
4. The same 'pixel overwriting' happens at the area in which the female 'overlaps' the male character, inside the GUI. Compare this to how they (correctly) behave in their 'object version', at the bottom of the room.

I would think that this is caused by what CJ explained:

Quote from: Pumaman on Wed 14/05/2008 19:35:52
But what this means is that when the GUI controls are being drawn, they are being drawn onto a temporary bitmap and not onto the screen itself. If the image being drawn to the temporary bitmap has an alpha channel then it will be copied, if not then the alpha value that is already there will remain.

Since the sprites have alpha channels, when you copy the second sprite you overwrite the alpha channel of the first sprite, so all the areas that are transparent in the second sprite become transparent and "disappear".

naltimari

Quote from: Snarky on Sat 17/05/2008 15:40:45
Quote from: naltimari on Fri 16/05/2008 21:17:33
1. The leftmost 'check-mark' inside the GUI has artifacts around it

So can't you just not use that import method, then?

Sure, but as I said, I think that behaviour is a bug (those artifacts shouldn't show up), and so I was trying to help. I'm a software developer too, so I like when someone tries to help me by trying to isolate the problem for me instead of just saying 'it does not work as I expect'.

Quote from: Snarky on Sat 17/05/2008 15:40:45
Since the sprites have alpha channels, when you copy the second sprite you overwrite the alpha channel of the first sprite, so all the areas that are transparent in the second sprite become transparent and "disappear".

Hmm... I guess you're right, so the copy operation should not 'overwrite' the alpha channel, but 'add' to it.

This could be done with the scripting interface, if AGS provided a way for us to draw directly on alpha channels. Right now we can copy a transparency mask from one sprite to another, but we can not alter the mask in any way.

I made a suggestion a while ago about a 'GetDrawingSurfaceForAlphaChannel()' that would return a DrawingSurface*, then we could alter the transparency of any sprite.

Pumaman

Ok, I've been having a play with this GUI alpha stuff, and as long as the temporary bitmap is in use, I don't think there's an ideal solution.

This is with the sprites drawn preserving the background alpha:



Ignore sprite alpha, replace with background:



Replacing the background alpha channel with that of the sprites:



Additive alpha, where the background's alpha is used as the base and then other sprites are alpha-drawn on top of it:



Differential conditional alpha, where the sprite alpha is used if it is more opaque than the background, otherwise the background is used:




Depending on what effect you want, I don't think any of these are really an appropriate solution because of the use of the temporary bitmap.

So I turn it over to you guys -- are any of these results an appropriate way for GUI Alpha to work?

naltimari

The closest to the ideal is the 'differential' one... But even this is not '100%' right, the character shadows are missing. Ok, I'm convinced... it's not that simple to keep 'temporary bitmap' approach with transparency.

Would it be too difficult to extend DrawingSurfaces to alpha channels, like I suggest in my previous post?

Or, another idea is to implement a CopyTransparencyMask() method that takes a sprite and applies it to another sprite's alpha channel (using the luminance of the pixels as the transparency).

JpSoft

In my opinion the best way is the diferential one too.

Jp

Pumaman

I was just experimenting with another method, doing an additive alpha channel where the opacity of the sprites is added to that of the background:



I think this actually looks reasonable (I still need to fix the non-alpha one) -- but the question is, is this sort of approach suitable for all you guys who use alpha channel GUIs, or would this be fixing one problem only to cause another?

naltimari

Quote from: Pumaman on Sun 18/05/2008 19:53:54
I was just experimenting with another method, doing an additive alpha channel where the opacity of the sprites is added to that of the background:

I think this actually looks reasonable (I still need to fix the non-alpha one) -- but the question is, is this sort of approach suitable for all you guys who use alpha channel GUIs, or would this be fixing one problem only to cause another?

It looks very good to me!! Can't say that it won't cause any problems though... Maybe you should add a drop-down to the GUI panel, asking which method would be used for alpha-blending (backward compatible, additive, differential, etc).

freshpaint

What's the scoop with the thin blue border that sometimes shows up and sometimes doesn't?  Any way to turn it off/on independent of the kind of background/alpha/method imported, etc. etc. used?  You can give it a color in the gui dialog, but sometimes seems to get overwritten, sometimes not.

(fyi, the additive experiment looks great, but only you know what has to go into such a fix and what else it might disturb!).

Thank you so much for working on this!



JpSoft

Quote from: Pumaman on Sun 18/05/2008 19:53:54
I think this actually looks reasonable (I still need to fix the non-alpha one) -- but the question is, is this sort of approach suitable for all you guys who use alpha channel GUIs, or would this be fixing one problem only to cause another?

I believe it will fix almost every situation, but of course the whised situation is actually that the programmer can manipulate the alpha channels in the script (as natimari explained)

I solved my GUI in the way natimari explained: i just added an empty alpha channel to all the images for the buttons, imported it "leave as is" and it worked well for me (since my buttons images do not need an alpha channel like natimari´s GUI)

Quote from: naltimari on Sun 18/05/2008 20:14:26
It looks very good to me!! Can't say that it won't cause any problems though... Maybe you should add a drop-down to the GUI panel, asking which method would be used for alpha-blending (backward compatible, additive, differential, etc).

Great idea. Or just add an alternative function called: Alpha_Channel_Method so it could be easily set in the script.

Jp

PS Thanks natimari for your suggestion.

Pumaman

Thanks for your feedback, I think what I'll do is add an option to the General Settings whereby you can choose the GUI Alpha Style between "Classic" mode (for any existing games that rely on the current behaviour) and the new additive-opacity mode ... hopefully that should account for everyone.

QuoteWhat's the scoop with the thin blue border that sometimes shows up and sometimes doesn't?

Oh, that was just me turning on the GUI Border for testing purposes ... just ignore it.

SMF spam blocked by CleanTalk