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

Author Topic: sf::Font as static class member problem  (Read 6526 times)

0 Members and 1 Guest are viewing this topic.

netrick

  • Full Member
  • ***
  • Posts: 174
    • View Profile
sf::Font as static class member problem
« on: August 15, 2012, 09:11:41 pm »
I'm writing wrapper for displaying text and I have a problem that I cant solve.

Class header:
Code: [Select]
class CRender
{
public:
static sf::Font openSans; //this is my problem, I'll explain it below this code
void write(string & text, sf::RenderWindow & window, short int x, short int y, short int size = 30, sf::Font & font = openSans);
};
So i want to load font from file into the openSans object once, and then use it as default font in my function. Complilator said me that if I want to have default value in my "write" function it must be static member. Okay, no problem.

So there is my class' cpp file:
Code: [Select]
sf::Font CRender::openSans.loadFromFile("data/fonts/SourceSansPro-Regular.ttf"); //and this is forbidden

void CRender::write(string & text, sf::RenderWindow & window, short int x, short int y, short int size, sf::Font & font)
{
sf::Text temp(text, font, size);
temp.setPosition(x, y);
window.draw(temp);
}
In first line of this cpp file i get error C2143: syntax error : missing ';' before '.'.
I have no idea what to do to have that font object with preloaded font ready to use in my function. Any ideas how to do it?

The reason may be that sf::Font doesn't have load from file constructor, maybe if I rewrite its constructor it will solve the problem? Coz I think that using constructor to initialize static member is allowed.

edit:
I'm using sfml 2.0 ofc, compiler is VC++ 2008 so maybe C++ 11 would allow to do it without problems, if you just know something please reply.

Thanks
« Last Edit: August 15, 2012, 09:17:26 pm by netrick »

FRex

  • Hero Member
  • *****
  • Posts: 1845
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: sf::Font as static class member problem
« Reply #1 on: August 15, 2012, 10:40:01 pm »
I'm not sure but try removing sf::Font from
sf::Font CRender::openSans.loadFromFile("data/fonts/SourceSansPro-Regular.ttf");
You're not initializing that static sf::Font, you're calling one of it's methods.
Back to C++ gamedev with SFML in May 2023

netrick

  • Full Member
  • ***
  • Posts: 174
    • View Profile
Re: sf::Font as static class member problem
« Reply #2 on: August 15, 2012, 10:46:46 pm »
Nah it doesn't work too :/ the problem is that i can't initialize that font object because it has no load-from-file constructor. I must call that method, but it's just impossible to do so (doing that in CRender constructor doesn't work too). Unless someone knows C++ good and can give me advice, I think the only way is add load-from-file constructor and recompile SFML, it's easy but I'd like to avoid it to keep my code clean, simple and portable, so I'm looking for better solution.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: sf::Font as static class member problem
« Reply #3 on: August 15, 2012, 10:48:04 pm »
You can't call a function during initialization of an object, you can only choose which constructor to use.

There's an easy workaround though, using the copy constructor:
sf::Font createFont()
{
    sf::Font font;
    font.loadFromFile("data/fonts/SourceSansPro-Regular.ttf");
    return font;
}

sf::Font CRender::openSans(createFont());

But loading SFML resources at global scope is strongly disadvised, it may lead to undefined behaviour. You should rather add an init() function that you call at the beginning, to initialize your renderer's internal stuff.
Laurent Gomila - SFML developer

netrick

  • Full Member
  • ***
  • Posts: 174
    • View Profile
Re: sf::Font as static class member problem
« Reply #4 on: August 15, 2012, 10:51:51 pm »
Thank's Lauren, that's brilliant!
And well, my CRender constructor loads all textures etc and handles errors, but unfortunately I can't initialize static member in constructor. Maybe I'll just leave constructor empty and make init() function? It will be the same and allow me to handle that static font object properly too. Thanks again

FRex

  • Hero Member
  • *****
  • Posts: 1845
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: sf::Font as static class member problem
« Reply #5 on: August 15, 2012, 11:05:48 pm »
That works too but it kind of abuses class slicing so..  :(
class MyFont : public sf::Font
{
public:
        MyFont(const std::string& font_to_load){loadFromFile(font_to_load);}
};
 
« Last Edit: August 15, 2012, 11:09:55 pm by FRex »
Back to C++ gamedev with SFML in May 2023

netrick

  • Full Member
  • ***
  • Posts: 174
    • View Profile
Re: sf::Font as static class member problem
« Reply #6 on: August 15, 2012, 11:12:26 pm »
Thanks that's also a good solution. However, I think I have another problem. I can't initialize static member in non-constructor function too. And I really want to handle errors (no crash when removing font file). I think the workaround is too integrate createFont() from Lauren's solution with my error handling system and it will solve all problems.
edit:
Of course the same applies to FRex's solution, I'll just do some error handling in that constructor.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: sf::Font as static class member problem
« Reply #7 on: August 16, 2012, 08:06:16 am »
Quote
I can't initialize static member in non-constructor function too.
Of course you can, what's the problem with that?

But in first place, why do you need this static font member? There's a much cleaner solution to your "default argument" issue:
void CRender::write(string & text, sf::RenderWindow & window, short int x, short int y, short int size)
{
        write(text, window, x, y, size, openSans);
}

void CRender::write(string & text, sf::RenderWindow & window, short int x, short int y, short int size, sf::Font & font)
{
        sf::Text temp(text, font, size);
        temp.setPosition(x, y);
        window.draw(temp);
}

And... this "C" design where everything's done with functions will not give you the best performances. Creating a new sf::Text object everytime you draw text is very expensive, especially since your texts will most likely never change. It's much more efficient to create all the resources and entities to draw at init time, update them when needed and then what's left to be done 60 times per second is only to draw them.
« Last Edit: August 16, 2012, 08:09:46 am by Laurent »
Laurent Gomila - SFML developer

netrick

  • Full Member
  • ***
  • Posts: 174
    • View Profile
Re: sf::Font as static class member problem
« Reply #8 on: August 16, 2012, 10:52:33 am »
Thanks. So it looks like the best solution is to make simple container based resource manager with all needed sf::Text instances. Well I wanted easy solution to write, because setting all sf::Text objects at startup isn't very convenient and at one moment I may need 5 of them and at another i may need 30, so I think resource manager is the best way to go.
And if it comes to initialize static member in function VC 2008 gives me an error (doing it outside of any function works flawlessy). Well, maybe I'm just doing something wrong.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: sf::Font as static class member problem
« Reply #9 on: August 16, 2012, 11:13:40 am »
Quote
And if it comes to initialize static member in function VC 2008 gives me an error (doing it outside of any function works flawlessy). Well, maybe I'm just doing something wrong.
You still have to define (initialize) static instances in a cpp file outside any function, but then you can use these objects like any other, in any function.

class Blop
{
    // declaration
    static sf::Font font;

    Blop();
};

// definition
sf::Font Blop::font;

Blop::Blop()
{
    font.loadFromFile(...);
}

Quote
Thanks. So it looks like the best solution is to make simple container based resource manager with all needed sf::Text instances. Well I wanted easy solution to write, because setting all sf::Text objects at startup isn't very convenient and at one moment I may need 5 of them and at another i may need 30, so I think resource manager is the best way to go.
Managers can be ok for shared resources such as textures or sounds, but why would you need them for text? Can't each text be stored and initialized in its owner class? Low-level graphics entities are usually part of higher-level classes that have their own init/update/draw cycle.
« Last Edit: August 16, 2012, 11:15:43 am by Laurent »
Laurent Gomila - SFML developer

netrick

  • Full Member
  • ***
  • Posts: 174
    • View Profile
Re: sf::Font as static class member problem
« Reply #10 on: August 16, 2012, 12:40:20 pm »
Yes I know it about static members, but I misunderstood you (I thought that you said that I can initialize it in function). I already have resource manager for textures implemented. Any why do I need resource manager for text? Well for example when I load map, I load quests too. On one map I have 20 quests, on another only 2, and when the quest had been finished it can be not 20, but 19 quest texts to load etc. And loading quest text from file isn't fast solution, so I think I need some kind of manager. Or maybe I'm wrong again and there is simpler solution?

edit:
Well of course I can just have vector of CQuest in my CMap class, and just load every text that can be displayed on map without caring if it will be ever used. That's simple, but it's not memory efficient. However I think text objects are rather small, so I think you are right, I will just keep it simple without any text manager.
« Last Edit: August 16, 2012, 12:46:31 pm by netrick »