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

Author Topic: sf::text not handling characters correctly  (Read 982 times)

0 Members and 1 Guest are viewing this topic.

Stauricus

  • Sr. Member
  • ****
  • Posts: 286
    • View Profile
    • Email
sf::text not handling characters correctly
« on: October 05, 2019, 07:58:24 pm »
hello
I'm having trouble drawing non ASCII character. i searched around, but did not found a good solution.
in the SFML window, I have this:


but when I print the same string to the console, it works:


inside the debugger the word is also correct, what makes me think its a problem in SFML interpretation of the string?


I have read the text tutorial, but I cant understand why just the SFML window is not showing the string correctly.
I tried many font types, of course all of them have the desider characters.
i'm using Linux, by the way.

this is the code:
#include <string>
#include <iostream>
#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Window/Event.hpp>
#include <SFML/Graphics/Font.hpp>
#include <SFML/Graphics/Text.hpp>

int main(){
    std::string str = "Opção olé";
    sf::Font font;
    font.loadFromFile("graphics/LondrinaSolid-Regular.otf");
    sf::Text text(str, font);
    sf::RenderWindow window(sf::VideoMode(400, 300), "SFML Text");
    std::cout << str;

    while (window.isOpen()){
        sf::Event event;
        while (window.pollEvent(event)){
            if (event.type == sf::Event::Closed)
                window.close();
        }
        window.clear();
        window.draw(text);
        window.display();
    }
    return 0;
}

I also tried changing the sf::Text creation line to
sf::Text text(sf::String(str), font);
but I have the same results.

do I have to change every string in my code to wstring? that would be a pain in the neck, mainly because too many functions take just strings as arguments  :-\

texus

  • Sr. Member
  • ****
  • Posts: 484
    • View Profile
    • TGUI
    • Email
Re: sf::text not handling characters correctly
« Reply #1 on: October 05, 2019, 11:05:40 pm »
Maybe there are better ways than what I'm going to say, but this is what I found out when trying to use unicode.

If a string is encoded as UTF-8, you can convert the string to an sf::String like this:
sf::String::fromUtf8(str.begin(), str.end())

You could force a UTF-8 encoding like this:
std::string str = u8"Opção olé";

This will however no longer compile when using c++20.
What you could do instead is manually encoding the bytes as UTF-8 (which will also assure that your code keeps working when your cpp file is saved with a different encoding):
std::string str = "Op\xc3\xa7\xc3\xa3o ol\xc3\xa9";

If you do that and change the creation of the text object to the following then it should work:
sf::Text text(sf::String::fromUtf8(str.begin(), str.end()), font);

When writing this I realized that this might break the std::cout though. Linux typically uses UTF-8 as locale, so it will work fine, but keep in mind that it is possible that on Windows the cout line might start spitting out garbage characters.

Note: if you don't care about Windows support and you assume that all the users of your program use the UTF-8 locale (which will be the case on practically any linux), then you don't have to encode the strings manually. Your code will work fine if you only add the sf::String::fromUtf8 part and leave the declaration of str like it is in your example.
TGUI: C++ SFML GUI
TGUI.Net: C# binding for TGUI

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 9841
    • View Profile
    • development blog
    • Email
Re: sf::text not handling characters correctly
« Reply #2 on: October 05, 2019, 11:20:52 pm »
Reads to me like the font you're using doesn't have any of the special characters you're trying to use. Check that the font supports çãé.
Official FAQ: https://www.sfml-dev.org/faq.php
Nightly Builds: https://www.nightlybuilds.ch/
——————————————————————
Dev Blog: https://dev.my-gate.net/
Thor: http://www.bromeon.ch/libraries/thor/

Stauricus

  • Sr. Member
  • ****
  • Posts: 286
    • View Profile
    • Email
Re: sf::text not handling characters correctly
« Reply #3 on: October 06, 2019, 08:28:20 pm »
if you don't care about Windows support and you assume that all the users of your program use the UTF-8 locale (which will be the case on practically any linux), then you don't have to encode the strings manually. Your code will work fine if you only add the sf::String::fromUtf8 part and leave the declaration of str like it is in your example.

actually i'd like the final code to be run both Linux and Windows... and this is the hardest part. if I change every string to wstring (which is suposed to work on Windows), my terminal emulator (in Debian) becomes unable to output the characters correctly  ???
isn't there some universal way to work in both cases?  :P


Reads to me like the font you're using doesn't have any of the special characters you're trying to use. Check that the font supports çãé.

yeah, it works in other programs, like Inkscape, etc

texus

  • Sr. Member
  • ****
  • Posts: 484
    • View Profile
    • TGUI
    • Email
Re: sf::text not handling characters correctly
« Reply #4 on: October 07, 2019, 10:56:32 am »
Quote
isn't there some universal way to work in both cases?
Not that I know of. The u16string and u32string from c++11 and especially the u8string from c++20 looked promising to store strings while being explicitly about the encoding (while std::string and std::wstring depend on the platform). But you can only use them to store strings in, as soon as you need to do something with it (like printing to to the screen) you need to manually convert them again anyway.

Using std::wstring sounded like the most universal ways to me. But I just tried and on manjaro with cinnamon it printed "?" in the terminal when using wstring and wcout in both XTerm and GNOME Terminal.
So if you want to print the text to the command line on both Windows and Linux then you might need some platform dependent code (unless there is some way that I don't know about yet, keep in mind that I never actually developed a program that uses unicode characters).

Using std::wstring will allow easier interaction with sf::String as you won't need to use code like the String::fromUtf8 to correctly display the characters, you would just be able to convert the std::wstring to an sf::String implicitly.

Then to output to the screen, instead of doing cout or wcout you would call a function that will call either one depending on the platform. As you can see, I don't know a very efficient way to go from sf::String to an UTF-8 std::string (the toAnsiString() function can't be used because it removed all non-ansi characters), but at least this method works. I didn't test the Windows implementation.
void output(const sf::String& str)
{
#ifdef SFML_SYSTEM_LINUX
    const std::basic_string<sf::Uint8>& tmpBuffer1 = str.toUtf8();
    const std::string tmpBuffer2(tmpBuffer1.begin(), tmpBuffer1.end());
    std::cout << tmpBuffer2;
#else // Assuming Windows is the only other platform
    std::wcout << str.toWideString();
#endif
}
(You might need some changes if you want to add a newline behind it or if you mix it with other cout statements in your code)

Update:
I looked up how to use std::wcout on linux. It turns out you can use wcout on linux if you add something like the following line at the start of your code (whether you want to actually do so is up to you, this might fail if the locale is not installed + going this route will likely also result in platform dependent code).
std::locale::global (std::locale ("en_US.UTF-8"));
« Last Edit: October 07, 2019, 10:59:36 am by texus »
TGUI: C++ SFML GUI
TGUI.Net: C# binding for TGUI

Stauricus

  • Sr. Member
  • ****
  • Posts: 286
    • View Profile
    • Email
Re: sf::text not handling characters correctly
« Reply #5 on: October 07, 2019, 01:07:55 pm »
Well, it works good, so it will be it.
Thanks for the help.  ;D