如何在SDL2中呈现文本?

Eth*_*ter 34 c sdl-2

我想知道如何使用SDL2渲染文本.我发现了一个名为API SDL_TTF和一些教程,但是它们不适用于我的情况.

我正在使用SDL_WindowSDL_Renderer,而教程是特定的SDL_Surface.

是否有可能使用SDL_TTFSDL_Render/SDL_Window?如果是这样,怎么样?

kdy*_*dyz 47

是的,有可能,鉴于你有一个渲染器和一个窗口加上你真的没有任何关于涉及表面的想法,那么你可能想要创建纹理,这里是一个示例代码

TTF_Font* Sans = TTF_OpenFont("Sans.ttf", 24); //this opens a font style and sets a size

SDL_Color White = {255, 255, 255};  // this is the color in rgb format, maxing out all would give you the color white, and it will be your text's color

SDL_Surface* surfaceMessage = TTF_RenderText_Solid(Sans, "put your text here", White); // as TTF_RenderText_Solid could only be used on SDL_Surface then you have to create the surface first

SDL_Texture* Message = SDL_CreateTextureFromSurface(renderer, surfaceMessage); //now you can convert it into a texture

SDL_Rect Message_rect; //create a rect
Message_rect.x = 0;  //controls the rect's x coordinate 
Message_rect.y = 0; // controls the rect's y coordinte
Message_rect.w = 100; // controls the width of the rect
Message_rect.h = 100; // controls the height of the rect

//Mind you that (0,0) is on the top left of the window/screen, think a rect as the text's box, that way it would be very simple to understance

//Now since it's a texture, you have to put RenderCopy in your game loop area, the area where the whole code executes

SDL_RenderCopy(renderer, Message, NULL, &Message_rect); //you put the renderer's name first, the Message, the crop size(you can ignore this if you don't want to dabble with cropping), and the rect which is the size and coordinate of your texture

//Don't forget too free your surface and texture
Run Code Online (Sandbox Code Playgroud)

我试图逐行解释代码,你没有看到任何窗口,因为我已经假设你知道如何初始化渲染器,这会让我知道你也知道如何初始化一个窗口,然后你需要的是如何初始化纹理的想法.

这里有一些小问题,你的窗户打开了吗?它是黑色的吗?如果是这样,那么我的想法是正确的,如果没有,那么你可以问我,我可以改变这个代码来实现整个部分,包括一个渲染器和一个窗口.

  • 你能解开你的表面吗? (51认同)
  • @engineerX 您可以使用`TTF_SizeText(TTF_Font *font, const char *text, int *w, int *h)` 获取渲染文本的尺寸 (4认同)
  • 如果这不起作用,请尝试在此代码之前运行 `TTF_Init()`。 (4认同)
  • TTF_Font 和 TTF_OpenFont 未定义...很高兴解释它们的来源 (3认同)
  • Message_rect.w = 100; //程序员应该知道他的文本最终会有多宽吗? (2认同)

Cir*_*四事件 13

SDL_ttf最小可运行示例

在此输入图像描述

不是超级高效,但易于集成.为了提高效率,请参阅:使用SDL2高效渲染字体和文本

保存在一个单独的repo而不是主SDL源,但托管在同一个官方服务器上,所以应该没问题:http://hg.libsdl.org/SDL_ttf/

换行不起作用.你必须使用线高.

您必须将TTF字体文件的路径传递给程序,如下所示:

sudo apt-get install -y libsdl2-dev
gcc -lSDL2 -lSDL2_ttf -o ttf ttf.c
./ttf /usr/share/fonts/truetype/freefont/FreeMonoOblique.ttf
Run Code Online (Sandbox Code Playgroud)

编译:

#include <stdlib.h>

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

#define WINDOW_WIDTH 300
#define WINDOW_HEIGHT (WINDOW_WIDTH)

/*
- x, y: upper left corner.
- texture, rect: outputs.
*/
void get_text_and_rect(SDL_Renderer *renderer, int x, int y, char *text,
        TTF_Font *font, SDL_Texture **texture, SDL_Rect *rect) {
    int text_width;
    int text_height;
    SDL_Surface *surface;
    SDL_Color textColor = {255, 255, 255, 0};

    surface = TTF_RenderText_Solid(font, text, textColor);
    *texture = SDL_CreateTextureFromSurface(renderer, surface);
    text_width = surface->w;
    text_height = surface->h;
    SDL_FreeSurface(surface);
    rect->x = x;
    rect->y = y;
    rect->w = text_width;
    rect->h = text_height;
}

int main(int argc, char **argv) {
    SDL_Event event;
    SDL_Rect rect1, rect2;
    SDL_Renderer *renderer;
    SDL_Texture *texture1, *texture2;
    SDL_Window *window;
    char *font_path;
    int quit;

    if (argc == 1) {
        font_path = "FreeSans.ttf";
    } else if (argc == 2) {
        font_path = argv[1];
    } else {
        fprintf(stderr, "error: too many arguments\n");
        exit(EXIT_FAILURE);
    }

    /* Inint TTF. */
    SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO);
    SDL_CreateWindowAndRenderer(WINDOW_WIDTH, WINDOW_WIDTH, 0, &window, &renderer);
    TTF_Init();
    TTF_Font *font = TTF_OpenFont(font_path, 24);
    if (font == NULL) {
        fprintf(stderr, "error: font not found\n");
        exit(EXIT_FAILURE);
    }
    get_text_and_rect(renderer, 0, 0, "hello", font, &texture1, &rect1);
    get_text_and_rect(renderer, 0, rect1.y + rect1.h, "world", font, &texture2, &rect2);

    quit = 0;
    while (!quit) {
        while (SDL_PollEvent(&event) == 1) {
            if (event.type == SDL_QUIT) {
                quit = 1;
            }
        }
        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
        SDL_RenderClear(renderer);

        /* Use TTF textures. */
        SDL_RenderCopy(renderer, texture1, NULL, &rect1);
        SDL_RenderCopy(renderer, texture2, NULL, &rect2);

        SDL_RenderPresent(renderer);
    }

    /* Deinit TTF. */
    SDL_DestroyTexture(texture1);
    SDL_DestroyTexture(texture2);
    TTF_Quit();

    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();
    return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)

在Ubuntu 16.04,SDL 2.0.4上测试.

GitHub存储库中的代码:https://github.com/cirosantilli/cpp-cheat/blob/e52ed4b838e2697d8f44ab5bef3e7a170705d48e/sdl/ttf.c

sudo apt-get install -y libsdl2-dev
gcc -lSDL2 -lSDL2_ttf -o ttf ttf.c
./ttf /usr/share/fonts/truetype/freefont/FreeMonoOblique.ttf
Run Code Online (Sandbox Code Playgroud)


jpw*_*jpw 12

是的.使用所需文本创建曲面,然后将其转换为可以渲染的纹理.

我的一个项目的一些示例代码:

std::string score_text = "score: " + std::to_string(score);        
SDL_Color textColor = { 255, 255, 255, 0 };
SDL_Surface* textSurface = TTF_RenderText_Solid(font, score_text.c_str(), textColor);
SDL_Texture* text = SDL_CreateTextureFromSurface(renderer, textSurface);
int text_width = textSurface->w;
int text_height = textSurface->h;
SDL_FreeSurface(textSurface);
SDL_Rect renderQuad = { 20, win_height - 30, text_width, text_height };
SDL_RenderCopy(renderer, text, NULL, &renderQuad);
SDL_DestroyTexture(text);
Run Code Online (Sandbox Code Playgroud)

这假设您已正确初始化SDL_ttf并加载了字体.在示例中score是一个int.屏幕被清除并呈现给其他地方(我没有包括那部分).

有关完整的工作示例,请查看Lazy Foo的SDL2中的SDL_ttf教程.


Bru*_*rha 5

进行编辑以使其更易于遵循、使用Roboto.ttf( https://fonts.google.com/specimen/Roboto ) 而不是Verdana.ttf并添加not2qubit建议。请记住,这根本不遵循任何 C++ 类约定。我只是想确保这很容易复制/粘贴和运行。

要构建它,您需要添加库SDL_ttfhttps://www.libsdl.org/projects/SDL_ttf/)。

g++ demo.cpp -o demo -Wall -I 包括 -lsdl2 -lsdl2_ttf

Since there are some people struggling with more complex code, I've included my own snippet here to help some beginners like myself. This will just show a red screen with a black hello world. Don't forget to add -lsdl2 and -lsdl2_ttf on your build and include the Verdana.ttf font on the same folder.

#include <iostream>
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h> //This is an sample library not included with stock SDL2. https://www.libsdl.org/projects/SDL_ttf/release-1.2.html

const char* WINDOW_TITLE = "Hello World SDL2 + TTF";
const char* FONT_NAME = "roboto.ttf";
const int FONT_SIZE = 128;
const int WINDOW_WIDTH = 1280, WINDOW_HEIGHT = 720;

SDL_Window* Window; // Window created by SDL.
SDL_Renderer* Renderer; // The renderer that shows our textures.
SDL_Event WindowEvent; // Event capturer from SDL Window.
SDL_Color TextColor = { 255, 0, 0, 255}; // Red SDL color.
TTF_Font* Font; // The font to be loaded from the ttf file.
SDL_Surface* TextSurface; // The surface necessary to create the font texture.
SDL_Texture* TextTexture; // The font texture prepared for render.
SDL_Rect TextRect; // Text rectangle area with the position for the texture text.

void CreateWindow() {
    Window = SDL_CreateWindow(WINDOW_TITLE, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_ALLOW_HIGHDPI);
    if (!Window)
        std::cout << "There was a problem creating the window.";
    Renderer = SDL_CreateRenderer(Window, -1, 0);
    if (!Renderer)
        std::cout << "There was a problem creating the renderer.";
}

void CreateText(const char* Message) {
    TTF_Init();
    TTF_Font *font = TTF_OpenFont(FONT_NAME, FONT_SIZE);
    if (!font)
        std::cout << "Couldn't find/init open ttf font." << std::endl;
    TextSurface = TTF_RenderText_Solid(font, Message, TextColor);
    TextTexture = SDL_CreateTextureFromSurface(Renderer, TextSurface);
    TextRect.x = WINDOW_WIDTH - TextSurface->w * 0.5; // Center horizontaly
    TextRect.y = WINDOW_HEIGHT - TextSurface->h * 0.5; // Center verticaly
    TextRect.w = TextSurface->w;
    TextRect.h = TextSurface->h;
    // After you create the texture you can release the surface memory allocation because we actually render the texture not the surface.
    SDL_FreeSurface(TextSurface);
    TTF_Quit();
}

bool IsPollingEvent() {
    while(SDL_PollEvent(&WindowEvent)) {
        switch (WindowEvent.type) {
            case SDL_QUIT: return false;
        }
    }
    return true;
}

void RenderText() {
    SDL_SetRenderDrawColor(Renderer, 0, 0, 0, 255); // Make window bg black.
    SDL_RenderClear(Renderer); // Paint screen black.
    SDL_RenderCopy(Renderer, TextTexture, NULL, &TextRect); // Add text to render queue.
    SDL_RenderPresent(Renderer); // Render everything that's on the queue.
    SDL_Delay(10); // Delay to prevent CPU overhead as suggested by the user `not2qubit`
}

void ClearMemory() {
    SDL_DestroyTexture(TextTexture);
    SDL_DestroyRenderer(Renderer);
    SDL_DestroyWindow(Window);
    SDL_Quit();
    std::cout << "Clear proccess done." << std::endl;
}

int main() {
    CreateWindow();
    CreateText("Hello SDL_Ttf");
    while (IsPollingEvent()) {
        RenderText();
    }
    ClearMemory();
    return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)