[bug] Draw fonts to RTT with alpha

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.
Post Reply
RdR
Competition winner
Posts: 273
Joined: Tue Mar 29, 2011 2:58 pm
Contact:

[bug] Draw fonts to RTT with alpha

Post by RdR »

There is a bug when drawing fonts with alpha to a RTT
First row of text are drawn to a RTT, second normal font drawing.
I used 4 font supplied in irrlicht.

Image

Simple testcase:

Code: Select all

 
#include <irrlicht.h>
#include "driverChoice.h"
 
using namespace irr;
 
// Draw fonts function
void drawFonts(gui::IGUIEnvironment* env, irr::u32 y) {
        gui::IGUIFont* font = env->getSkin()->getFont();
        for (irr::u32 i = 0; i < 4; i++) {
 
                // Get font
                if (i == 1) {
                        font = env->getFont("fontlucida.png"); // Has alpha
                } else if (i == 2) {
                        font = env->getFont("fonthaettenschweiler.bmp");
                } else if (i == 3) {
                        font = env->getFont("fontcourier.bmp");
                }
 
                // Draw text
                font->draw(L"Lorem ipsum dolor", core::recti(10 + (150 * i), y, 100 + (150 * i), y + 20), video::SColor(255, 255, 255, 255));
                font->draw(L"Lorem ipsum dolor", core::recti(10 + (150 * i), y + 20, 100 + (150 * i), y + 40), video::SColor(255, 0, 255, 0));
                font->draw(L"Lorem ipsum dolor", core::recti(10 + (150 * i), y + 40, 100 + (150 * i), y + 60), video::SColor(255, 0, 0, 255));
                font->draw(L"Lorem ipsum dolor", core::recti(10 + (150 * i), y + 60, 100 + (150 * i), y + 80), video::SColor(255, 255, 0, 0));
                font->draw(L"Lorem ipsum dolor", core::recti(10 + (150 * i), y + 80, 100 + (150 * i), y + 100), video::SColor(255, 0, 0, 0));
        }
}
 
int main() {
        // ask user for driver
        video::E_DRIVER_TYPE driverType = driverChoiceConsole();
        if (driverType == video::EDT_COUNT)
                return 1;
 
        // create device with full flexibility over creation parameters
        // you can add more parameters if desired, check irr::SIrrlichtCreationParameters
        irr::SIrrlichtCreationParameters params;
        params.DriverType = driverType;
        params.WindowSize = core::dimension2d<u32>(1024, 768);
        params.Bits = 32;
        IrrlichtDevice* device = createDeviceEx(params);
 
        if (device == 0)
                return 1; // could not create selected driver.
 
        video::IVideoDriver* driver = device->getVideoDriver();
        scene::ISceneManager* smgr = device->getSceneManager();
        gui::IGUIEnvironment* env = device->getGUIEnvironment();
 
        if (!driver->queryFeature(video::EVDF_RENDER_TO_TARGET)) {
                printf("EVDF_RENDER_TO_TARGET not supported!!\n");
        }
 
        // Create RTT
        core::dimension2du dimension = core::dimension2du(800, 400);
        video::ITexture* texture = driver->addRenderTargetTexture(dimension, "RTT", video::ECF_A8R8G8B8);
 
        // Set window title
        core::stringw str = L"Driver: ";
        str += driver->getName();
        device->setWindowCaption(str.c_str());
        const video::SColor color = video::SColor(255, 255, 255, 255);
 
        while (device->run()) {
                if (device->isWindowActive()) {
                        if (texture) {
                                driver->setRenderTarget(texture, true, true, video::SColor(0, 0, 0, 0));
                                driver->draw2DRectangle(video::SColor(100, 0, 0, 0), core::recti(0, 0, 800, 400));
 
                                // Draw fonts
                                drawFonts(env, 0);
 
                                driver->setRenderTarget(0, false, false, 0);
                        }
 
                        driver->beginScene(true, true, video::SColor(255, 10, 10, 200));
 
                        smgr->drawAll();
 
                        env->drawAll();
 
                        // Draw RTT
                        driver->draw2DImage(texture, core::vector2di(0, 0), core::recti(0, 0, texture->getOriginalSize().Width, texture->getOriginalSize().Height), 0, color, true);
 
                        // Draw fonts normal
                        drawFonts(env, 200);
 
                        driver->endScene();
                }
        }
 
        device->drop();
        return 0;
}
 
 
This also occurs when creating new fonts which have alpha.
Both DirectX and OpenGL have this problem.
REDDemon
Developer
Posts: 1044
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

Re: [bug] Draw fonts to RTT with alpha

Post by REDDemon »

could be the texture filtering for the RTT? O_O if the texture has also alpha channel there are further options that need to be setted
Junior Irrlicht Developer.
Real value in social networks is not about "increasing" number of followers, but about getting in touch with Amazing people.
- by Me
RdR
Competition winner
Posts: 273
Joined: Tue Mar 29, 2011 2:58 pm
Contact:

Re: [bug] Draw fonts to RTT with alpha

Post by RdR »

REDDemon wrote:could be the texture filtering for the RTT? O_O if the texture has also alpha channel there are further options that need to be setted
Yes the texture has also a alpha channel (video::ECF_A8R8G8B8 color format) , what kind of options you mean?
REDDemon
Developer
Posts: 1044
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

Re: [bug] Draw fonts to RTT with alpha

Post by REDDemon »

maybe alpha to coverage? is your RTT the same size of the screen?
Junior Irrlicht Developer.
Real value in social networks is not about "increasing" number of followers, but about getting in touch with Amazing people.
- by Me
RdR
Competition winner
Posts: 273
Joined: Tue Mar 29, 2011 2:58 pm
Contact:

Re: [bug] Draw fonts to RTT with alpha

Post by RdR »

REDDemon wrote:maybe alpha to coverage? is your RTT the same size of the screen?
No, its just a part of the screen (see testcase in topic start).
Alpha to coverage? Not sure what you mean by that.
CuteAlien
Admin
Posts: 9702
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: [bug] Draw fonts to RTT with alpha

Post by CuteAlien »

What I think is happening: While rendering to the RTT the rendering calculation does correctly multiply the rgb's with the alpha's. The problem now is that it also writes the alpha-values in the texture. So when using that texture now again for drawing with alpha's the alpha's will be used a second time. But problem is - it's not easy to avoid this. If it wouldn't write the alpha's at all then it would stay transparent. If it would write an alpha of 255 in there it might look better in this case maybe. That could be done maybe with glBlendFuncSeparate... but that does not exist in my headers (too old gl?).

I got the idea for glBlendFuncSeparate from some similar discussion going on here: http://www.opengl.org/discussion_boards ... ber=257628
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
CuteAlien
Admin
Posts: 9702
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: [bug] Draw fonts to RTT with alpha

Post by CuteAlien »

I thought a little more about it. What you would need is rendering the font without alpha - but having the alpha-values written into the target-texture.
Only workaround I could think of for now would be adding a flag to font-rendering that allows ignoring alpha, rendering it twice (once with and once without alpha) and then copying the alpha-channel over to the render without alpha.
Anyone got a better idea?
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
REDDemon
Developer
Posts: 1044
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

Re: [bug] Draw fonts to RTT with alpha

Post by REDDemon »

CuteAlien wrote:I thought a little more about it. What you would need is rendering the font without alpha - but having the alpha-values written into the target-texture.
Only workaround I could think of for now would be adding a flag to font-rendering that allows ignoring alpha, rendering it twice (once with and once without alpha) and then copying the alpha-channel over to the render without alpha.
Anyone got a better idea?

I think that is not possible for multiple layers

If we draw multiple layer of GUI in the same render target we have to make a choice:

1)draw all GUI blending alpha
2)draw all GUI without alpha (as sad by you) and then render twice

in the 1st case all gui elements are correctly stacked but the final render target will look wrong (as in the screenshot because alpha is used twice )
in the 2nd case all gui elements will not stack properly, but if we render just 1 layer of GUI it will look correct in the final screen shot (enough for rendering fonts).

what about - precompute a different alpha for the fonts?. If the problem is double multiplication by the alpha value we can solve it by changing the IMage by doing SQRT on alpha values (of course first we have to convert 0..255 value to fit in ragne 0...1)..

this will at least save us from rendering the fonts twice. I will tri with FreeImageMixer and see what happens..

EDIT:

ok for now I was able to get 2 fonts identical. so success!

Code: Select all

 
#include <irrlicht.h>
#include "driverChoice.h"
 
using namespace irr;
 
// Draw fonts function
void drawFonts(gui::IGUIEnvironment* env, irr::u32 y) {
        gui::IGUIFont* font = env->getSkin()->getFont();
 
        font = env->getFont("../../media/fontlucida2.png");
        font->draw(L"fontlucida2", core::recti(10 + (150 * 0), y, 100 + (150 * 0), y + 20), video::SColor(255, 255, 255, 255));
 
        font = env->getFont("../../media/fontlucida.png");
        font->draw(L"fontlucida", core::recti(10 + (150 * 1), y, 100 + (150 * 1), y + 20), video::SColor(255, 255, 255, 255));
 
        font = env->getFont("../../media/fontlucida3.png");
        font->draw(L"fontlucida3", core::recti(10 + (150 * 2), y, 100 + (150 * 2), y + 20), video::SColor(255, 255, 255, 255));
 
        font = env->getFont("../../media/fontlucida4.png");
        font->draw(L"fontlucida4", core::recti(10 + (150 * 3), y, 100 + (150 * 3), y + 20), video::SColor(255, 255, 255, 255));
}
 
int main() {
        // ask user for driver
        video::E_DRIVER_TYPE driverType = driverChoiceConsole();
        if (driverType == video::EDT_COUNT)
                return 1;
 
        // create device with full flexibility over creation parameters
        // you can add more parameters if desired, check irr::SIrrlichtCreationParameters
        irr::SIrrlichtCreationParameters params;
        params.DriverType = driverType;
        params.WindowSize = core::dimension2d<u32>(1024, 768);
        params.Bits = 32;
        IrrlichtDevice* device = createDeviceEx(params);
 
        if (device == 0)
                return 1; // could not create selected driver.
 
        video::IVideoDriver* driver = device->getVideoDriver();
        scene::ISceneManager* smgr = device->getSceneManager();
        gui::IGUIEnvironment* env = device->getGUIEnvironment();
 
        if (!driver->queryFeature(video::EVDF_RENDER_TO_TARGET)) {
                printf("EVDF_RENDER_TO_TARGET not supported!!\n");
        }
 
        // Create RTT
        core::dimension2du dimension = core::dimension2du(800, 400);
        video::ITexture* texture = driver->addRenderTargetTexture(dimension, "RTT", video::ECF_A8R8G8B8);
 
        // Set window title
        core::stringw str = L"Driver: ";
        str += driver->getName();
        device->setWindowCaption(str.c_str());
        const video::SColor color = video::SColor(255, 255, 255, 255);
 
        while (device->run()) {
                if (device->isWindowActive()) {
                        if (texture) {
                                driver->setRenderTarget(texture, true, true, video::SColor(0, 0, 0, 0));
                                driver->draw2DRectangle(video::SColor(100, 0, 0, 0), core::recti(0, 0, 800, 400));
 
                                // Draw fonts
                                drawFonts(env, 0);
 
                                driver->setRenderTarget(0, false, false, 0);
                        }
 
                        driver->beginScene(true, true, video::SColor(255, 10, 10, 200));
 
                        smgr->drawAll();
 
                        env->drawAll();
 
                        // Draw RTT
                        driver->draw2DImage(texture, core::vector2di(0, 0), core::recti(0, 0, texture->getOriginalSize().Width, texture->getOriginalSize().Height), 0, color, true);
 
                        // Draw fonts normal
                        drawFonts(env, 200);
 
                        driver->endScene();
                }
        }
 
        device->drop();
        return 0;
}
 
 
mix:

Code: Select all

 
#include <ImageMixer>
 
IMAGE_MIXER_START(256,256);
 
Image im1;
Channel A;
im1.load("fontlucida.png");
A = im1.A();
 
//sqrt
im1.A() = sqrt(A);
im1.save("fontlucida2.png");
 
//pow to 2
im1.A() = A*A;
im1.save("fontlucida3.png");
 
IMAGE_MIXER_END();
 
 
 
fontlucida2 in the RTT was identical to fontlucida3 without RTT. (wich is the expected result because of double multiplication by alpha).
 
so if the expected font is fontlucida3. We must use fontlucida2.
 
The problem is that we start with fontlucida.
 
then...
 

Code: Select all

 
im1.A() = sqrt(sqrt(A));
im1.save("fontlucida4.png");
 
using "fontlucida4.png" as font. gives in the RTT the same result given by "fontlucida.png". If is enough for you you can still achieve your target of rendering fonts into a RTT without the need of using shaders or drawing twice. but you have todo an operation on the Alpha channel of the texture. I still don't know what will happen drawing something in more than 1 layer

Image

..infact trying to render 2 images on the same RTT with pre-computed alpha gives wrong result:
Image
Junior Irrlicht Developer.
Real value in social networks is not about "increasing" number of followers, but about getting in touch with Amazing people.
- by Me
RdR
Competition winner
Posts: 273
Joined: Tue Mar 29, 2011 2:58 pm
Contact:

Re: [bug] Draw fonts to RTT with alpha

Post by RdR »

REDDemon, thanks for your test case. :D
So by changing the fonts alpha I can achieve the same result.
But that only works when background stays the same ofcource, but that should work for TANK@WAR :mrgreen:
REDDemon wrote:
..infact trying to render 2 images on the same RTT with pre-computed alpha gives wrong result:
Everything drawn on an RTT with an alpha (<255) is going wrong (atleast the ones I tested like draw2Dline() )
REDDemon
Developer
Posts: 1044
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

Re: [bug] Draw fonts to RTT with alpha

Post by REDDemon »

you are wellcome :)
Junior Irrlicht Developer.
Real value in social networks is not about "increasing" number of followers, but about getting in touch with Amazing people.
- by Me
Post Reply