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

Author Topic: subpixel multi-channel text rendering for SFML: A demonstration  (Read 297 times)

0 Members and 2 Guests are viewing this topic.

GoS

  • Newbie
  • *
  • Posts: 1
    • View Profile
    • Email
This is more than a feature request - and also as yet less than a pull request. See attached image for example text output.

Objective: Make text rendered by SFML crisper on suitable monitors[1] by making use of Freetype's ability to supply position offsets for each of the red, green, and blue channels in glyph bitmap data. This feature got added to SDL during v3 development; SFML deserves no less.

[1] These being horizontally decimated LCD displays. Most LCD desktop- or laptop-type monitors qualify when in landscape orientation.

The below code is not yet suitable for a proper pull request. For starters, it provides no way for users of the library to control which Freetype glyph rendering option they would prefer. It is merely a demo.


You need:
1. A standard LCD desktop- or laptop-type monitor, in landscape orientation.
2. A working SFML development setup.
3. A program that displays text on screen using the sfml-graphics library. Text size should be anything from 8 to 12 points for the most obvious effect. The objective here is to make it display text as crisply on your LCD monitor as does a native GTK or Windows application.


Instructions:
Open the file <SFML>\src\SFML\Graphics\Font.cpp.
Find the method "Glyph Font::loadGlyph(". In this method, find "FT_LOAD_TARGET_NORMAL"; change to "FT_LOAD_TARGET_LCD". Find "FT_RENDER_MODE_NORMAL"; change to "FT_RENDER_MODE_LCD".

Now we need to make the SFML code cooperate with the new input from Freetype. Instead of one 8-bit input pixel per output pixel, we are now given three. So, find "Extract the glyph's pixels from the bitmap" and add the following code after the block "if (bitmap.pixel_mode == FT_PIXEL_MODE_MONO)":

        else if ((bitmap.pixel_mode == FT_PIXEL_MODE_LCD) || (bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V))
        {
            // Input pixels are 3x8 bit gray levels
            for (unsigned int y = padding; y < size.y - padding; ++y)
            {
                std::size_t index = padding + y * size.x;

                // Output is 32-bit RGBA. Advance x by three per output pixel.
                for (unsigned int x = padding; x < size.x - padding;)
                {
                    // Fill all three color channels. Compute and fill the alpha channel.
                    uint8_t r = pixels[x++ - padding];
                    uint8_t g = pixels[x++ - padding];
                    uint8_t b = pixels[x++ - padding];
                    int     a_calc = r + g + b; // XXX - check this for correctness
                    if (a_calc > 255)
                        a_calc = 255;
                    uint8_t a = (uint8_t)a_calc;

                    m_pixelBuffer[index * 4 + 0] = r;
                    m_pixelBuffer[index * 4 + 1] = g;
                    m_pixelBuffer[index * 4 + 2] = b;
                    m_pixelBuffer[index * 4 + 3] = a;
                    index++; // Advance index by one per three input pixels.
                }
                pixels += bitmap.pitch;
            }
        }
 

If these instructions are unclear, incorrect, or do not give you crisp output on an LCD monitor, please advise.

 

anything