2014-04-05 2 views
29

Mi chiedevo come eseguire il rendering del testo con SDL2. Ho trovato un'API chiamata SDL_TTF e alcuni tutorial, tuttavia non funzionano con la mia situazione.Come eseguire il rendering del testo in SDL2?

Sto utilizzando un SDL_Window e SDL_Renderer, mentre le esercitazioni sono specifiche per SDL_Surface.

È possibile utilizzare SDL_TTF con SDL_Render/SDL_Window? Se é cosi, come?

risposta

34

Sì, è possibile, dal momento che si dispone di un renderer e una finestra in più si in realtà non hanno alcun pensiero su dilettarsi con superfici allora si potrebbe desiderare in mente sulla creazione di trama, ecco un esempio di codice

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 

Ho provato a spiegare il codice riga per riga, non vedi alcuna finestra proprio lì, poiché ho già pensato che tu sapessi come inizializzare un renderer che mi avrebbe dato l'idea che sai anche come inizializzare una finestra , quindi tutto ciò che serve è l'idea su come inizializzare una trama.

Domande minori qui, hai aperto la finestra? era colorato di nero? se così fosse, i miei pensieri erano giusti, se no, allora puoi solo chiedermelo e io potrei cambiare questo codice per implementare l'intera sezione che consiste in un renderer e una finestra.

+43

Potresti per favore liberare la tua superficie? – Leonardo

+0

@Leonardo Inchiodato. – saadtaame

+0

Message_rect.w = 100; // il programmatore dovrebbe sapere quanto sarà vasto il suo testo? – engineerX

8

Sì, lo è. Crei una superficie con il testo che desideri e poi la converti in una texture che puoi renderizzare.

Alcuni codice di esempio da uno dei miei progetti:

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

Questo presuppone che si sia inizializzato correttamente SDL_ttf e caricato un tipo di carattere. Nell'esempio score è un int. Lo schermo viene cancellato e reso in un'altra posizione (non ho incluso quella parte).

Per un esempio operativo completo, consultare tutorial for SDL_ttf in SDL2 at Lazy Foo.

+0

Questo genera un'eccezione non gestita di memoria per qualche motivo? –

+0

@EthanWebster Oh, il codice era semplicemente inteso come un esempio (non funzionante), in quanto manca di cose importanti da eseguire, come il codice init, il controllo degli errori eccetera. – jpw

+0

@EthanWebster Ho aggiunto un collegamento a un tutorial con codice di esempio di lavoro. – jpw

10

SDL_ttf minimo esempio eseguibile

enter image description here

Non super efficiente, ma facile da integrare. Per l'efficienza vedere: Rendering fonts and text with SDL2 efficiently

conservati in un repo separata rispetto la fonte principale di SDL, ma ospitato sullo stesso server ufficiale, quindi dovrebbe andare bene: http://hg.libsdl.org/SDL_ttf/

Newlines non funzionerà. Devi lavorare con altezze di linea.

È necessario passare il percorso di un file di font TTF al programma come:

./ttf /usr/share/fonts/truetype/freefont/FreeMonoOblique.ttf 

Compilare con:

sudo apt-get install -y libsdl2-dev 
gcc -lSDL2 -lSDL2_ttf -o ttf ttf.c 

testato su Ubuntu 16.04, SDL 2.0.4.

Codice in un repository GitHub: https://github.com/cirosantilli/cpp-cheat/blob/e52ed4b838e2697d8f44ab5bef3e7a170705d48e/sdl/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; 
}