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

Author Topic: text.getrect() behaviour  (Read 9199 times)

0 Members and 1 Guest are viewing this topic.

Boogiwoogie

  • Newbie
  • *
  • Posts: 19
    • View Profile
text.getrect() behaviour
« on: February 05, 2010, 08:44:23 am »
i checked out sfml2 and was wondering what happened to the sf::String class. took a while til i realized that its now split up into string and text. i think i like it that way, not sure yet ;)
however, in my small imgui code that i wrote a while back i replaced all sf::string by sf::text and it pretty much works like it did, with a single exception: sf::text.getrect() takes into account if theres a literal that "goes through" the bottom line, like "y" or "g". so my nice little edit box that i am so proud of starts popping up if i hit such a literal, eg the box shows "nnn" and i add a "j". however, getrect() does not do the same on the upper half of the glyph, texts like "nnn" and "NNN" give same y-coordinates.
any way to handle this? i am actually interested in the "bounding rect" that pretends to always have a preceding "j" in it the text.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
text.getrect() behaviour
« Reply #1 on: February 05, 2010, 09:17:31 am »
Quote
took a while til i realized that its now split up into string and text

Not exactly. sf::String was renamed to sf::Text, and sf::Unicode::Text was rewritten and renamed sf::String.

Quote
with a single exception: sf::text.getrect() takes into account if theres a literal that "goes through" the bottom line, like "y" or "g"

You mean that it doesn't in SFML 1.x? I don't remember changing this function in SFML 2 :?

Quote
any way to handle this? i am actually interested in the "bounding rect" that pretends to always have a preceding "j" in it the text.

But your text doesn't have this "j" ;)
I can't make the bounding rectangle bigger just in case you type a "j" later.

But I don't understand why your edit box depends on the size of its contents? Isn't it supposed to have a fixed size?
Laurent Gomila - SFML developer

Boogiwoogie

  • Newbie
  • *
  • Posts: 19
    • View Profile
text.getrect() behaviour
« Reply #2 on: February 05, 2010, 09:54:50 am »
Quote from: "Laurent"

Quote
any way to handle this? i am actually interested in the "bounding rect" that pretends to always have a preceding "j" in it the text.

But your text doesn't have this "j" ;)
I can't make the bounding rectangle bigger just in case you type a "j" later.

But I don't understand why your edit box depends on the size of its contents? Isn't it supposed to have a fixed size?

it has fixed size. the sf::text is scaled so that it nicely fits into it.
i am not sure whether you noticed the inconsistency. sf::text.getrect() gives same height for "nnn" and "NNN" and ".....". but it gives bigger height for "nng". i may be wrong but i think that 1.5 didnt care about literals that exceeded the bottom line, it always returned the top-to-bottom-line-difference (which was to small for strings containing such literals).

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
text.getrect() behaviour
« Reply #3 on: February 05, 2010, 10:16:45 am »
Quote
am not sure whether you noticed the inconsistency. sf::text.getrect() gives same height for "nnn" and "NNN" and ".....". but it gives bigger height for "nng"

I know. There's actually a reason for this behaviour, but I agree that it's inconsistent.

Quote
i may be wrong but i think that 1.5 didnt care about literals that exceeded the bottom line, it always returned the top-to-bottom-line-difference (which was to small for strings containing such literals).

I don't remember changing that, but maybe I did it a long time ago.

Anyway, this stuff will soon change in SFML 2, so don't worry and just wait and see ;)
Laurent Gomila - SFML developer

Boogiwoogie

  • Newbie
  • *
  • Posts: 19
    • View Profile
text.getrect() behaviour
« Reply #4 on: February 05, 2010, 10:52:31 am »
Quote from: "Laurent"
Quote
i may be wrong but i think that 1.5 didnt care about literals that exceeded the bottom line, it always returned the top-to-bottom-line-difference (which was to small for strings containing such literals).

I don't remember changing that, but maybe I did it a long time ago.

ok i looked it up and it seems that i was wrong, 1.5 and 2.0 have same behaviour on that one.

Quote from: "Laurent"
Anyway, this stuff will soon change in SFML 2, so don't worry and just wait and see ;)

i actually fixed my problem, sf::text.getcharactersize() is a value that doesnt change on different literals and can be used for scaling the text. so i stopped worrying and started waiting and seeing ;)

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
text.getrect() behaviour
« Reply #5 on: February 05, 2010, 01:51:14 pm »
I have encountered the same problem, and I have also used the workaround by GetCharacterSize(). However, I think in most cases the bounding rectangle is expected to be equally high, independently of containing a "j" or not (or it takes "n" in account, as well). At least, I can't imagine many cases where one wants to distinguish texts with a "j" and ones without. For all other cases, the user is forced to manually perform an adaption.

That's just my impression, it would be nice to see how other users think about it. I don't know either whether a change of this behaviour involves a lot of effort for you, Laurent.
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
text.getrect() behaviour
« Reply #6 on: February 05, 2010, 02:06:09 pm »
Quote
At least, I can't imagine many cases where one wants to distinguish texts with a "j" and ones without

Maybe the extra space will not be acceptable for click detection, in some situations. Some programs require very precise collision detection, even for text.

Quote
I don't know either whether a change of this behaviour involves a lot of effort for you, Laurent.

No, it's pretty easy to change.
Laurent Gomila - SFML developer

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
text.getrect() behaviour
« Reply #7 on: February 05, 2010, 02:27:38 pm »
Quote from: "Laurent"
Maybe the extra space will not be acceptable for click detection, in some situations. Some programs require very precise collision detection, even for text.
Okay, that might be true. But for those, the current approach is not sufficient, either (because of "n"). Maybe, there is even a distinction for each character required (dependent on what x coordinate you click), where a handmade function is necessary anyway.

Besides, do you plan to spend sf::Text an sf::Vector2f GetSize() const method for a more uniform interface compared to sf::Sprite? If so, a possibility would also be to return the character-independent size in this function...

By the way, I know the dilemma of keeping an interface small but still powerful. ;)
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
text.getrect() behaviour
« Reply #8 on: February 05, 2010, 02:42:23 pm »
Quote
But for those, the current approach is not sufficient, either (because of "n"). Maybe, there is even a distinction for each character required (dependent on what x coordinate you click), where a handmade function is necessary anyway.

I agree, the current solution is not the best one.

I'll implement something more consistent in SFML 2.
Laurent Gomila - SFML developer

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
text.getrect() behaviour
« Reply #9 on: February 05, 2010, 03:48:31 pm »
Great, thanks a lot! :)

Meanwhile, I have done some tests and I am currently using the following approach. The problem is, you can't just add GetCharacterSize() to GetRect().Top because the rectangle begins over the highest character and you have to take the scale into account. After experimenting a little, I found the factor 1.27. :D
Code: [Select]
sf::FloatRect GetBoundingRect(const sf::Text& Text)
{
sf::FloatRect Rect = Text.GetRect();

float Height = 1.27f * Text.GetCharacterSize() * Text.GetScale().y;
return sf::FloatRect(Rect.Left, Rect.Top, Rect.Right, Rect.Top + Height);
}

And here is a complete example that displays the bounding rectangles:
Code: [Select]
#include <SFML/Graphics.hpp>

sf::FloatRect GetBoundingRect(const sf::Text& Text)
{
sf::FloatRect Rect = Text.GetRect();

float Height = 1.27f * Text.GetCharacterSize() * Text.GetScale().y;
return sf::FloatRect(Rect.Left, Rect.Top, Rect.Right, Rect.Top + Height);
}

sf::Shape Bounds(const sf::FloatRect& Rect)
{
return sf::Shape::Rectangle(Rect.Left, Rect.Top, Rect.Right, Rect.Bottom,
sf::Color::Black, 1.f, sf::Color::Red);
}

int main()
{
sf::RenderWindow App(sf::VideoMode(400, 400), "title");
App.SetFramerateLimit(30);

sf::Text Normal("Normal");
Normal.SetPosition(150, 350);
Normal.SetColor(sf::Color::Yellow);
sf::Shape NormalRect = Bounds(GetBoundingRect(Normal));

sf::Text Special("Special");
Special.SetPosition(20, 20);
Special.SetColor(sf::Color::Yellow);
sf::Shape SpecialRect = Bounds(GetBoundingRect(Special));

sf::Text NormalScaled("Normal");
NormalScaled.SetPosition(200, 40);
NormalScaled.SetScale(2.f, 3.f);
NormalScaled.SetColor(sf::Color::Yellow);
sf::Shape NormalScaledRect = Bounds(GetBoundingRect(NormalScaled));

sf::Text SpecialScaled("Special");
SpecialScaled.SetPosition(20, 170);
SpecialScaled.SetScale(2.f, 3.f);
SpecialScaled.SetColor(sf::Color::Yellow);
sf::Shape SpecialScaledRect = Bounds(GetBoundingRect(SpecialScaled));

for (;;)
{
sf::Event Event;
while (App.GetEvent(Event))
{
if (Event.Type == sf::Event::KeyPressed || Event.Type == sf::Event::Closed)
return 0;
}

App.Clear();

App.Draw(NormalRect);
App.Draw(Normal);
App.Draw(SpecialRect);
App.Draw(Special);

App.Draw(NormalScaledRect);
App.Draw(NormalScaled);
App.Draw(SpecialScaledRect);
App.Draw(SpecialScaled);

App.Display();
}
}

Quite a hack, I know. If I forgot something, please say it. ;)
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
text.getrect() behaviour
« Reply #10 on: February 05, 2010, 03:59:06 pm »
Yep, the character size is more a global scale, it doesn't represent anything that you can measure on the rendered glyphs.

What about using the line spacing (which is available in sf::Font since a few weeks)? It should be more relevant, as the line spacing is usually calculated as ascent (the max height above the base line) + descent (the min height above the baseline) + 1 (the baseline thickness).
Laurent Gomila - SFML developer

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
text.getrect() behaviour
« Reply #11 on: February 05, 2010, 04:15:33 pm »
Quote from: "Laurent"
What about using the line spacing (which is available in sf::Font since a few weeks)?
Cool, I didn't know about it. I think it would look like this:
Code: [Select]
sf::FloatRect GetBoundingRect(const sf::Text& Text)
{
sf::FloatRect Rect = Text.GetRect();

float Height = Text.GetFont().GetLineSpacing(Text.GetCharacterSize()) * Text.GetScale().y;
return sf::FloatRect(Rect.Left, Rect.Top, Rect.Right, Rect.Top + Height);
}

The idea is not bad, and probably less error-prone than the above one. But it looks like the lower ends of characters like "j" are slightly overlapping the rectangles. Additionally, the text doesn't look vertically centered, which might be useful in some cases. To see what I mean, you can just test it by replacing the complete example's GetBoundingRect() function.

Alternatively, I could combine line spacing and magic numbers. :D
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
text.getrect() behaviour
« Reply #12 on: February 05, 2010, 04:24:03 pm »
It seems that adding 1 to the line spacing is enough to produce a perfect result.

Don't ask me why, I checked the FreeType documentation and I couldn't find an explanation.
http://www.freetype.org/freetype2/docs/glyphs/glyphs-3.html
The line spacing I return is the "height" that you can see on the glyph picture.

Quote
Additionally, the text doesn't look vertically centered, which might be useful in some cases

Ascent is always bigger than descent, ie the baseline is never centered ;)
Laurent Gomila - SFML developer

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
text.getrect() behaviour
« Reply #13 on: February 05, 2010, 04:42:39 pm »
Quote from: "Laurent"
It seems that adding 1 to the line spacing is enough to produce a perfect result.
Thanks, that works. I'll probably add 2 in order to have small extra space to the lower bound. ;)

Quote from: "Laurent"
Ascent is always bigger than descent, ie the baseline is never centered ;)
I don't mean the baseline itsself, but baseline + ascent/2 (I hope I use terms correctly, I mean the y coordinate of "-" inside an "H" for example). In my opinion, a string looks more esthetic if this point is located in the middle of a textbox (or whatever the bounding rectangle stands for).

By the way, thank you for the link, I am totally unexperienced in glyph metrics. :)
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
text.getrect() behaviour
« Reply #14 on: February 05, 2010, 04:49:14 pm »
Quote
I don't mean the baseline itsself, but baseline + ascent/2 (I hope I use terms correctly, I mean the y coordinate of "-" inside an "A" for example). In my opinion, a string looks more esthetic if this point is located in the middle of a textbox (or whatever the bounding rectangle stands for).

Ah, I see. I guess it depends on how the font is made.
Laurent Gomila - SFML developer