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

Author Topic: sf::Font Change & sf::Text Notification  (Read 15288 times)

0 Members and 1 Guest are viewing this topic.

FRex

  • Hero Member
  • *****
  • Posts: 1841
  • Not doing gamedev/using SFML lately
    • View Profile
    • Email
sf::Font Change & sf::Text Notification
« on: January 03, 2014, 03:16:57 am »
Edit: Moved the thread to SFML development and give a more descriptive title in light of the sub-forum change

#include <SFML/Graphics.hpp>
#include <cstdlib>

void breakFont(sf::Font& f)
{
    for (int i = 0; i < 30; ++i)
    {
        char a = 'a' + std::rand() % ('z' - 'a' + 1); //random char from 'a'..'z'
        f.getGlyph(a, 30u, false);
    }
}

int main(int argc, char * argv[])
{
    std::srand(std::time(0x0));

    sf::RenderWindow app(sf::VideoMode(640u, 480u), "Font");
    app.setFramerateLimit(30u);
    bool broken = false;

    const std::string filename("OpenDyslexic-Regular.ttf");

    sf::Font font;
    font.loadFromFile(filename);

    sf::Text text("font is broken", font, 30u);

    while (app.isOpen())
    {
        sf::Event eve;
        while (app.pollEvent(eve))
        {

            if (eve.type == sf::Event::Closed) app.close();

            if (!broken && eve.type == sf::Event::KeyPressed)
            {
                broken = true;
                font.loadFromFile(filename);
                breakFont(font);
            }

        }

        app.clear();
        app.draw(text);
        app.display();
    }

}
 
Change filename to any font you want to use, it shouldn't matter, I used OpenDyslexic from http://opendyslexic.org/

Basically sf::Text displays garbage when sf::Font is reloaded and glyphs of same size get loaded in other order, if no glyphs get loaded it'll just display nothing, but is well defined, operator[] on map will insert new default constructed GlyphTable and return it's default constructed sf::Texture resulting in nothing.

It's a non issue for almost all sane use cases but I'm putting it out here with example so that it's known, I couldn't find it when I searched, if you want to ensure sf::Text is ok you can call text.setString(text.getString()) clear the string and set it again to force updateGeometry to be called (you can't call it directly, it's private).
« Last Edit: October 03, 2022, 07:50:12 pm by eXpl0it3r »
I'm not using SFML nor doing any gamedev lately.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10390
    • View Profile
    • development blog
    • Email
Re: Text garbage after Font reload
« Reply #1 on: January 05, 2015, 10:53:51 am »
Hmmm, what's actually also kind of scary is that simply reloading the font, will make the text vanish:

#include <SFML/Graphics.hpp>

int main()
{
    sf::RenderWindow app(sf::VideoMode(640u, 480u), "Font");
    app.setFramerateLimit(30u);
    bool broken = false;

    const std::string filename("DroidSans.ttf");

    sf::Font font;
    font.loadFromFile(filename);

    sf::Text text("font is broken", font, 30u);

    while (app.isOpen())
    {
        sf::Event eve;
        while (app.pollEvent(eve))
        {

            if (eve.type == sf::Event::Closed) app.close();

            if (!broken && eve.type == sf::Event::KeyPressed)
            {
                broken = true;
                font.loadFromFile(filename);
                text.setFont(font);
                text.setCharacterSize(30u);
                text.setString("font is broken");
            }

        }

        app.clear();
        app.draw(text);
        app.display();
    }

}

While you usually don't reload fonts, I think this is still an issue that should get fixed. ;)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://dev.my-gate.net/

FRex

  • Hero Member
  • *****
  • Posts: 1841
  • Not doing gamedev/using SFML lately
    • View Profile
    • Email
Re: Text garbage after Font reload
« Reply #2 on: January 05, 2015, 05:50:07 pm »
I like how you respond a bit over a year later. ;D
It's not too real of a problem... but if you really want to fix it, putting an unsinged in sf::Font, bumping it on reload and on setPixelated(because you probably come from that thread) and then saving and checking it in ensureGeometryUpdate will work.
I'm not using SFML nor doing any gamedev lately.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10390
    • View Profile
    • development blog
    • Email
Re: Text garbage after Font reload
« Reply #3 on: January 05, 2015, 06:41:57 pm »
Oh right we're in 2015. ;D

I don't really understand your suggested fix, but I hope others will take a look.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://dev.my-gate.net/

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Text garbage after Font reload
« Reply #4 on: January 05, 2015, 07:54:02 pm »
He suggests that sf::Font maintains a "change id", which it increments every time the whole set of glyphs are invalidated. So if a sf::Text sees that the font id has changed (compared to the one the font had when it last built its vertex array), then the font has changed and it must discard and rebuild its own vertex array.

It is similar to what sf::Texture does so that sf::RenderTarget knows when it has changed, and can invalidate its internal texture cache.

This is probably the only way to handle this, if we don't want the font to be able to directly notify objects that depend on it, but I can't think of a clean way to add such a function. That would be a private member of sf::Font, and sf::Text would be declared as friend to access it?
Laurent Gomila - SFML developer

FRex

  • Hero Member
  • *****
  • Posts: 1841
  • Not doing gamedev/using SFML lately
    • View Profile
    • Email
Re: Text garbage after Font reload
« Reply #5 on: January 05, 2015, 10:27:37 pm »
In my own code where I have similar situation I call that variable dirtyness and it has a public getter.
There is no reason to make it 100% private because that'd harm any new text layout class that isn't sf::Text because they couldn't check for that.

Quote
Hmmm, what's actually also kind of scary is that simply reloading the font, will make the text vanish:
Rendering garbage sounded more dramatic and I originally wanted to make the garbage spell out something meaningful by manipulating the order of loading glyphs but it didn't work. :P
« Last Edit: January 05, 2015, 10:30:47 pm by FRex »
I'm not using SFML nor doing any gamedev lately.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Text garbage after Font reload
« Reply #6 on: January 05, 2015, 10:50:20 pm »
Quote
In my own code where I have similar situation I call that variable dirtyness and it has a public getter.
Yes, I guess we can hardly find a better name for this... :(
Laurent Gomila - SFML developer

Jesper Juhl

  • Hero Member
  • *****
  • Posts: 1405
    • View Profile
    • Email
Re: Text garbage after Font reload
« Reply #7 on: January 06, 2015, 01:04:37 am »
Yes, I guess we can hardly find a better name for this... :(
"tainted" would be an option.

Gambit

  • Sr. Member
  • ****
  • Posts: 283
    • View Profile
Re: Text garbage after Font reload
« Reply #8 on: January 06, 2015, 02:37:04 am »
Or "invalidated".

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Text garbage after Font reload
« Reply #9 on: January 06, 2015, 07:52:17 am »
Anything in -ed is wrong, because this is an ID, not a boolean.
Laurent Gomila - SFML developer

Gambit

  • Sr. Member
  • ****
  • Posts: 283
    • View Profile
Re: Text garbage after Font reload
« Reply #10 on: January 06, 2015, 08:03:32 am »
How could "refreshCount" then?

FRex

  • Hero Member
  • *****
  • Posts: 1841
  • Not doing gamedev/using SFML lately
    • View Profile
    • Email
Re: Text garbage after Font reload
« Reply #11 on: January 07, 2015, 02:26:52 pm »
Here it is, I named the variable Laurent:
https://gist.github.com/FRex/ced31eca2872ca610c96
 ;D ;D ;D


Ok, jokes aside, the name can be changed later but I'm asking about all the other code:
https://github.com/FRex/SFML

The if in Text.cpp and the surrounding code is a bit :( but otherwise I think it looks fine:
https://github.com/FRex/SFML/blob/master/src/SFML/Graphics/Text.cpp#L245
I'm not using SFML nor doing any gamedev lately.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Text garbage after Font reload
« Reply #12 on: January 07, 2015, 02:33:51 pm »
Quote
// Bump Laurent
++m_Laurent;
Ouch!
Laurent Gomila - SFML developer

FRex

  • Hero Member
  • *****
  • Posts: 1841
  • Not doing gamedev/using SFML lately
    • View Profile
    • Email
Re: Text garbage after Font reload
« Reply #13 on: January 07, 2015, 02:44:24 pm »
Do you want these unsigned ints to be sf::Uint64 instead? (For the use case where someone somehow makes exactly 2^32 loads between two draws.)

Also, special thanks to exploiter for merging xcb last night. I had to install xcb-devel, xcb-util-devel, xcb-util-image-devel and xcb-util-wm-devel to get SFML to compile. :P
Well.. at least I confirmed it still works on Fedora 21.
I'm not using SFML nor doing any gamedev lately.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Text garbage after Font reload
« Reply #14 on: January 07, 2015, 03:21:30 pm »
Quote
Do you want these unsigned ints to be sf::Uint64 instead? (For the use case where someone somehow makes exactly 2^32 loads between two draws.)
Yes, this can't hurt, and will be more consistent with the one in sf::Texture (*).

(*) I'm surprised you still haven't suggested to apply the same API (public getLaurent() ;D) to sf::Texture.
Laurent Gomila - SFML developer