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

Author Topic: [solved] Issues drawing characters outside ASCII char set  (Read 4056 times)

0 Members and 1 Guest are viewing this topic.

krvju

  • Newbie
  • *
  • Posts: 3
    • View Profile
[solved] Issues drawing characters outside ASCII char set
« on: July 18, 2024, 12:40:18 am »
Hello, I am having issues printing non-ASCII characters on Windows.

    //i have also tried wide strings and u8 encoded strings
    sf::String str= sf::String("привет");
    std::cout << str.toAnsiString() << std::endl; //outputs "привет" to console
    sf::Text text_block = sf::Text(str, font, 48);
    window.draw(text_block);
 

I have tried the font.hasGlyph() function too, but I am not sure if I am using it correctly :)))
It does not exit the program here so the characters should exist in the font file
    //cyrillic п character in utf-32 bytecode
    sf::Uint32 cyrillic_p = 0x0000043f;
    if (!font.hasGlyph(sf::Uint32(cyrillic_p))) {
        std::cerr << "font error" << std::endl;
        exit(1);
    }
 

In the attached image I am using the Arial system font which should have the cyrillic alphabet in it. I have also tried it with three other system fonts and three downloaded fonts with the same results.
« Last Edit: July 20, 2024, 05:01:57 pm by krvju »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11032
    • View Profile
    • development blog
    • Email
Re: Issues drawing characters outside ASCII char set
« Reply #1 on: July 19, 2024, 02:45:07 pm »
You'll need to use wide-string encoding for your string literals:
auto str = sf::String(L"привет");

This is using SFML master:
#include <SFML/Graphics.hpp>

int main()
{
        auto window = sf::RenderWindow{ sf::VideoMode{{500, 500}}, "Hello World" };
        window.setFramerateLimit(144);

        auto font = sf::Font::openFromFile("C:\\Windows\\Fonts\\Arial.ttf").value();

        auto text = sf::Text{ font };
        text.setString(L"привет");

        while (window.isOpen())
        {
            while (auto event = window.pollEvent())
            {
                if (event.value().is<sf::Event::Closed>())
                {
                                window.close();
                }

                        window.clear();
                        window.draw(text);
                        window.display();
            }
        }
}
 
« Last Edit: July 19, 2024, 03:08:45 pm by eXpl0it3r »
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

krvju

  • Newbie
  • *
  • Posts: 3
    • View Profile
Re: Issues drawing characters outside ASCII char set
« Reply #2 on: July 20, 2024, 02:00:30 am »
Thanks for the reply : )

I looked into it a bit more and the problem was that the program couldn't show understand any character wider than 0xFF when in a wide string, anything longer had to be manually added (for example wide_str += 0x43f;). I found a utf_8 decoder online and that solved the problem :) I think it only works if the source file is utf_8 encoded but I am not sure.

#include <SFML/Graphics.hpp>
#include <Windows.h>

//source: https://stackoverflow.com/a/3999597/22872825
std::wstring utf8_decode(const std::string &str)
{
    if( str.empty() ) return std::wstring();
    int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
    std::wstring wstrTo( size_needed, 0 );
    MultiByteToWideChar                  (CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);
    return wstrTo;
}

int main(){
    auto context_settings = sf::ContextSettings();
    auto window = sf::RenderWindow{ sf::VideoMode{{500, 500}}, "Hello World", sf::State::Windowed, context_settings};
    window.setFramerateLimit(60);
    auto font = sf::Font::openFromFile("C:\\Windows\\Fonts\\Arial.ttf").value();
    auto text = sf::Text{ font };

    std::string str = "привет";
    std::wstring new_str = utf8_decode(str);
    text.setString(new_str);

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

fallahn

  • Hero Member
  • *****
  • Posts: 507
  • Buns.
    • View Profile
    • Trederia
Re: Issues drawing characters outside ASCII char set
« Reply #3 on: July 20, 2024, 09:47:37 am »
SFML actually has this built in. https://www.sfml-dev.org/documentation/2.6.1/classsf_1_1String.php#aa7beb7ae5b26e63dcbbfa390e27a9e4b

With C++17:
std::string str = u8"привет";
text.setString(sf::String::fromUtf8(str.begin(), str.end()));
 

or if you want to use wstring (assuming wchar_t is 16 bit on your platform, it might not be)

std::wstring str = L"привет";
text.setString(sf::String::fromUtf16(str.begin(), str.end()));
 

If you want to read utf8 from a file you can copy it byte by byte into a vector and do the same thing:

std::vector<std::uint8_t> fileBytes;
//read file into fileBytes here

text.setString(sf::String::fromUtf8(fileBytes.begin(), fileBytes.end()));
 

krvju

  • Newbie
  • *
  • Posts: 3
    • View Profile
Re: Issues drawing characters outside ASCII char set
« Reply #4 on: July 20, 2024, 05:01:04 pm »
Hi, I didn't know this had been built in, thanks for letting me know! I'll use that instead of the Windows one since it has been made more simpler :))))