RenderTarget and drawTriangleList

You are an experienced programmer and have a problem with the engine, shaders, or advanced effects? Here you'll get answers.
No questions about C++ programming or topics which are answered in the tutorials!
Post Reply
caburfoot
Posts: 22
Joined: Mon Aug 08, 2011 6:15 am

RenderTarget and drawTriangleList

Post by caburfoot »

I've been blithely working on our app with Irrlicht and added the ability to use IGuiFont. No problem. Then they wanted it to be a scaled window. No problem. Added in a rendertargettexture and if ( ! fullscreen ) rendertotexture then draw the render target. But NO, mirrored and REALLY messes with the screen.

Investigation says that rendertextures should ALLWAYS and ONLY be rendered via draw2dImage() instead of the drawVerticesxxx variants (drawIndexedTrianglelist etc)

So I modified the UserInterface example to the following :

Code: Select all

 
/** Example 005 User Interface
 
This tutorial shows how to use the built in User Interface of
the Irrlicht Engine. It will give a brief overview and show
how to create and use windows, buttons, scroll bars, static
texts, and list boxes.
 
As always, we include the header files, and use the irrlicht
namespaces. We also store a pointer to the Irrlicht device,
a counter variable for changing the creation position of a window,
and a pointer to a listbox.
*/
#define _IRR_STATIC_LIB_ 1
#include <irrlicht.h>
#include "driverChoice.h"
 
using namespace irr;
 
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
 
#ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlichtd.lib")
#endif
 
// Declare a structure to hold some context for the event receiver so that it
// has it available inside its OnEvent() method.
struct SAppContext
{
        IrrlichtDevice *device;
        s32                             counter;
        IGUIListBox*    listbox;
};
 
// Define some values that we'll use to identify individual GUI controls.
enum
{
        GUI_ID_QUIT_BUTTON = 101,
        GUI_ID_NEW_WINDOW_BUTTON,
        GUI_ID_FILE_OPEN_BUTTON,
        GUI_ID_TRANSPARENCY_SCROLL_BAR
};
 
/*
The Event Receiver is not only capable of getting keyboard and
mouse input events, but also events of the graphical user interface
(gui). There are events for almost everything: Button click,
Listbox selection change, events that say that a element was hovered
and so on. To be able to react to some of these events, we create
an event receiver.
We only react to gui events, and if it's such an event, we get the
id of the caller (the gui element which caused the event) and get
the pointer to the gui environment.
*/
class MyEventReceiver : public IEventReceiver
{
public:
        MyEventReceiver(SAppContext & context) : Context(context) { }
 
        virtual bool OnEvent(const SEvent& event)
        {
                if (event.EventType == EET_GUI_EVENT)
                {
                        s32 id = event.GUIEvent.Caller->getID();
                        IGUIEnvironment* env = Context.device->getGUIEnvironment();
 
                        switch(event.GUIEvent.EventType)
                        {
 
                        /*
                        If a scrollbar changed its scroll position, and it is
                        'our' scrollbar (the one with id GUI_ID_TRANSPARENCY_SCROLL_BAR), then we change
                        the transparency of all gui elements. This is a very
                        easy task: There is a skin object, in which all color
                        settings are stored. We simply go through all colors
                        stored in the skin and change their alpha value.
                        */
                        case EGET_SCROLL_BAR_CHANGED:
                                if (id == GUI_ID_TRANSPARENCY_SCROLL_BAR)
                                {
                                        s32 pos = ((IGUIScrollBar*)event.GUIEvent.Caller)->getPos();
                                        
                                        for (u32 i=0; i<EGDC_COUNT ; ++i)
                                        {
                                                SColor col = env->getSkin()->getColor((EGUI_DEFAULT_COLOR)i);
                                                col.setAlpha(pos);
                                                env->getSkin()->setColor((EGUI_DEFAULT_COLOR)i, col);
                                        }
                                        
                                }
                                break;
 
                        /*
                        If a button was clicked, it could be one of 'our'
                        three buttons. If it is the first, we shut down the engine.
                        If it is the second, we create a little window with some
                        text on it. We also add a string to the list box to log
                        what happened. And if it is the third button, we create
                        a file open dialog, and add also this as string to the list box.
                        That's all for the event receiver.
                        */
                        case EGET_BUTTON_CLICKED:
                                switch(id)
                                {
                                case GUI_ID_QUIT_BUTTON:
                                        Context.device->closeDevice();
                                        return true;
 
                                case GUI_ID_NEW_WINDOW_BUTTON:
                                        {
                                        Context.listbox->addItem(L"Window created");
                                        Context.counter += 30;
                                        if (Context.counter > 200)
                                                Context.counter = 0;
 
                                        IGUIWindow* window = env->addWindow(
                                                rect<s32>(100 + Context.counter, 100 + Context.counter, 300 + Context.counter, 200 + Context.counter),
                                                false, // modal?
                                                L"Test window");
 
                                        env->addStaticText(L"Please close me",
                                                rect<s32>(35,35,140,50),
                                                true, // border?
                                                false, // wordwrap?
                                                window);
                                        }
                                        return true;
 
                                case GUI_ID_FILE_OPEN_BUTTON:
                                        Context.listbox->addItem(L"File open");
                                        env->addFileOpenDialog(L"Please choose a file.");
                                        return true;
 
                                default:
                                        return false;
                                }
                                break;
 
                        default:
                                break;
                        }
                }
 
                return false;
        }
 
private:
        SAppContext & Context;
};
 
 
/*
Ok, now for the more interesting part. First, create the Irrlicht device. As in
some examples before, we ask the user which driver he wants to use for this
example:
*/
 
/* MOD COde to support adding drawabale strings */
 
#include <list>
 
typedef struct drawstr
{
        video::ITexture * ptext;
        core::rect<s32> scrrect;
        std::wstring stodraw;
        gui::IGUIFont * pfont;
        video::SMaterial * pmat;
        video::S3DVertex m_Vertices[4];
        drawstr( ) { ptext = NULL; pfont = NULL, scrrect = core::rect<s32>( 0, 0, 10, 10 ) ; }
} DRAWSTR, *PDRAWSTR;
 
std::list< DRAWSTR > listdraw;
 
video::IVideoDriver * driver = NULL;
 
void calcuv( PDRAWSTR pds )
{
        if ( pds )
        {
                core::dimension2d<u32> scrsize = driver->getScreenSize();
                float width = float(scrsize.Width);
                float height = float(scrsize.Height);
                
                video::S3DVertex * v = pds->m_Vertices;
                v->Pos.set( pds->scrrect.UpperLeftCorner.X/width, pds->scrrect.UpperLeftCorner.Y/height, 0.f);
                v->TCoords.set( 0.0f, 0.0f );
                v++;
                v->Pos.set( pds->scrrect.LowerRightCorner.X/width, pds->scrrect.UpperLeftCorner.Y/height, 0.f);
                v->TCoords.set( 1.0f, 0.0f );
                v++;
                v->Pos.set( pds->scrrect.LowerRightCorner.X/width, pds->scrrect.LowerRightCorner.Y/height, 0.f);
                v->TCoords.set( 1.0f, 1.0f );
                v++;
                v->Pos.set( pds->scrrect.LowerRightCorner.X/width, pds->scrrect.UpperLeftCorner.Y/height, 0.f);
                v->TCoords.set( 0.0f, 1.0f );
                v++;
 
 
        }
 
 
}
 
PDRAWSTR adddrawstr(  IGUIFont * pf, const wchar_t * p2draw, const core::rect<s32> & rwhere )
{
        PDRAWSTR pds = NULL;
        if ( pf )
        {
 
                DRAWSTR stuff2draw;
                stuff2draw.stodraw = p2draw;
                stuff2draw.pfont = pf;
                stuff2draw.ptext = NULL;
                stuff2draw.pmat = NULL;
                stuff2draw.scrrect = rwhere;
                calcuv( &stuff2draw );
                listdraw.push_back( stuff2draw );
                std::list<DRAWSTR>::iterator it = listdraw.end();
                it--;
                pds = &(*it);
        }
        return pds;
}
 
int inameval = 1;
#include <stdio.h>
#include <stdlib.h>
 
PDRAWSTR adddrawstr(  IGUIFont * pf, const wchar_t * p2draw, const core::rect<s32> & rwhere,  video::SMaterial * pMaterial, bool busertt )
{
        PDRAWSTR pds = adddrawstr( pf, p2draw, rwhere );
        if ( pds )
        {
                pds->pmat = pMaterial;
                core::dimension2d<u32> dimat = pf->getDimension( p2draw );
 
                char snamebuf[ 32 ];
                sprintf( snamebuf, "%drtname%d", inameval, inameval );
                inameval++;
                io::path nextname = snamebuf;
                pds->ptext = driver->addRenderTargetTexture( dimat, nextname, ECF_A8R8G8B8 );
 
        }
        return pds;
}
 
u16 primaryindices[6] = {3,2,1, 3, 1, 0 };
void drawDRAWSTR( PDRAWSTR pds )
{
        if ( pds )
        {
                video::SColor cblack( 0xff, 0,0,0 );
 
                if ( pds->ptext )
                {
                        core::dimension2d<u32> dim = pds->pfont->getDimension( pds->stodraw.c_str() );
                        core::rect<s32> rendrect( 0, 0, dim.Width , dim.Height );
                        
                        driver->setRenderTarget( pds->ptext, true, true );
                        pds->pfont->draw( pds->stodraw.c_str(), rendrect, cblack, false, false );
 
                        driver->setRenderTarget( NULL, false, false );
 
/* change this to false to use drawIndexdtriangle */
                        bool buse2d = true;  // controls the draw mode ...
 
                        if ( !buse2d )
                        {
 
                                pds->pmat->setTexture(0, pds->ptext);
                                driver->setMaterial( *pds->pmat );
                                driver->drawIndexedTriangleList( pds->m_Vertices, 4, primaryindices, 2);
                        }
                        else
                        {
 
                                driver->draw2DImage( pds->ptext, pds->scrrect, rendrect, NULL, NULL, true );
                        }
                }
                else
                {
                        pds->pfont->draw( pds->stodraw.c_str(), pds->scrrect, cblack, false, false );
 
                }
        }
}
 
void drawallDRAWSTR()
{
        std::list<DRAWSTR>::iterator it = listdraw.begin();
        std::list<DRAWSTR>::iterator last = listdraw.end();
        for ( ; it != last ; it++ )
        {
                drawDRAWSTR( &(*it) );
        }
}
/* MOD COde to support adding drawabale strings */
 
int main()
{
        // ask user for driver
        video::E_DRIVER_TYPE driverType= video::EDT_OPENGL; // driverChoiceConsole();
        if (driverType==video::EDT_COUNT)
                return 1;
 
        // create device and exit if creation failed
 
        IrrlichtDevice * device = createDevice(driverType, core::dimension2d<u32>(640, 480));
 
        if (device == 0)
                return 1; // could not create selected driver.
 
        /* The creation was successful, now we set the event receiver and
                store pointers to the driver and to the gui environment. */
 
        device->setWindowCaption(L"Irrlicht Engine - User Interface Demo");
        device->setResizable(true);
 
        driver = device->getVideoDriver();
        IGUIEnvironment* env = device->getGUIEnvironment();
 
        /*
        To make the font a little bit nicer, we load an external font
        and set it as the new default font in the skin.
        To keep the standard font for tool tip text, we set it to
        the built-in font.
        */
 
        IGUISkin* skin = env->getSkin();
        //
        IGUIFont* font = env->getFont("../../media/fonthaettenschweiler.bmp");
        if (font)
                skin->setFont(font);
 
        skin->setFont(env->getBuiltInFont(), EGDF_TOOLTIP);
 
        /*
        We add three buttons. The first one closes the engine. The second
        creates a window and the third opens a file open dialog. The third
        parameter is the id of the button, with which we can easily identify
        the button in the event receiver.
        */      
 
        env->addButton(rect<s32>(10,240,110,240 + 32), 0, GUI_ID_QUIT_BUTTON,
                        L"Quit", L"Exits Program");
        env->addButton(rect<s32>(10,280,110,280 + 32), 0, GUI_ID_NEW_WINDOW_BUTTON,
                        L"New Window", L"Launches a new Window");
        env->addButton(rect<s32>(10,320,110,320 + 32), 0, GUI_ID_FILE_OPEN_BUTTON,
                        L"File Open", L"Opens a file");
 
/* MAJOR CHANGE here */
        wchar_t * ppword = L"PASSWORD";
        wchar_t * pstars = L"*****";
        wchar_t * puser = L"USERNAME";
        wchar_t * pguest = L"Guest";
        s32 centerleft = 640/2;
        s32 centertop = 480/2;
 
        video::SMaterial mattrans;
        mattrans.Wireframe = false;
        mattrans.Lighting = false;
        mattrans.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
 
        s32 rightofcenter = centerleft + 120;
        gui::IGUIFont * pf = font; // mashedfont ;
        core::dimension2d<u32> textdim = mashedfont->getDimension( ppword);
        adddrawstr( pf, ppword, core::rect<s32>( centerleft, centertop, centerleft + textdim.Width, centertop + textdim.Height ) );
        textdim = pf->getDimension( pstars);
        adddrawstr( pf, pstars, core::rect<s32>( rightofcenter, centertop, rightofcenter + textdim.Width, centertop + textdim.Height ) );
 
        centertop += 40;
 
        textdim = mashedfont->getDimension( ppword);
        adddrawstr( pf, ppword, core::rect<s32>( centerleft, centertop, centerleft + textdim.Width + 10, centertop + textdim.Height ), &mattrans, true );
        textdim = mashedfont->getDimension( pstars );
        adddrawstr( pf, pstars, core::rect<s32>( rightofcenter, centertop, rightofcenter + textdim.Width + 10, centertop + textdim.Height ), &mattrans, true );
 
        centertop += 40;
        textdim = pf->getDimension( puser);
        adddrawstr( pf, puser, core::rect<s32>( centerleft, centertop, centerleft + textdim.Width, centertop + textdim.Height ) );
        textdim = pf->getDimension( pguest);
        adddrawstr( pf, pguest, core::rect<s32>( rightofcenter, centertop, rightofcenter + textdim.Width, centertop + textdim.Height ) );
 
        centertop += 40;
        textdim = pf->getDimension( puser);
        adddrawstr( pf, puser, core::rect<s32>( centerleft, centertop, centerleft + textdim.Width + 10, centertop + textdim.Height ), &mattrans, true );
        textdim = pf->getDimension( pguest);
        adddrawstr( pf, pguest, core::rect<s32>( rightofcenter, centertop, rightofcenter + textdim.Width + 10, centertop + textdim.Height ), &mattrans, true );
 
/* END MOD area */
 
        /*
        Now, we add a static text and a scrollbar, which modifies the
        transparency of all gui elements. We set the maximum value of
        the scrollbar to 255, because that's the maximal value for
        a color value.
        Then we create an other static text and a list box.
        */
 
        env->addStaticText(L"Transparent Control:", rect<s32>(150,20,350,40), true);
        IGUIScrollBar* scrollbar = env->addScrollBar(true,
                        rect<s32>(150, 45, 350, 60), 0, GUI_ID_TRANSPARENCY_SCROLL_BAR);
        scrollbar->setMax(255);
 
        // set scrollbar position to alpha value of an arbitrary element
        scrollbar->setPos(env->getSkin()->getColor(EGDC_WINDOW).getAlpha());
 
        env->addStaticText(L"Logging ListBox:", rect<s32>(50,110,250,130), true);
        IGUIListBox * listbox = env->addListBox(rect<s32>(50, 140, 250, 210));
        env->addEditBox(L"Editable Text", rect<s32>(350, 80, 550, 100));
 
 
        // Store the appropriate data in a context structure.
        SAppContext context;
        context.device = device;
        context.counter = 0;
        context.listbox = listbox;
 
        // Then create the event receiver, giving it that context structure.
        MyEventReceiver receiver(context);
 
        // And tell the device to use our custom event receiver.
        device->setEventReceiver(&receiver);
 
 
        /*
        And at last, we create a nice Irrlicht Engine logo in the top left corner. 
        */
        env->addImage(driver->getTexture("../../media/irrlichtlogo2.png"),
                        position2d<int>(10,10));
 
 
        /*
        That's all, we only have to draw everything.
        */
        
        int lastFPS = -1;
        while(device->run() && driver)
        if (device->isWindowActive())
        {
                driver->beginScene(true, true, SColor(0,200,200,200));
 
                env->drawAll();
                
                drawallDRAWSTR();
        
                driver->endScene();
 
                int fps = driver->getFPS();
 
                if (lastFPS != fps)
                {
                        core::stringw str = L"Irrlicht Engine - User Interface Demo [";
                        str += driver->getName();
                        str += "] FPS:";
                        str += fps;
 
                        device->setWindowCaption(str.c_str());
                        lastFPS = fps;
                }
 
        }
 
        device->drop();
 
        return 0;
}
 
/*
**/
 
It 'should' be buildable and when you change the bool buse2d in the drawDRAWSTR(), you should see the issue - it's NOT going to be pretty.

Feedback would be appreciated...
caburfoot
Posts: 22
Joined: Mon Aug 08, 2011 6:15 am

Re: RenderTarget and drawTriangleList

Post by caburfoot »

Talking with one fellow indicated that it's rendered Mirrorred?
So we need to use UV at 1,1 to 0,0 instead of 0,0 to 1,1 ( 1,1; 1,0; 0,0;0,1 ) ??
I tried that an it vanished all together, but the Irrlicht logo is upside down ?

Come on you Irrlicht pros, educate us...
tbw
Posts: 59
Joined: Sat Jan 15, 2011 9:51 am
Location: Germany

Re: RenderTarget and drawTriangleList

Post by tbw »

try using

Code: Select all

                // set 2d material
                VideoDriver->setMaterial(VideoDriver->getMaterial2D());
before using 2d functions.
I had the same effect but only with opengl driver. It was fixed by using the above snippet for methods as draw2dImage().
Post Reply