How to render text in SDL2?
Yep, it is possible, given that you have a renderer and a window plus you don't really have any thoughts on dabbling with surfaces then you might want to mind on creating texture, here is a sample code
//this opens a font style and sets a sizeTTF_Font* Sans = TTF_OpenFont("Sans.ttf", 24);// this is the color in rgb format,// maxing out all would give you the color white,// and it will be your text's colorSDL_Color White = {255, 255, 255};// as TTF_RenderText_Solid could only be used on// SDL_Surface then you have to create the surface firstSDL_Surface* surfaceMessage = TTF_RenderText_Solid(Sans, "put your text here", White); // now you can convert it into a textureSDL_Texture* Message = SDL_CreateTextureFromSurface(renderer, surfaceMessage);SDL_Rect Message_rect; //create a rectMessage_rect.x = 0; //controls the rect's x coordinate Message_rect.y = 0; // controls the rect's y coordinteMessage_rect.w = 100; // controls the width of the rectMessage_rect.h = 100; // controls the height of the rect// (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 understand// Now since it's a texture, you have to put RenderCopy// in your game loop area, the area where the whole code executes// 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 textureSDL_RenderCopy(renderer, Message, NULL, &Message_rect);// Don't forget to free your surface and textureSDL_FreeSurface(surfaceMessage);SDL_DestroyTexture(Message);
I tried to explain the code line by line, you don't see any window right there since I already assumed that you knew how to initialize a renderer which would give me an idea that you also know how to initialize a window, then all you need is the idea on how to initialize a texture.
Minor questions here, did your window open? was it colored black? if so then my thoughts were right, if not, then you can just ask me and I could change this code to implement the whole section which consists of a renderer and a window.
SDL_ttf minimal runnable example
Not super efficient, but easy to integrate. For efficiency see: How to render fonts and text with SDL2 efficiently?
Kept in a separate repo than the main SDL source, but hosted on the same official server, so should be fine: http://hg.libsdl.org/SDL_ttf/
Newlines won't work. You have to work with line heights.
Compile and run:
sudo apt-get install -y libsdl2-devgcc -lSDL2 -lSDL2_ttf -o ttf ttf.c./ttf /usr/share/fonts/truetype/freefont/FreeMonoOblique.ttf
You must pass the path of a TTF font file to the program.
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;}
Tested in Ubuntu 16.04, SDL 2.0.4.
Yes it is. You create a surface with the text you want and then convert it to a texture that you can render.
Some sample code from one of my projects:
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);
This assumes you've properly initialized SDL_ttf and loaded a font. In the example score
is an int. The screen gets cleared and rendered to somewhere else (I didn't include that part).
For a full working example, check out the tutorial for SDL_ttf in SDL2 at Lazy Foo.