c++ - 使用 FreeType 和 SDL2 渲染文本会生成白色方块而不是字符
问题描述
我正在尝试获得一个基本项目来使用 SDL2 和 FreeType 呈现文本,但它所呈现的只是白色方块而不是每个字符。我正在渲染每个 glygh 并将像素数据转换为SDL_Surface
with 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);
}
解决方案
您可以设置调色板:
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);
}
推荐阅读
- .net-5 - 在托管服务器上时,Blazor 应用程序未运行服务器代码
- node.js - React 前端连接到我的计算机上的开发服务器,而不是 Azure VM 上的 Node 服务器,从为什么使用 localhost 托管它
- python - 从同一个python类中另一个函数中的函数访问变量
- python - Python ffmpeg 子进程制作无法播放的文件,但大小合适,只是挂起
- asp.net - 浏览到 ASP.NET 网站文件夹中的 PDF
- eclipse - 最终启动序列中的错误:无法执行 MI 命令:-exec-run
- python-3.x - 有人可以解释一下,以下代码段的输出如何为 100?
- networking - 我有一个关于流量控制数据的利用率和吞吐量以及如何找到数据包错误率的问题
- javascript - 以反应形式自定义验证器传递动态参数
- java - 当缺少一个 configurationPid 时,OSGi DS 的组件属性的优先级如何?