SFML community forums

Help => Graphics => Topic started by: dreadward07 on December 10, 2023, 05:09:19 am

Title: How to render in color emojis?
Post by: dreadward07 on December 10, 2023, 05:09:19 am
Hello! I am trying to render an emoji on screen using Google's Noto font. However, it always either renders blank squares, or nothing at all. Here's a link to the download:
https://fonts.google.com/noto/specimen/Noto+Color+Emoji (https://fonts.google.com/noto/specimen/Noto+Color+Emoji)

And here's the small amount of code I've written to try and display it.

#include <SFML/Graphics.hpp>

int main()
{

        sf::RenderWindow window(sf::VideoMode(640, 480), "Emoji", sf::Style::Close);
        sf::Event event;
        sf::Clock clock;
        while (window.isOpen())
        {
                while(window.pollEvent(event))
                {
                        switch (event.type)
                        {
                        case(sf::Event::Closed):
                        {
                                window.close();
                        }
                        }
                }

                window.clear();

                sf::Font font;
                font.loadFromFile("NotoColorEmoji-Regular.ttf");
               
                sf::Text text;
                text.setFont(font);
                text.setString("Test Text");

                window.draw(text);

                window.display();
        }

        return 0;
}

What am I doing wrong? I'm pretty sure this font doesn't contain any standard characters, which makes sense, but if that's the case, how do I render anything at all? Do I use Unicode? Glyphs? If it's either, then how do I use them?
I'm VERY new to the concept of fonts and character encoding as a whole, so I understand if I've missed something completely obvious.

Thank you for your help!
Title: Re: How to render in color emojis?
Post by: fallahn on December 10, 2023, 01:11:44 pm
Short story: You can't; SFML doesn't support coloured fonts. However there is a monochrome version of the noto emoji font which might work: https://fonts.google.com/noto/specimen/Noto+Emoji

Long story: I've been through this experience recently with my own engine (https://github.com/fallahn/crogine/tree/golf-1.15), which uses SFML fonts/text/string as a basis for text renderering. Here's a brief summary of what I've found:

As you point out one font won't contain all the emojis and text characters. You need to use multiple fonts with multiple strings/text which can make it difficult to mix emojis with text in SFML. DearImGui takes an interesting approach which allows assigning multiple fonts to different ranges of unicode - you can read about it here (https://github.com/ocornut/imgui/blob/master/docs/FONTS.md#using-colorful-glyphsemojis).

I used this approach to modify what was essentially SFML's font class to allow loading multiple ttf files into a single Font (https://github.com/fallahn/crogine/blob/golf-1.15/samples/golf/src/GolfGame.cpp#L861), mapping them to different character ranges. This would be a nice feature, I think, to add to SFML.

SFML's fonts don't support colour - however they *could* if the way the underlying freetype library is used was changed slightly. Again, this would be a nice addition to SFML. *HOWEVER* that being said, while this will apparently work with Windows built in emoji font (C:/Windows/Fonts/seguiemj.ttf - license forbids redistribution) it still doesn't work with the colour format used by Google's Noto colour font  ::)

To print emojis with sf::String is relatively easy, though you will probably have to use codepoints directly, rather than string literals
Code: [Select]
sf::String str(u8"🌙");
This might work for single codepoint emojis, but for multi-point emojis you'll need to combine them yourself:
Code: [Select]
sf::String str(0x2600);
str += sf::String(0xFE0F);

Emojipedia (https://emojipedia.org/sun#technical) is a good reference source - the technical tab will list any codepoints you need to combine.

HTH
Title: Re: How to render in color emojis?
Post by: dreadward07 on December 10, 2023, 04:46:24 pm
I tried using sf::String and the seguiemj font, as Noto also shows blank boxes

sf::Font font;
font.loadFromFile("C:/Windows/Fonts/seguiemj.ttf");

sf::Text text;
text.setFont(font);

text.setString(u8"🌙");

window.draw(text);

However this displays the following:
https://ibb.co/Lrx0YwB (https://ibb.co/Lrx0YwB)
Title: Re: How to render in color emojis?
Post by: Hapax on December 10, 2023, 08:51:02 pm
It doesn't look like sf::String (https://www.sfml-dev.org/documentation/2.6.1/classsf_1_1String.php) takes a UTF-8 string as a parameter. It seems to presume any chains of 8-bit characters (e.g. an std::string) is an "ANSI string". This is not Unicode so you cannot pass Unicode to sf::String with UTF-8 in its constructor.

Maybe try UTF-16 (using a wide string) or UTF-32 (string of sf::Uint32).

That said, you can create an sf::String with fromUtf8 (https://www.sfml-dev.org/documentation/2.6.1/classsf_1_1String.php#aa7beb7ae5b26e63dcbbfa390e27a9e4b) and then assign it to your actual string. e.g.:
std::string uStr{ u8"🌙" };
sf::String str{ sf::String::fromUtf8(uStr.begin(), uStr.end()) };
I'd expect that to work but I haven't tested it :P I'm 100% on if it'll accept those iterators.