Как эффективно визуализировать шрифты и текст с помощью SDL2?

Пила этот пост здесь об использовании SDL_ttf для рендеринга текста в игре. Однако этот подход требует вызова SDL_CreateTextureFromSurface(), а также SDL_FreeSurface() и SDL_DestroyTexture() для каждого кадра.

Создает ли текстуры (и, возможно, впоследствии отправляет их на графический процессор) каждый кадр, что может существенно повлиять на мою производительность?

было бы разумнее использовать SDL_ttf только для создания текстуры с моей выделенной кодировкой, а затем для того, чтобы blit оттуда сам по себе, символ по символу?

Изменить. Я ищу для создания простых моноширинных шрифтов только на английском языке (базовый ASCII).

Ответ 1

Да, при создании текстур каждый кадр может повлиять на производительность. Кроме того, растрирование шрифтов TrueType на SDL_Surfaces (как это делает SDL_ttf), каждый кадр может повлиять на производительность.

Я рекомендую SDL_FontCache (полное раскрытие: я автор). Он использует SDL_ttf и кэширует полученные глифы в текстурах, поэтому вам не нужно делать все это самостоятельно:
https://github.com/grimfang4/SDL_FontCache

Ответ 2

Текстовые методы OpenGL

Вы, скорее всего, найдете эффективную реализацию с помощью OpenGL, поскольку она более широко используется, чем SDL, см. Как нарисовать текст, используя только методы OpenGL?

В настоящее время я бы выбрал freetype-gl: https://github.com/rougier/freetype-gl, который поддерживает текстурный атлас https://en.wikipedia.org/wiki/Texture_atlas из коробки.

SDL хорошо поддерживает OpenGL, и вы даже можете использовать текстуры GL и SDL в одной программе, если вы уже используете текстуры SDL в своей программе, например:

#include "common.h"

int main(void) {
    SDL_GLContext gl_context;
    SDL_Event event;
    SDL_Renderer *renderer = NULL;
    SDL_Texture *texture = NULL;
    SDL_Window *window = NULL;
    Uint8 *base;
    const unsigned int
        WINDOW_WIDTH = 500,
        WINDOW_HEIGHT = WINDOW_WIDTH
    ;
    int pitch;
    unsigned int x, y;
    void *pixels = NULL;

    /* Window setup. */
    SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO);
    window = SDL_CreateWindow(
        __FILE__, 0, 0,
        WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL
    );
    renderer = SDL_CreateRenderer(window, 0, 0);
    gl_context = SDL_GL_CreateContext(window);

    /* GL drawing. */
    glClearColor(1.0, 0.0, 1.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);

    /* Wrapped texture drawing. */
    texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888,
        SDL_TEXTUREACCESS_STREAMING, WINDOW_WIDTH, WINDOW_HEIGHT);
    SDL_LockTexture(texture, NULL, &pixels, &pitch);
    for (x = 0; x < WINDOW_WIDTH; x++) {
        for (y = 0; y < WINDOW_HEIGHT; y++) {
            base = ((Uint8 *)pixels) + (4 * (x * WINDOW_WIDTH + y));
            base[0] = 0;
            base[1] = 0;
            base[2] = COMMON_COLOR_MAX;
            base[3] = COMMON_COLOR_MAX;
        }
    }
    SDL_UnlockTexture(texture);
    SDL_Rect rect;
    rect.x = 0;
    rect.y = 0;
    rect.w = WINDOW_WIDTH / 2;
    rect.h = WINDOW_HEIGHT / 2;
    SDL_RenderCopy(renderer, texture, NULL, &rect);
    SDL_GL_SwapWindow(window);

    /* Main loop. */
    while (1) {
        if (SDL_PollEvent(&event) && event.type == SDL_QUIT)
            break;
    }

    /* Cleanup. */
    SDL_GL_DeleteContext(gl_context);
    SDL_DestroyTexture(texture);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();

    return EXIT_SUCCESS;
}

GitHub вверх по течению: https://github.com/cirosantilli/cpp-cheat/blob/d36527fe4977bb9ef4b885b1ec92bd0cd3444a98/sdl/texture_and_opengl.c