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

Author Topic: findCharacterPos() is not returning expected value.  (Read 4388 times)

0 Members and 1 Guest are viewing this topic.

HammaJamma

  • Newbie
  • *
  • Posts: 12
    • View Profile
findCharacterPos() is not returning expected value.
« on: June 05, 2014, 04:41:53 am »
I'm writing a text wrapping function that takes a string and breaks it up in to multiple strings based on it's position in the window. I'm using a for loop and sf::Text.getCharacterpos().x to find the first character that is outside of the text box.
here's the problem I'm having.


lines that are composed of mostly large character's (like "k") are longer then lines that are composed of mostly smaller characters(like "j").
hopefully someone can help me understand what i'm doing wrong.

here's the function I'm working on,

//text wrapping function
//this function takes 3 arguments
//      #1 input_text : this argument passes in the original string via an sf::text object which will
//                             need to be broken up into into smaller strings based on the size of the intended text box.
//      #2 output_string: this argument will pass in a reference to the desired string vector so the function
//                                 can push back as many individual lines as needed.
//      #3 line_width   : use this argument to pass in the desired line length in pixels.
void wrapText(sf::Text input_text, std::vector<std::string> &output_string, int string_width)
{      
        std::string string = input_text.getString();
        std::string temp_string;
        for(int i = 0; i < string.size(); i++)
        {
                if(input_text.findCharacterPos(i).x > string_width)
                {
                        for(int j = 0; j < i; j++)
                        {
                                temp_string += string[j];
                        }
                        output_string.push_back(temp_string);
                        temp_string = "";
                        for(int k = i; k < string.size(); k++)
                        {
                                temp_string += string[k];
                        }
                        string = temp_string;
                        temp_string = "";
                        i = 0;
                }
               
        }
        output_string.push_back(string);
};

thanks in advance for any help  :D

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: findCharacterPos() is not returning expected value.
« Reply #1 on: June 05, 2014, 08:15:34 am »
Launch the debugger, run your code step by step, watch what the function returns, as well as the intermediate values, and find what's wrong. That what programmers usually do when the implementation of an algorithm doesn't work as expected ;)
Laurent Gomila - SFML developer

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: findCharacterPos() is not returning expected value.
« Reply #2 on: June 05, 2014, 08:17:29 am »
lines that are composed of mostly large character's (like "k") are longer then lines that are composed of mostly smaller characters(like "j").
Yes, obviously, since you're not using a monospace font.
 
hopefully someone can help me understand what i'm doing wrong.
What exactly is your problem?

If you want to find out how many characters fit into a certain width, there's no need to have nested for loops. Just use this algorithm:
float totalWidth = 0.f;
for (every character in text)
{
    totalWidth += character width; // use sf::Glyph
    if (totalWidth > maxWidth)
    {
        break line before character;
    }
}
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
AW: findCharacterPos() is not returning expected value.
« Reply #3 on: June 05, 2014, 08:19:02 am »
If you want to go with number of characters you need to choose a mono spaced font.
If you use a font with varying character widths you need to sum up the width of each character and compare it to your wanted width.

Also keep in mind, if you just want a simple line break, there's no need for a new text object, just insert n = new line into the string.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: findCharacterPos() is not returning expected value.
« Reply #4 on: June 05, 2014, 08:42:35 am »
No no no guys. Summing glyphs widths is incorrect, because you don't take in account the kerning and horizontal advance. Text layout is more complex than that. This is exactly why the findCharacterPos function exists.

But yes, the function seems a little too complicated for what it does. All these temporary strings and nested loops are probably not needed.
Laurent Gomila - SFML developer

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: findCharacterPos() is not returning expected value.
« Reply #5 on: June 05, 2014, 09:03:10 am »
No no no guys. Summing glyphs widths is incorrect, because you don't take in account the kerning and horizontal advance. Text layout is more complex than that. This is exactly why the findCharacterPos function exists.
You get access to the advance via glyph, but I forgot about the kerning. I've thought of a way to know where the next glyph would be placed without initially constructing the complete sf::Text that is thrown away afterwards, but apparently, this is not possible (at least not without re-implementing findCharacterPos()).

On a related note, the sf::Glyph documentation is quite short and doesn't really describe how this class can be used meaningfully. Do you think an addition might be worthwhile, or at least a note that most users won't need to access it directly and can refer to sf::Font and sf::Text instead?
« Last Edit: June 05, 2014, 09:04:49 am by Nexus »
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: findCharacterPos() is not returning expected value.
« Reply #6 on: June 05, 2014, 09:33:21 am »
Quote
I've thought of a way to know where the next glyph would be placed without initially constructing the complete sf::Text that is thrown away afterwards, but apparently, this is not possible (at least not without re-implementing findCharacterPos()).
In my old todo-list there was an idea for a class that would contain all the text layout logic, outside the graphical sf::Text class. It would then be used for building the vertex array, implementing the findCharacterPos function, and of course to ease the implementation of any other user algorithm.

Quote
On a related note, the sf::Glyph documentation is quite short and doesn't really describe how this class can be used meaningfully. Do you think an addition might be worthwhile, or at least a note that most users won't need to access it directly and can refer to sf::Font and sf::Text instead?
The tutorial is a little more detailed, but yes it can't hurt to improve the API doc too.
Laurent Gomila - SFML developer

HammaJamma

  • Newbie
  • *
  • Posts: 12
    • View Profile
Re: findCharacterPos() is not returning expected value.
« Reply #7 on: June 05, 2014, 07:09:37 pm »
thanks for all the replies! I have 2 new questions.

first.
all this talk about glyphs, kerning and horizontal advance is a bit over my head. can anyone link me some documentation to better understand what you're all talking about? the tutorials/API have left me wanting.
 
second
Can anyone break down what findCharacterPos() is doing/returning? The concept i have from reading the API is that it's supposed to return the x and y coordinates of the requested character in the string.

Also, I initially considered using newline instead of breaking up the string into sub strings but I liked the idea of being able to control each line as it's own text object. However, the more I work with sf:: text the less I see the need to use individual text objects for each line and I may just end up using a function like Nexus posted

float totalWidth = 0.f;
for (every character in text)
{
    totalWidth += character width; // use sf::Glyph
    if (totalWidth > maxWidth)
    {
        break line before character;
    }
}

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: findCharacterPos() is not returning expected value.
« Reply #8 on: June 05, 2014, 08:27:27 pm »
As Laurent stated, you don't need to care about kerning, glyphs and all that stuff if you simply use findCharacterPos().

So... what exactly doesn't work with it?
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

HammaJamma

  • Newbie
  • *
  • Posts: 12
    • View Profile
Re: findCharacterPos() is not returning expected value.
« Reply #9 on: June 05, 2014, 09:25:16 pm »
So... what exactly doesn't work with it?

what i'm having issues with is;
a line of 20 k's and a line of 20 j's are different graphical sizes but they are both returning the same x coordinate for the last letter in their index. 
As stated by Nexus, I am not using a monospace font and if I cannot use a non-monospace font with findCharachterPos() then I can deal with that, but, I would prefer to have that option open to me.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: findCharacterPos() is not returning expected value.
« Reply #10 on: June 05, 2014, 09:48:14 pm »
Quote
a line of 20 k's and a line of 20 j's are different graphical sizes but they are both returning the same x coordinate for the last letter in their index. 
Can you please show a complete and minimal code that demonstrates this problem, so that we can test it?
Laurent Gomila - SFML developer

HammaJamma

  • Newbie
  • *
  • Posts: 12
    • View Profile
Re: findCharacterPos() is not returning expected value.
« Reply #11 on: June 05, 2014, 11:09:28 pm »
I actually just figured it out!

void wrapText(sf::Text input_text, std::vector<std::string> &output_string, int string_width)
{      
        input_text.setCharacterSize(20);
        std::string string = input_text.getString();
        std::string temp_string;
        for(int i = 0; i < string.size(); i++)
        {

                input_text.setString(string);// <- I was missing this line!! i just needed to reset the string
                                    //inside the text object after I had modified it. derp

                if(input_text.findCharacterPos(i).x > string_width)
                {
                        for(int j = 0; j < i; j++)
                        {
                                temp_string += string[j];
                        }
                        output_string.push_back(temp_string);
                        temp_string = "";
                        for(int k = i; k < string.size(); k++)
                        {
                                temp_string += string[k];
                        }
                        string = temp_string;
                        temp_string = "";
                        i = 0;
                }
               
        }
        output_string.push_back(string);
};

 

anything