Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » "Average" blending

This thread is locked; no one can reply to it. rss feed Print
 1   2 
"Average" blending
Bruce Pascoe
Member #15,931
April 2015
avatar

I can't figure out a way to do this using any Allegro's provided blend modes. Is there a set of parameters I can pass to al_set_blender() to average the two pixels, like this?

dest.red   = (dest.red   + src.red)   / 2
dest.green = (dest.green + src.green) / 2;
dest.blue  = (dest.blue  + src.blue)  / 2;

al_set_blend_mode(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE) gives me the addition, but I don't see a way to represent the division by two at the end.

beoran
Member #12,636
March 2011

How about using al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_ONE), and then make sure that both source images have 50% alpha set? Or draw with al_draw_tinted_bitmap with a tint that has 0.5 for all it's values, like is done in this thread: https://www.allegro.cc/forums/thread/612304

Bruce Pascoe
Member #15,931
April 2015
avatar

The thing is that I need it to work in the general case, as I am emulating an existing game engine (Sphere). My use case for Allegro is... well, quite a bit broader in scope than the norm. :) It's served me very well so far, but there are a few things like this that trip me up.

The other thing I'm having an issue with: I need some way to set the alpha channel unconditionally to 255 for blended pixels. Can that be done?

RPG Hacker
Member #12,492
January 2011
avatar

This could be tough. As far as I know, most (if not all) GPUs only support certain preset blend settings that you can combine to create your blend operation. I don't think there is an average blend setting, so you'll most likely have to do it manually. One thing you could do: render your whole game into a bitmap, then, whenever you need blending, pass this bitmap (let's call it "destination") and your source bitmap to a shader and do all the blending inside the pixel shader. Oh well, maybe it's not that tough after all. In any case, you'll most likely have to use shaders. I don't think there is another efficient way, unless you consider going with the %50 alpha solution.

I need some way to set the alpha channel unconditionally to 255 for blended pixels. Can that be done?

How about just using a bitmap without alpha channel as your target bitmap? Effectively this will just not writ anything to the alpha channel at all. If you access such a texture from a shaders, as far as I know, the alpha channel will always return 1.0.

beoran
Member #12,636
March 2011

Hmm, could you provide a few examples of the desired effects? Inputs and desired output? In the past I've found that Allegro blending is very powerful but not always straightforward. I think what you want could very well be possible, but it's easier to see what you want through examples.

Bruce Pascoe
Member #15,931
April 2015
avatar

Okay, well first off, the averaging. That isn't a big deal to me, I don't personally use it but it's something that Sphere supports so I'd have to emulate it for full compatibility. It would be very easy to implement if we had an ALLEGRO_HALF blend op:

al_set_blender(ALLEGRO_ADD, ALLEGRO_HALF, ALLEGRO_HALF);

But sadly, such a thing doesn't exist. :(

The second effect however, is VERY useful, and I personally make use of it in my own Sphere games. Here's the code for Sphere's usual mode of blending:

void Blend3(destT& d, srcT s, int alpha)
{
    d.red   = (s.red   * alpha + d.red   * (255 - alpha)) / 255;
    d.green = (s.green * alpha + d.green * (255 - alpha)) / 255;
    d.blue  = (s.blue  * alpha + d.blue  * (255 - alpha)) / 255;
}

inline void blendRGBA(RGBA& dest, RGBA src)
{
    Blend3(dest, src, src.alpha);
    dest.alpha = 255;
}

This performs traditional alpha blending on the RGB components, but sets any pixels touched to fully opaque. This is useful as it allows you to do stuff like this:

textSurface = new Surface(320, 36, new Color(0, 0, 0, 0));
for (i = 0; i < 3; ++i) {
    font.setColorMask(textColor);
    textSurface.drawText(font, 5, i * 12, textLines[i]);
}

// later on...
textSurface.blit(textbox_x, textbox_y);

When that surface is rendered, only the text is visible and everything else remains transparent. Which in turn allows effects like this:

{"name":"Untitled.png","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/5\/6\/56129637a2a3df511fc5a2bf70f399c3.png","w":656,"h":519,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/5\/6\/56129637a2a3df511fc5a2bf70f399c3"}Untitled.png

Note the fade-in effect on the end of a line of text. This is done by rendering the text to a transparent surface (which makes the text opaque but leaves the rest transparent), then switching to subtractive blending and drawing a gradient over the line with alpha going from 0 to 255, making the end of the line gradually transition from opaque to invisible. This is a difficult effect to achieve with Allegro at present.

beoran
Member #12,636
March 2011

ALLEGRO_HALF isn't possible directly because such blending functionality doesn't exist directly in OpenGL nor in DirectX. The blending functions are mostly a thin wrapper around glBlendFunc and glBlendEquation or SetRenderState(D3DRS_*BLEND*, ...). The workaround is to make the source bitmap half transparent by filling the alpha channel only with 0.5 alpha. The function al_set_separate_blender() will be useful for that.

As for the fade in effect, I'm experimenting how to do it. But I think it's certainly possible if I'm allowed to modify the text surface and draw the gradient on it.

RPG Hacker
Member #12,492
January 2011
avatar

Thinking about this, in case you're going with shaders anyways, you can get this much easier than I described in my previous post. You don't actually even need to render to texture for that. Just set up your blend state as

al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA)

And then, in your pixel shader, just return the unmodified color of a pixel except with the alpha channel set to 0.5. That should already give the desired effect if the blend state is set up correctly and the sprites are drawn in the correct order. Of course you can still render to an RGB bitmap, as described above, to eliminate the the alpha channel in your destination image.

Bruce Pascoe
Member #15,931
April 2015
avatar

All these solutions would be great, if I were making a standalone game. Unfortunately, I'm not (well, I AM, but that's a secondary goal)--I'm trying to replicate the blend semantics of an existing general-purpose game engine. So far that has gone more than well (my engine is at v1.4 already :) ), but sometimes little things like this trip me up. Ultimately it's not a big deal, I'm at the point now where minisphere is stable, I'm just trying to fix the areas where it deviates from the original engine. If at the end of the day it turns out what I want is impossible, no harm done.

That said, I found out yesterday that the averaging is quite possible using glBlendFunc set to GL_CONSTANT_COLOR and sent a PR to implement support for it in Allegro:
https://github.com/liballeg/allegro5/pull/15

D3D has similar functionality (D3DBLEND_BLENDFACTOR). So with this, to average src and dest, you would do:

al_set_blender(ALLEGRO_ADD, ALLEGRO_CONSTANT_COLOR, ALLEGRO_CONSTANT_COLOR);
al_set_blend_color(al_map_rgb(128, 128, 128, 255));

Replicating the "set dest alpha to 1.0" behavior still proves impossible however. :( Why aren't Blend Shaders a thing?

edit: Well, I got close to a "set alpha to 255" blender, anyway. It's not perfect, but much better than what I was using. The blend flags I ended up using, for the curious:

al_set_separate_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA,
  ALLEGRO_ADD, ALLEGRO_INVERSE_DEST_COLOR, ALLEGRO_ONE);

beoran
Member #12,636
March 2011

The feature of the pull request is interesting but the pull request itself won' t be acceptable, I'm afraid. Please remove the .gitignore, and add at least one example such as ex_blend_color.c Also does this work on all platforms including the mobile ones as well?

Good to hear you found a useful combination. Cloning an existing engine is hard to do if you want to keep the effects completely identical. I'm glad to hear Allegro has been of use.

Bruce Pascoe
Member #15,931
April 2015
avatar

Without the .gitignore, Git wants to commit all the CMake cruft, why is it not acceptable?

I can't possibly test on EVERY platform though, especially not mobile.

beoran
Member #12,636
March 2011

We don't have a gitignore. Please don't use git commit -a :)

Also , you don't have to test yourself, but you'll have to ask others to test this for you. That's where the example program comes in.

Bruce Pascoe
Member #15,931
April 2015
avatar

I actually use GitHub for Windows for the most part, only dropping to the shell for complex stuff. And by default it selects everything for each commit, so I have to uncheck them all and then sift through the list for the actual changes. It's quite annoying.

I'm really not much of a commandline person.

I'll see about whipping up an example program.

Thomas Fjellstrom
Member #476
June 2000
avatar

You can just unstage the git ignore files, and other files that aren't part of your feature.

I actually use GitHub for Windows for the most part, only dropping to the shell for complex stuff. And by default it selects everything for each commit, so I have to uncheck them all and then sift through the list for the actual changes. It's quite annoying.

And that's where the cli is a much better interface ;)

Quote:

I'll see about whipping up an example program.

I think there is an example for the blending already, you could probably add the new mode to that, I think.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Bruce Pascoe
Member #15,931
April 2015
avatar

The problem with CLI is that I don't always remember exactly which files I changed, and if "git status" lists hundreds of build files (500+ at my last count), I can't view what changed any more easily than the GUI.

I do wonder if I do gitception (add the .gitignore to .gitignore), can I get the benefit without committing it... Hm. Something to try later.

Thomas Fjellstrom
Member #476
June 2000
avatar

IIRC you can just remove entire directories at a time with the CLI.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Bruce Pascoe
Member #15,931
April 2015
avatar

Okay, I posted a better pull request.
https://github.com/liballeg/allegro5/pull/16

No gitignore. a much more comprehensive implementation (OGL, D3D, software) and entries in ex_blend2 to see it in action. I also summarized the API additions in the PR summary.

Polybios
Member #12,293
October 2010

Maybe I haven't read the thread carefully, but isn't that the reason for using build directories outside your source tree, i. e. out-of-source builds?

beoran
Member #12,636
March 2011

That looks better! I'll try it out on Linux as soon as I can!

Mark Oates
Member #1,146
March 2001
avatar

The CLI is better. GitHub for Windows is just silly.

Bruce Pascoe
Member #15,931
April 2015
avatar

You clearly haven't seen me with a mouse. :) I can type around 100wpm on a good day, and I'm STILL faster with a mouse than I am on the command line. Plus it helps to see the diffs right in front of me before I pull the trigger on a commit. Viewing diffs in the shell = not fun.

Keep in mind I grew up with MS-DOS so I do know my way around a command prompt. It's just not my preferred interface. ;)

Thomas Fjellstrom
Member #476
June 2000
avatar

Viewing diffs in the shell = not fun.

I dunno, in my shell I get working scrolling and syntax highlighting/coloring. \o/

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Polybios
Member #12,293
October 2010

MS-DOS so I do know my way around a command prompt

If your concept of "command prompt" is based on MS-DOS, then you'd be surprised what you can do with a UNIX shell... not to speak of vim and friends...

Bruce Pascoe
Member #15,931
April 2015
avatar

Yeah, don't get me wrong, I won't hesitate to drop to bash (NOT Command Prompt) for complex stuff like merges, cherry-pick, bisect (things which are intrinsically serial)... But for normal day-to-day commit and branch creation I find the GUI superior.

We'll just have to agree to disagree here, I think I've derailed the thread enough (which is ironic since it's my own thread, and also because there's a guy with a Thomas the Tank Engine avatar here :P).

Thomas Fjellstrom
Member #476
June 2000
avatar

I just have to say I haven't yet used a gui interface to a version control system that actually worked reasonably well day to day. They often assume certain workflows that don't match up with my own, and cause a lot of unnecessary work.

there's a guy with a Thomas the Tank Engine avatar here

Someone put that in a thread a while back and it was so good I had to make it my avatar. :D8-)

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

 1   2 


Go to: