Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Problem with character positioning  (Read 6835 times)

0 Members and 1 Guest are viewing this topic.

ineed.help

  • Jr. Member
  • **
  • Posts: 56
    • View Profile
Problem with character positioning
« on: July 24, 2014, 01:43:46 pm »
Hello!

I have been working for quite a while now on a system to draw a series of sprite as if they were an sf::Text.
However, I recently took notice of a problem: if you look at this picture...

As you can see, there are some rather large gaps between some of the characters, and I don't quite understand why.
There is also a very large difference between the y-coordinates of the lines.
This is a sample of the code I have been using which contains my problem.

int main()
{
        sf::RenderWindow window(sf::VideoMode(360, 240, 32), "Title");
        sf::Font font;
        font.loadFromFile("fonts/font.ttf");
        std::vector<sf::Sprite> chars;
        sf::Sprite tempSprite;
        std::string str = "Hello! This is a string! This string is rather long, so it needs to be divided into multiple lines.";
        unsigned short xPos = 0, yPos = 0;
        unsigned char prevChar = 'A';

        for (unsigned short i = 0; i < str.length(); i++)
        {
                tempSprite.setTexture(font.getTexture(24));
                tempSprite.setTextureRect(font.getGlyph(str[i], 24, false).textureRect);
                tempSprite.setColor(sf::Color::Black);

                if (xPos + (2 * tempSprite.getTextureRect().width) >= window.getSize().x)
                {
                        xPos = 0;
                        yPos += font.getLineSpacing(24);
                }

                else
                { if (i > 1) { xPos += font.getKerning(prevChar, str[i], 24); } }

                tempSprite.setPosition(xPos, yPos + font.getGlyph(str[i], 24, false).bounds.top + font.getGlyph('A', 24, false).bounds.height); // should this be 'A' (?)
                chars.push_back(tempSprite);
                xPos += font.getGlyph(str[i], 24, false).advance;
                prevChar = str[i];
        }

        unsigned short crtCharNo = 0;

        while(window.isOpen())
        {
                window.clear(sf::Color::White);
                if (crtCharNo < chars.size() - 1) { crtCharNo++; }
                for (unsigned short i = 0; i <= crtCharNo; i++)
                { window.draw(chars[i]); }
                window.display();
        }
}
 

What am I doing wrong? I thought "getKerning" moves the characters closer, and "advance" moved them apart, but I am clearly doing something wrong.
(This assumes there is nothing wrong with the font I am using, which is called "Linux Libertine", although I doubt that's the case.)

Hopefully I explained myself in a decent manner. I would greatly appreciate any help.
« Last Edit: July 24, 2014, 02:29:21 pm by ineed.help »

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Problem with character positioning
« Reply #1 on: July 24, 2014, 02:54:18 pm »
You should use sf::Text::findCharacterPos(), it handles the positioning for you. Unfortunately, this may require the creation of a useless sf::Text object.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Strelok

  • Full Member
  • ***
  • Posts: 139
    • View Profile
    • GitHub
Re: Re: Problem with character positioning
« Reply #2 on: July 24, 2014, 03:14:18 pm »
You should use sf::Text::findCharacterPos(), it handles the positioning for you. Unfortunately, this may require the creation of a useless sf::Text object.
The irony ;D

ineed.help

  • Jr. Member
  • **
  • Posts: 56
    • View Profile
Re: Problem with character positioning
« Reply #3 on: July 24, 2014, 03:18:59 pm »
... I don't understand; how am I supposed to use it? I understand if it's just one line, but with multiple lines, how would I go about doing that?

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Problem with character positioning
« Reply #4 on: July 24, 2014, 04:33:54 pm »
This functionality might be outsourced one day. For now, you could copy the algorithm from sf::Text::findCharacterPos (or at least have a look at it and see what you need to do), because creating a sf::Text object is of course not ideal if you want to draw sf::Sprites ;)

What difference do multiple lines make to find the position? The text then just starts at another character... and when you use the algorithm directly without sf::Text, you can probably even find a more elegant solution than reassigning the string.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

ineed.help

  • Jr. Member
  • **
  • Posts: 56
    • View Profile
Re: Problem with character positioning
« Reply #5 on: July 24, 2014, 05:06:17 pm »
I have read it. I did as it said, too, in my previous code:

xPos += font.getKerning(prevChar, str[i], fontSize);
tempSprite.setPosition(xPos, yPos + font.getGlyph(str[i], fontSize, false).bounds.top + font.getGlyph(0, fontSize, false).bounds.height);
chars.push_back(tempSprite);
xPos += font.getGlyph(str[i], fontSize, false).advance;
prevChar = str[i];
 

As the source code says... Am I missing something?
« Last Edit: July 24, 2014, 08:12:24 pm by ineed.help »

ineed.help

  • Jr. Member
  • **
  • Posts: 56
    • View Profile
Re: Problem with character positioning
« Reply #6 on: July 24, 2014, 09:25:20 pm »
Anyone?

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Problem with character positioning
« Reply #7 on: July 24, 2014, 10:24:19 pm »
Your other post is only a few hours old... Why are people so impatient? This is a forum of contributors spending their free time, and in my opinion it is slightly disrespectful to push topics after such a short amount of time. People will see your post and answer if they want to, it doesn't need additional attention.

You could use the time to debug further. Does it work with findCharacterPos()? If so, find the difference to your code. And double-check the documentation again, it has been a while since I last worked with glyphs...
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

ineed.help

  • Jr. Member
  • **
  • Posts: 56
    • View Profile
Re: Problem with character positioning
« Reply #8 on: July 24, 2014, 10:34:45 pm »
I don't know how these forums work, if people only generally reply to the top topic or not, as this is the case in some other forums. I did not mean to be disrespectful. I am just an impatient person.

As I said earlier, the problem is not one that can be debugged; it doesn't work with "findCharacterPos()", because sf::Text doesn't do automatic line breaks like my program does. For this to work, I would have to create a sf::Text object, assign a line break every time the automatic line break occurs, and then use "findCharacterPos()", and I feel that this is a bit reduntant, which is why I am asking for help from those more experienced with SFML.

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Problem with character positioning
« Reply #9 on: July 24, 2014, 11:18:24 pm »
I have read it. I did as it said, too, in my previous code:
...
As the source code says... Am I missing something?
I don't know what source code you read, but the one in sf::Text::ensureGeometryUpdate() contains way more than those few lines of code you mentioned. Since I really can't be bothered explaining each line of the code that you didn't read properly, I'll just paste this here and let you spot the differences.
int main()
{
    sf::RenderWindow window(sf::VideoMode(360, 240, 32), "Title");
    sf::Font font;
    font.loadFromFile("font.ttf");
    std::vector<sf::Sprite> chars;
    sf::Sprite tempSprite;
    std::string str = "Hello! This is a string! This string is rather long, so it needs to be divided into multiple lines.";
    unsigned short xPos = 0, yPos = 24;
    unsigned char prevChar = 0;

    for (unsigned short i = 0; i < str.length(); i++)
    {
        const sf::Glyph& glyph = font.getGlyph(str[i], 24, false);

        sf::Vector2f scale(1.f, 1.f);

        if (glyph.textureRect.width && glyph.textureRect.height)
        {
            scale.x = glyph.bounds.width / glyph.textureRect.width;
            scale.y = glyph.bounds.height / glyph.textureRect.height;
        }

        tempSprite.setTexture(font.getTexture(24));
        tempSprite.setTextureRect(glyph.textureRect);
        tempSprite.setColor(sf::Color::Black);
        tempSprite.setScale(scale);

        if (xPos + (2 * tempSprite.getTextureRect().width) >= window.getSize().x)
        {
            xPos = 0;
            yPos += font.getLineSpacing(24);
            prevChar = 0;
        }
        else
        {
            xPos += font.getKerning(prevChar, str[i], 24);
        }

        tempSprite.setPosition(xPos + glyph.bounds.left, yPos + glyph.bounds.top);
        chars.push_back(tempSprite);
        xPos += glyph.advance;
        prevChar = str[i];
    }

    unsigned short crtCharNo = 0;

    while(window.isOpen())
    {
        window.clear(sf::Color::White);
        if (crtCharNo < chars.size() - 1) { crtCharNo++; }
        for (unsigned short i = 0; i <= crtCharNo; i++)
        { window.draw(chars[i]); }
        window.display();
    }
}
Oh and by the way... there is nothing wrong with the vertical spacing between the lines in your original picture. You just picked the worst possible spot to measure the distance at.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

ineed.help

  • Jr. Member
  • **
  • Posts: 56
    • View Profile
Re: Problem with character positioning
« Reply #10 on: July 24, 2014, 11:36:07 pm »
Thank you, I will check this out first thing in the morning (it's nearly midnight in my country).

(Also, I checked "findCharacterPos()", not "ensureGeometryUpdate()".)

ineed.help

  • Jr. Member
  • **
  • Posts: 56
    • View Profile
Re: Problem with character positioning
« Reply #11 on: July 25, 2014, 10:25:28 am »
All right, it works... mostly. How come it doesn't start at (0, 0)? This happens with sf::Text as well; if you set its position to (0, 0), the y-position is never at 0.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Problem with character positioning
« Reply #12 on: July 25, 2014, 10:36:02 am »
Because text is aligned on the baseline, not on the top position. The extra space at the top would be filled if you had the highest possible glyph in your text.
Laurent Gomila - SFML developer

ineed.help

  • Jr. Member
  • **
  • Posts: 56
    • View Profile
Re: Problem with character positioning
« Reply #13 on: July 25, 2014, 11:05:36 am »
What do you mean by the "highest possible glyph"? Can I do something with the base y-position to correct this for all characters?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Problem with character positioning
« Reply #14 on: July 25, 2014, 11:17:33 am »
I mean the tallest one, like 'É'. The behaviour is the same as in any text editor.

If you really want your text to be aligned on top, you can subtract getLocalBounds().top from its Y position.
Laurent Gomila - SFML developer

 

anything