[A5] Front-to-back Alpha Blending
abenthy

Hello,

for my GUI code its essential that what I draw last gets drawn above everything drawn after it. So I want to reverse the usual painters algorithm.

I tried figuring out how to do this using al_set_blender or al_set_separate_blender, but I failed.

Can someone help me out?

al_set_blender( ? ? ? );
al_draw_filled_rectangle( ... button ... );
al_draw_filled_rectangle( ... label ... );

// I want this to be behind the widgets drawn above.
al_draw_filled_rectangle( ... here comes the frame ... );

Trent Gamblin

Draw them in the order you want, simple as that. Blending won't help. When you draw something, OpenGL/DX renders pixels to a frame buffer. There is only one framebuffer so once those pixels are there, anything you draw goes on top of them.

Arthur Kalliokoski

If you were using OpenGL you could set an orthogonal perspective and use the depth buffer along with 3d vertices, incrementing the Z value a bit for everything you drew.

Edgar Reynaldo
abenthy said:

for my GUI code its essential that what I draw last gets drawn above everything drawn after it.

This does not make sense - there can't be anything drawn after the last one gets drawn by definition of the term 'last'. Like Trent said, draw from the bottom up. There's no other way to do it.

Elias

Besides the depth buffer as Arthur said, you could also use the stencil buffer.

jmasterx

Why not just draw them recursively, I simply do:
baseContainer->paintChildren();

and then the whole gui is painted!

#SelectExpand
1void AguiWidget::paintChildren(const AguiPaintEventArgs &paintargs ) 2{ 3 stackOffset = paintargs.graphics()->getOffset(); 4 stackRects = paintargs.graphics()->getClippingStack(); 5 recursiveDrawChildren(this,isEnabled(),paintargs.graphics()); 6 paintargs.graphics()->setClippingStack(stackRects,stackOffset); 7} 8 9void AguiWidget::recursiveDrawChildren( AguiWidget *root, bool enabled, 10 AguiGraphicsManager *graphicsContext ) 11{ 12 //recursively calls itself to render widgets from back to front 13 14 if(!root->isVisible()) 15 { 16 return; 17 } 18 19 bool widgetEnabled = root->isEnabled(); 20 21 if(enabled == false) 22 { 23 widgetEnabled = false; 24 } 25 26 if(root != this) 27 { 28 root->clip(AguiPaintEventArgs(enabled,graphicsContext)); 29 30 root->paint(AguiPaintEventArgs(enabled,graphicsContext)); 31 32 if(root->isPaintingChildren()) 33 { 34 return; 35 } 36 } 37 38 for(std::vector<AguiWidget*>::iterator it = 39 root->getPrivateChildBegin(); 40 it != root->getPrivateChildEnd(); ++it) 41 { 42 recursiveDrawChildren(*it,widgetEnabled,graphicsContext); 43 } 44 for(std::vector<AguiWidget*>::iterator it = 45 root->getChildBegin(); 46 it != root->getChildEnd(); ++it) 47 { 48 recursiveDrawChildren(*it,widgetEnabled,graphicsContext); 49 } 50 51}

abenthy

Thanks for your answers so far, really! I read them all carefully.
But I probably described very badly what I want to do, so to give you some details:

  • I'm coding an Immediate Mode GUI (like the one in Unity3D, this means no retainted state in a class hierarchy), this is a complicated/new subject to most GUI programmers. Here is a cool tutorial:

Sol IMGui Tutorial

  • My problem with the implementation is quite good explained here:

Molly Rocket Immediate Mode GUI Forums

  • The problem is that I can only draw the frame background image after the buttons/labels inside of it are drawn.

  • Take a look at this example code, to see how it works:

gui.begin_frame(); // We do not yet know how big the frame will have to be.
// We also do not know if it's active, because one of the buttons/labels
// could become active, but we do not know about them yet.

gui.label("MyLabel");
if(gui.button("MyButton")) {
   printf("The button was pressed!\n");
}

// Now that we _do_ know about the widgets in the frame, we could draw the frame.
// but this place doesn't really fit the rendering order.
gui.end_frame();

  • I do know that there are other solutions to this (buffer images, render queues). Anyway, I would like to know if there is a way to draw the frame right by just using blending in A5. Like sean from Molly Rocket points out:

Quote:

4. Process widgets front-to-back and draw with the crazy front-to-back blend mode that still lets you use alpha values for anti-aliased edges.

Trent Gamblin

Destination alpha is a possibility but I don't think that is very well supported by video cards. Especially for the framebuffer itself... I don't know about using a buffer with destination alpha though it seems clear you don't want to do that.

Thread #607035. Printed from Allegro.cc