TextArea GUI Element [v1.0]

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
RdR
Competition winner
Posts: 273
Joined: Tue Mar 29, 2011 2:58 pm
Contact:

TextArea GUI Element [v1.0]

Post by RdR »

Hello all,

I've created a textarea class which I want to share with you if someone needs something like it.

Features:
- Multiple colors on 1 line
- Padding
- Line spacing/offset
- Adjustable size
- TextArea border ( adjustable size )
- Wrapping
- Long word chop
- Left / Right / Center aligned
- Background texture
- Multiple fonts in textarea (1 font per line)
- Image support
- (Auto) Scrolling
- Batching text to minimize draw calls
- Use RTT to improve performance
- Line lifetime (auto removed when expired )

Examples:
Image
Image

Image

Image

More examples can be found in an other project of mine TANK@WAR: http://irrlicht.sourceforge.net/phpBB2/ ... hp?t=44174

Source:
http://dev.ferket.net/irrlicht/TextArea.zip
IrrExt mirror

Example use:

Code: Select all

 
// Create a new textarea
TextArea* textArea = new TextArea(Environment, Environment->getRootGUIElement());
textArea->setDimension(370, 135);
textArea->setMaxLines(6);
textArea->setAlignment(TextArea::LEFT);
textArea->setPosition(irr::core::vector2di(5, 200));
textArea->drop(); // Always drop custom GUI Elements
 
 
// Create new line
Line* line = new Line();
 
irr::core::stringw msg = L"";
msg = "Lorum ipsum";
line->addString(msg, irr::video::SColor(255, 0, 0, 0));
 
msg = "dolor";
line->addString(msg, irr::video::SColor(255, 0, 255, 0));
 
msg = "amut";
line->addString(msg, irr::video::SColor(255, 125, 255, 0));
 
// Add image to line
irr::video::ITexture* icon = Environment->getVideoDriver()->getTexture("./media/icons/icon.png");
line->addImage(icon);
 
// Add new line to chatBox
textArea->addLine(line);
 
// Create another line with different font
line = new Line(Environment->getFont("./media/fonts/arial.xml"));
 
msg = "Lorum ipsum";
line->addString(msg, irr::video::SColor(255, 0, 0, 0));
 
// Add new line to chatBox
textArea->addLine(line);
 
To use the scrolling feature make you have to get the EMIE_MOUSE_WHEEL event:

Code: Select all

 
// Basic example
 
float mouseWheel;
 
bool OnEvent(const SEvent& event) {
        if (event.EventType == EET_MOUSE_INPUT_EVENT && event.MouseInput.Event == EMIE_MOUSE_WHEEL) {
                mouseWheel += event.MouseInput.Wheel;
        }
        return false;
}
 
// Put this in your handle method
if (mouseWheel > 0 || mouseWheel < 0) {
        textArea->changeStartIndex((irr::s32) mouseWheel);
}
 
Note:
Make sure you add the source of Irrlicht to your includes as well (source/Irrlicht)
Else you will get an error like: TextArea.cpp:24:22: fatal error: CGUIFont.h: No such file or directory compilation terminated.
Last edited by RdR on Tue May 15, 2012 9:42 am, edited 29 times in total.
shadowslair
Posts: 758
Joined: Mon Mar 31, 2008 3:32 pm
Location: Bulgaria

Post by shadowslair »

Hello. I`ve made sth similar some time ago, but your looks better. Thanks for sharing. :wink:
"Although we walk on the ground and step in the mud... our dreams and endeavors reach the immense skies..."
Ovan
Posts: 70
Joined: Thu Dec 18, 2008 12:41 am
Contact:

Post by Ovan »

Thanks for sharing :)
but i think this is not optimized, you use std::vector but why not irr::core::array ? ...
and I think this he need to PreRender the text and always update if it changed, not always update on render
REDDemon
Developer
Posts: 1044
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

Post by REDDemon »

Yup it can be optimized but that's not a difficult task. Good job :)
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:

Post by RdR »

Ovan wrote:Thanks for sharing :)
but i think this is not optimized, you use std::vector but why not irr::core::array ? ...
and I think this he need to PreRender the text and always update if it changed, not always update on render
What do you mean by PreRender? I'm calculating the visible line only when new lines are added or the dimension of the textarea changes.

You mean something like using static text and only updating when a new line is added? (or changes in dimension)
REDDemon wrote:Yup it can be optimized but that's not a difficult task. Good job :)
Thanks, what are your suggestions for optimization?
REDDemon
Developer
Posts: 1044
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

Post by REDDemon »

RdR wrote:Thanks, what are your suggestions for optimization?
first of all there are some methods that can be setted as const:)

Code: Select all

irr::u32 TextArea::getNumberOfLines();
irr::core::recti getDimension();
the following methods can be added in two flavors, const and not-const. The compiler will select the best:

Code: Select all

std::vector<Line*> TextArea::getLines();
drawing method:
I personally like how do you compute all the things in the draw method. But there is also an alternative (idk if it is reallygood).

Actually you are calling all the drawings methods.
like this:

Code: Select all

for (irr::u32 i = 0; i < strings.size(); i++)
{
    irr::core::stringw str = strings.at(i); //!

    stringDimension = font->getDimension(str.c_str());
    lastDimension.LowerRightCorner.X += stringDimension.Width;

    font->draw(str.c_str(), lastDimension, colors.at(i), false, false);
    lastDimension.UpperLeftCorner.X = lastDimension.LowerRightCorner.X;
}
look at the "//!". You are just copying data, that can be copied directly to the draw() function skipping a step. The compiler can detect this redondance as not. If not you are just spending cycles re-copying data.

You can for example access data from an array when iterating, and precompute that array every time a string change

Code: Select all

font->draw(somethingelsehere, lastDimension, colors.at(i), false, false);
There are similiar things like that that can be done. I will add two test cases with original code and modified and I'll check i there is really a perfomance increase just because I want to waste some time :).
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
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Calling font->draw for single characters is also pretty cycle wasting, and will reduce render performance to a bare minimum. You have to call this method for larger portions of the text.
REDDemon
Developer
Posts: 1044
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

Post by REDDemon »

O_O I dont think he is calling it for every character, but only for whole strings.

EDIT: gotta what you mean. I don't see any easy way for doing that.
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
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Check the draw2dImageBatch method. That's what is actually happening in font->draw.
RdR
Competition winner
Posts: 273
Joined: Tue Mar 29, 2011 2:58 pm
Contact:

Post by RdR »

hybrid wrote:Check the draw2dImageBatch method. That's what is actually happening in font->draw.
But isn't that used by all text drawing methods?
REDDemon
Developer
Posts: 1044
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

Post by REDDemon »

RdR wrote:
hybrid wrote:Check the draw2dImageBatch method. That's what is actually happening in font->draw.
But isn't that used by all text drawing methods?
Actually if you draw 5 different textes with the same colour they are not batched togheter with your method. so instead of 1 draw calls there will be 5 draw calls.

Every character is batched in the same text every times irrlicht call a draw font method. But you can batch more texts if you know they can be batched.

I have the feeling that the whole text on the screen can be drawed with only 1 draw call (if color is holded by vertex data). but changin the text maybe is a bit slow if it is all batched togheter. So un-batched text is not fast as light but in general is more flexible
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: Textarea (Chatbox etc)

Post by RdR »

I added some extra features:

- Multiple font support (1 font per line)
- Image support
- Scrolling

And some fixes
How to use it, see code in first post.

Source:
http://dev.ferket.net/irrlicht/TextArea.zip

Image

Image
Last edited by RdR on Wed Oct 12, 2011 10:03 am, edited 1 time in total.
Ovan
Posts: 70
Joined: Thu Dec 18, 2008 12:41 am
Contact:

Re: Textarea (Chatbox etc)

Post by Ovan »

hello juste post a sample code to replace text by image

smiley varible is std::map<const char*, const char*>

Code: Select all

 
void ClientEngine::initMap()
{
    smiley[":)"] = "smile.png";
    smiley[";)"] = "wink.png";
    smiley[":("] = "sad.png";
    smiley[":o"] = "surprise.png";
}
const char* ClientEngine::findFirst(irr::core::stringw text, int pos, int &find)
{
    int out = -1;
    const char *findKey = "no";
    const char *tnew = 0;
    for(std::map<const char*, const char*>::iterator i = smiley.begin(); i != smiley.end(); ++i)
    {
        int current = text.find((*i).first, pos);
        if(current > -1)
        {
            if(current < (out == -1 ? text.size() : out))
            {
                out = current;
                findKey = (*i).first;
                tnew = (*i).second;
            }
        }
    }
    printf("[%s = %s]\n", findKey, tnew);
    find = out;
    return tnew;
}
engine::addon::Line* ClientEngine::replace(engine::addon::Line *l)
{
    int pictureIndex = 0;
    engine::addon::Line *lnew = new engine::addon::Line(l->getFont());
    printf("-----------------------------------\n");
    for(int it = 0; it != l->getStrings().size(); it++)
    {
        irr::core::stringw text = l->getStrings().at(it);
        if(text == IMAGE_PLACEHOLDER)
        {
            lnew->addImage(l->getImages().at(pictureIndex));
            if(pictureIndex < l->getImages().size()) pictureIndex++;
        }
        else
        {
            int pos = 0, zln = 0;
            const char *tnew = findFirst(text, pos, zln);
            if(zln < 0) lnew->addString(text.subString(0, text.size()), l->getColors().at(it));
            while(zln != -1)
            {
                tnew = findFirst(text, pos, zln);
                lnew->addString(text.subString(pos, zln-pos), l->getColors().at(it));
                lnew->addImage(driver->getTexture(tnew));
                pos = zln+2; // smiley key size ( ":)" size = 2 )
            }
        }
    }
    delete l;
    return lnew;
}
use:

Code: Select all

 
                engine::addon::Line *tmp = new engine::addon::Line();
                tmp->addString(your_text, your_color);
                history->addLine(replace(tmp));
 
RdR
Competition winner
Posts: 273
Joined: Tue Mar 29, 2011 2:58 pm
Contact:

Re: Textarea (Chatbox etc)

Post by RdR »

Ovan wrote:hello juste post a sample code to replace text by image

smiley varible is std::map<const char*, const char*>

Code: Select all

 
void ClientEngine::initMap()
{
    smiley[":)"] = "smile.png";
    smiley[";)"] = "wink.png";
    smiley[":("] = "sad.png";
    smiley[":o"] = "surprise.png";
}
const char* ClientEngine::findFirst(irr::core::stringw text, int pos, int &find)
{
    int out = -1;
    const char *findKey = "no";
    const char *tnew = 0;
    for(std::map<const char*, const char*>::iterator i = smiley.begin(); i != smiley.end(); ++i)
    {
        int current = text.find((*i).first, pos);
        if(current > -1)
        {
            if(current < (out == -1 ? text.size() : out))
            {
                out = current;
                findKey = (*i).first;
                tnew = (*i).second;
            }
        }
    }
    printf("[%s = %s]\n", findKey, tnew);
    find = out;
    return tnew;
}
engine::addon::Line* ClientEngine::replace(engine::addon::Line *l)
{
    int pictureIndex = 0;
    engine::addon::Line *lnew = new engine::addon::Line(l->getFont());
    printf("-----------------------------------\n");
    for(int it = 0; it != l->getStrings().size(); it++)
    {
        irr::core::stringw text = l->getStrings().at(it);
        if(text == IMAGE_PLACEHOLDER)
        {
            lnew->addImage(l->getImages().at(pictureIndex));
            if(pictureIndex < l->getImages().size()) pictureIndex++;
        }
        else
        {
            int pos = 0, zln = 0;
            const char *tnew = findFirst(text, pos, zln);
            if(zln < 0) lnew->addString(text.subString(0, text.size()), l->getColors().at(it));
            while(zln != -1)
            {
                tnew = findFirst(text, pos, zln);
                lnew->addString(text.subString(pos, zln-pos), l->getColors().at(it));
                lnew->addImage(driver->getTexture(tnew));
                pos = zln+2; // smiley key size ( ":)" size = 2 )
            }
        }
    }
    delete l;
    return lnew;
}
use:

Code: Select all

 
                engine::addon::Line *tmp = new engine::addon::Line();
                tmp->addString(your_text, your_color);
                history->addLine(replace(tmp));
 
Thats a nice addon, thanks for sharing!
RdR
Competition winner
Posts: 273
Joined: Tue Mar 29, 2011 2:58 pm
Contact:

Re: Textarea (Chatbox etc)

Post by RdR »

Updated the textarea.
Batching the text with the same font and color now, so draw() calls are minimized.
In my test project it gained from ~200 FPS to ~800 FPS :D

Image

Also fixt the wrapping for right & center alignment
And some minor bugs.

So I recommend everyone using this to upgrade to latest version.

Image
Post Reply