Как сделать текст в SDL2?

Мне было интересно, как сделать текст с SDL2. Я нашел API под названием SDL_TTF и некоторые учебные пособия, однако они не работают с моей ситуацией.

Я использую SDL_Window и SDL_Renderer, тогда как учебники относятся к SDL_Surface.

Можно ли использовать SDL_TTF с SDL_Render/SDL_Window? Если да, то как?

Ответ 1

Да, это возможно, учитывая, что у вас есть средство рендеринга и окно, плюс у вас нет никаких мыслей о том, чтобы побаловаться с поверхностями, тогда вы можете подумать о создании текстуры, вот пример кода

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 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 x coordinate 
Message_rect.y = 0; // controls the rect 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 box, that way it would be very simple to understance

//Now since it 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 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

Я пытался объяснить код построчно, вы не видите здесь никакого окна, так как я уже предполагал, что вы знаете, как инициализировать рендер, что даст мне представление, что вы также знаете, как инициализировать окно, а затем все нужна идея о том, как инициализировать текстуру.

Незначительные вопросы здесь, ваше окно открылось? это было окрашено в черный цвет? если так, то мои мысли были правильными, если нет, то вы можете просто спросить меня, и я мог бы изменить этот код, чтобы реализовать весь раздел, который состоит из средства визуализации и окна.

Ответ 2

SDL_ttf минимальный исполняемый пример

enter image description here

Не супер эффективный, но легко интегрируемый. Об эффективности см.: Как эффективно отображать шрифты и текст с помощью SDL2?

Хранится в отдельном репо, чем основной источник SDL, но размещается на том же официальном сервере, поэтому должно быть в порядке: http://hg.libsdl.org/SDL_ttf/

Новые строки не будут работать. Вы должны работать с высотами линий.

Скомпилируйте и запустите:

sudo apt-get install -y libsdl2-dev
gcc -lSDL2 -lSDL2_ttf -o ttf ttf.c
./ttf /usr/share/fonts/truetype/freefont/FreeMonoOblique.ttf

Вы должны передать путь файла шрифта TTF в программу.

ttf.c

#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;
}

GitHub вверх по течению.

Протестировано в Ubuntu 16.04, SDL 2.0.4.

Ответ 3

Да, это так. Вы создаете поверхность с нужным текстом, а затем преобразуете ее в текстуру, которую вы можете отобразить.

Пример кода из одного из моих проектов:

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);

Предполагается, что вы правильно инициализировали SDL_ttf и загрузили шрифт. В примере score есть int. Экран очищается и отображается в другом месте (я не включал эту часть).

Для полного рабочего примера ознакомьтесь с учебником для SDL_ttf в SDL2 в Lazy Foo.