首页 > 解决方案 > 使用 FreeType 和 SDL2 渲染文本会生成白色方块而不是字符

问题描述

我正在尝试获得一个基本项目来使用 SDL2 和 FreeType 呈现文本,但它所呈现的只是白色方块而不是每个字符。我正在渲染每个 glygh 并将像素数据转换为SDL_Surfacewith SDL_CreateRGBSurfaceFrom()。我尝试弄乱 rgb 组件的位掩码、像素的深度,甚至表面的混合模式,但到目前为止,这些都没有奏效。

这是相关的代码位。字体在文件的早期正确加载,我在加载后设置字体的大小。什么可能导致字符显示为空白方块?

#include <sdl.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_BITMAP_H
#include FT_OUTLINE_H

#include <iostream>

/// Forward declaration
void Init();
void DeInit();
void Input();
void Update();
void Draw();

/// Memory
SDL_Window* window;
SDL_Surface* target;
FT_Library ftLib;
FT_Bitmap ftTarget;
FT_Face ftFace;

bool running = true;
int x = 0;
int y = 32;

/// Functions
void DrawBitmap(FT_Bitmap bm, int x, int y);

int main(int argc, char* argv[]) {
    Init();
    while (running) {
        Input();
        Update();
        Draw();
    }
    DeInit();

    return 0;
}

void Init() {
    // Init
    SDL_Init(SDL_INIT_EVERYTHING);
    window = SDL_CreateWindow("FreeType Test", 1920/2-600/2, 1080/2-400/2, 600, 400, 0);
    FT_Init_FreeType(&ftLib);
    FT_New_Face(ftLib, "C:\\Windows\\Fonts\\Arial.ttf", 0, &ftFace);
    FT_Set_Char_Size(ftFace, 12 << 6, 12 << 6, 72, 72);

    // Setup
    target = SDL_GetWindowSurface(window);
}

void DeInit() {
    // DeInit
    FT_Done_Face(ftFace);
    FT_Done_FreeType(ftLib);
    SDL_DestroyWindow(window);
    SDL_Quit();
}

void Input() {
    SDL_Event e;
    while (SDL_PollEvent(&e)) {
        switch (e.type) {
        case SDL_QUIT:
            running = false;
            break;
        }
    }
}

void Update() {
    // nothing for now
}

void Draw() {
    SDL_FillRect(target, nullptr, SDL_MapRGBA(target->format, 128, 128, 0, 255));

    // Draw text
    constexpr char text[] = "This is cool B)";
    for (int n = 0; n < sizeof(text); n++)
    {
        FT_Load_Char(ftFace, text[n], FT_LOAD_RENDER);

        DrawBitmap(ftFace->glyph->bitmap, x + ftFace->glyph->bitmap_left, y - ftFace->glyph->bitmap_top);

        x += ftFace->glyph->advance.x >> 6;
        y += ftFace->glyph->advance.y >> 6;
    }

    x = 0;
    y = 32;

    SDL_UpdateWindowSurface(window);
    SDL_Delay(10);
}

void DrawBitmap(FT_Bitmap bm, int x, int y) {
    SDL_Surface* glyph = SDL_CreateRGBSurfaceFrom(bm.buffer, bm.width, bm.rows, 8, bm.pitch, 0, 0, 0, 0xFF);
    SDL_SetSurfaceBlendMode(glyph, SDL_BlendMode::SDL_BLENDMODE_NONE);
    SDL_Rect dest = { x, y, 0, 0 };
    SDL_BlitSurface(glyph, nullptr, target, &dest);
    SDL_FreeSurface(glyph);
}

标签: c++sdlfreetype

解决方案


您可以设置调色板:

void DrawBitmap(FT_Bitmap bm, int x, int y)
{
    SDL_Surface* glyph = SDL_CreateRGBSurfaceFrom(bm.buffer, bm.width, bm.rows, 8, bm.pitch, 0, 0, 0, 0xFF);

    SDL_Color colors[256];
    for( int i = 0; i < 256; i++)
    {
        colors[i].r = colors[i].g = colors[i].b = i;
    }
    SDL_SetPaletteColors(glyph->format->palette, colors, 0, 256);

    SDL_SetSurfaceBlendMode(glyph, SDL_BlendMode::SDL_BLENDMODE_NONE);
    SDL_Rect dest = { x, y, 0, 0 };
    SDL_BlitSurface(glyph, nullptr, target, &dest);
    SDL_FreeSurface(glyph);
}

或者自己进行 RGBA 转换:

void DrawBitmap(FT_Bitmap bm, int x, int y)
{
    if( bm.width == 0 || bm.rows == 0 )
    {
        return;
    }

    std::vector< unsigned char > rgba( bm.width * bm.rows * 4 );
    for( unsigned int y = 0; y < bm.rows; ++y )
    {
        for( unsigned int x = 0; x < bm.width; ++x )
        {
            unsigned char val = bm.buffer[ ( bm.pitch * y ) + x ];
            size_t base = ( ( bm.width * y ) + x ) * 4;
            rgba[ base + 0 ] = 0xFF;
            rgba[ base + 1 ] = 0xFF;
            rgba[ base + 2 ] = 0xFF;
            rgba[ base + 3 ] = val;
        }
    }

    SDL_Surface* glyph = SDL_CreateRGBSurfaceFrom
        (
        &rgba[0],
        bm.width,
        bm.rows,
        32,
        bm.width*4,
        0x000000ff,
        0x0000ff00,
        0x00ff0000,
        0xff000000
        );

    SDL_SetSurfaceBlendMode(glyph, SDL_BlendMode::SDL_BLENDMODE_BLEND);
    SDL_Rect dest = { x, y, 0, 0 };
    SDL_BlitSurface(glyph, nullptr, target, &dest);
    SDL_FreeSurface(glyph);
}

推荐阅读