Page 1 of 1

[bug] Draw fonts to RTT with alpha

Posted: Tue Feb 28, 2012 12:44 pm
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.

Re: [bug] Draw fonts to RTT with alpha

Posted: Thu Mar 01, 2012 9:01 am
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

Re: [bug] Draw fonts to RTT with alpha

Posted: Thu Mar 01, 2012 12:00 pm
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?

Re: [bug] Draw fonts to RTT with alpha

Posted: Fri Mar 02, 2012 5:45 pm
by REDDemon
maybe alpha to coverage? is your RTT the same size of the screen?

Re: [bug] Draw fonts to RTT with alpha

Posted: Fri Mar 02, 2012 10:09 pm
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.

Re: [bug] Draw fonts to RTT with alpha

Posted: Sat Mar 03, 2012 8:19 pm
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

Re: [bug] Draw fonts to RTT with alpha

Posted: Tue Mar 06, 2012 12:44 pm
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?

Re: [bug] Draw fonts to RTT with alpha

Posted: Tue Mar 06, 2012 7:38 pm
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

Re: [bug] Draw fonts to RTT with alpha

Posted: Wed Mar 07, 2012 10:52 am
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() )

Re: [bug] Draw fonts to RTT with alpha

Posted: Wed Mar 07, 2012 12:26 pm
by REDDemon
you are wellcome :)