SDL TTF - 如何实现文本自动换行和改变换行后行高?

5

最近我正在使用SDL2编写一个小型的文本冒险游戏,但是遇到了换行问题。我使用TTF_RenderText_Blended_Wrapped()来渲染字符串,这样可以得到一些漂亮的自动换行。但是行高是个问题,行之间看起来很挤,像'jqg'这样的字母与'tli'这样的字母重叠。

有人知道如何更改行高吗?SDL_ttf的文档中甚至还没有介绍TTF_RenderText_Blended_Wrapped()。我应该编写自己的文本换行函数吗?

字体大小为16pt,样式为TTF_STYLE_BOLD,字体可以在这里找到。下面的代码应该能够复现错误,但几乎没有错误检查,请自行承担风险。以下是代码输出结果:

#include <stdio.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>

int main(int argc, char *argv[]) {
    SDL_Window *gui;
    SDL_Surface *screen, *text;
    SDL_Event ev;
    TTF_Font *font;
    int running = 1;

    const char *SAMPLETEXT = "This is an example of my problem, for most lines it works fine, albeit it looks a bit tight. But for any letters that \"hang\" below the line, there is a chance of overlapping with the letters below. This isn\'t the end of the world, but I think it makes for rather cluttered text.\n\nNotice the p and k on line 1/2, and the g/t on 2/3 and 3/4.";

    // init SDL/TTF
    SDL_Init(SDL_INIT_EVERYTHING);  
    TTF_Init();

    // Open and set up font
    font = TTF_OpenFont("Anonymous.ttf", 16);
    if(font == NULL) {
        fprintf(stderr, "Error: font could not be opened.\n"); 
        return 0; 
    }
    TTF_SetFontStyle(font, TTF_STYLE_BOLD);


    // Create GUI
    gui = SDL_CreateWindow("Example", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 
            640, 480, SDL_WINDOW_SHOWN);
    // Grab GUI surface
    screen = SDL_GetWindowSurface(gui); 

    // Clear screen black
    SDL_FillRect(screen, NULL, 0);
    // Draw some text to screen
    SDL_Color color = {0xff, 0xff, 0xff, 0xff};
    text = TTF_RenderText_Blended_Wrapped(font, SAMPLETEXT, color, screen->w);
    SDL_BlitSurface(text, NULL, screen, NULL);

    while(running) { // Main loop
        while(SDL_PollEvent(&ev)) {
            switch(ev.type){
                case SDL_QUIT:
                    running = 0;
                    break;
            }
        }

        SDL_UpdateWindowSurface(gui); // Refresh window
        SDL_Delay(20); // Delay loop
    }

    // Destroy resources and quit
    TTF_CloseFont(font);
    TTF_Quit();

    SDL_FreeSurface(text);
    SDL_DestroyWindow(gui);
    SDL_Quit();

    return 0;
}

我没有看到有任何控制行间距的方法。这里是源代码链接。你尝试过使用不同的字体吗?你比较过TTF_FontHeight()TTF_FontLineSkip()返回的值吗? - ad absurdum
谢谢提供链接。行距大于高度,我已经尝试了几种字体。我相信一定有某种字体可以解决这个问题,但我不想去寻找。 - Jacob H
你能够分享一下你正在使用的字体吗?我在我的系统上尝试了几种字体,但无法复制这个问题。 - Tim
这是字体,我试了几个其他的,但如果你没有问题,我应该测试更多。 - Jacob H
你能发布一张显示不正确的文本图片吗?另外,你使用的字体大小和样式是什么? - Tim
字体大小为16,加粗文本,尽管我使用了普通格式进行测试。我在帖子中添加了一张图片以及一些代码。 - Jacob H
1个回答

5
最简单的解决方案是找一个没有这个问题的字体。FreeMono字体有更多的间距:

using the FreeMono.ttf

从查看TTF_RenderUTF8_Blended_Wrapped的源代码可以发现,它是由TTF_RenderText_Blended_Wrapped调用的,但没有可配置的方法来设置行之间的间距。请参见第1893行上的const int lineSpace = 2;
然而,即使将lineSpace设置为2,在计算每个要渲染的像素的地址时也没有使用它。这实际上将行间距设置为0。我在SDL_ttf库中报告了这个bug: https://bugzilla.libsdl.org/show_bug.cgi?id=3679 我通过以下更改修复了SDL_ttf 2.0.14中的问题:
--- a/SDL_ttf.c Fri Jan 27 17:54:34 2017 -0800
+++ b/SDL_ttf.c Thu Jun 22 16:54:38 2017 -0700
@@ -1996,7 +1996,7 @@
         return(NULL);
     }

-    rowSize = textbuf->pitch/4 * height;
+    rowSize = textbuf->pitch/4 * (height + lineSpace);

     /* Adding bound checking to avoid all kinds of memory corruption errors
      that may occur. */

应用上述补丁后,您的示例程序将使用匿名字体正确显示行间距:

correct line spacing with patched SDL_ttf


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接