web-dev-qa-db-ja.com

SDL2でテキストをレンダリングする方法は?

SDL2でテキストをレンダリングする方法を知りたいと思いました。 SDL_TTFというAPIといくつかのチュートリアルを見つけましたが、私の状況では機能しません。

SDL_WindowSDL_Rendererを使用していますが、チュートリアルはSDL_Surfaceに固有のものです。

SDL_TTFSDL_Render/SDL_Windowとともに使用することはできますか?もしそうなら、どのように?

33
Ethan Webster

ええ、可能です。レンダラーとウィンドウがあり、表面を軽くたたくという考えがまったくない場合は、テクスチャを作成することをお勧めします。サンプルコードを次に示します。

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

コードを行ごとに説明しようとしましたが、ウィンドウが表示されないのは、レンダラーを初期化する方法を知っているとすでに仮定しているためです。必要なのは、テクスチャを初期化する方法に関するアイデアです。

ここでちょっとした質問がありますが、ウィンドウは開いていましたか?黒い色だった?もしそうなら、私の考えは正しかった、そうでなければ、あなたは私に尋ねることができ、レンダラーとウィンドウで構成されるセクション全体を実装するためにこのコードを変更することができます。

45
kdyz

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でテスト済み。

はい、そうです。必要なテキストを使用してサーフェスを作成し、レンダリング可能なテクスチャに変換します。

私のプロジェクトの1つからのサンプルコード:

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です。画面はクリアされ、他の場所にレンダリングされます(その部分は含めませんでした)。

完全に機能する例については、 Lazy FooのSDL2のSDL_ttfのチュートリアル をご覧ください。

11
jpw