I was wondering how to render text with SDL2. I found an API called SDL_TTF
and some tutorials, however they do not work with my situation.
我想知道如何用SDL2渲染文本。我找到了一个叫做SDL_TTF的API和一些教程,但是它们不能处理我的情况。
I'm using an SDL_Window
and SDL_Renderer
, whereas the tutorials are specific to SDL_Surface
.
我使用的是SDL_Window和SDL_Renderer,而这些教程是针对SDL_Surface的。
Is it possible to use SDL_TTF
with SDL_Render/SDL_Window
? If so, how?
是否可以使用SDL_Render/SDL_Window使用SDL_TTF ?如果是这样,如何?
3 个解决方案
#1
37
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
是的,这是有可能的,因为你有一个渲染器和一个窗口,而且你真的没有任何想法去尝试表面那么你可能想要关注创建纹理,这是一个示例代码
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
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.
小问题,你的窗户打开了吗?颜色黑色吗?如果是,那么我的想法是对的,如果不是,那么你可以问我,我可以修改这段代码来实现整个由渲染器和窗口组成的部分。
#2
10
SDL_ttf minimal runnable example
SDL_ttf最小运行的例子
Not super efficient, but easy to integrate. For efficiency see: Rendering fonts and text with SDL2 efficiently
不是非常高效,但是很容易集成。有关效率,请参阅:使用SDL2有效地呈现字体和文本
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/
与主SDL源代码保持在一个单独的repo中,但是托管在同一个官方服务器上,所以应该没问题:http://hg.libsdl.org/SDL_ttf/
Newlines won't work. You have to work with line heights.
换行行不通。你必须使用直线高度。
You must pass the path of a TTF font file to the program as:
您必须将TTF字体文件的路径传递给程序,如:
./ttf /usr/share/fonts/truetype/freefont/FreeMonoOblique.ttf
Compile with:
编译:
sudo apt-get install -y libsdl2-dev
gcc -lSDL2 -lSDL2_ttf -o ttf ttf.c
Tested on Ubuntu 16.04, SDL 2.0.4.
在Ubuntu 16.04上测试,SDL 2.0.4。
Code on a GitHub repository: https://github.com/**/cpp-cheat/blob/e52ed4b838e2697d8f44ab5bef3e7a170705d48e/sdl/ttf.c
代码在GitHub上的存储库:https://github.com/**/cpp-cheat/blob/e52ed4b838e2697d48e/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;
}
#3
9
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).
这假设您已经正确地初始化SDL_ttf并加载了一个字体。在这个示例中,scoreis是一个int类型,屏幕会被清除并呈现到其他地方(我没有包含该部分)。
For a full working example, check out the tutorial for SDL_ttf in SDL2 at Lazy Foo.
有关一个完整的工作示例,请参阅在Lazy Foo的SDL2中关于SDL_ttf的教程。
#1
37
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
是的,这是有可能的,因为你有一个渲染器和一个窗口,而且你真的没有任何想法去尝试表面那么你可能想要关注创建纹理,这是一个示例代码
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
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.
小问题,你的窗户打开了吗?颜色黑色吗?如果是,那么我的想法是对的,如果不是,那么你可以问我,我可以修改这段代码来实现整个由渲染器和窗口组成的部分。
#2
10
SDL_ttf minimal runnable example
SDL_ttf最小运行的例子
Not super efficient, but easy to integrate. For efficiency see: Rendering fonts and text with SDL2 efficiently
不是非常高效,但是很容易集成。有关效率,请参阅:使用SDL2有效地呈现字体和文本
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/
与主SDL源代码保持在一个单独的repo中,但是托管在同一个官方服务器上,所以应该没问题:http://hg.libsdl.org/SDL_ttf/
Newlines won't work. You have to work with line heights.
换行行不通。你必须使用直线高度。
You must pass the path of a TTF font file to the program as:
您必须将TTF字体文件的路径传递给程序,如:
./ttf /usr/share/fonts/truetype/freefont/FreeMonoOblique.ttf
Compile with:
编译:
sudo apt-get install -y libsdl2-dev
gcc -lSDL2 -lSDL2_ttf -o ttf ttf.c
Tested on Ubuntu 16.04, SDL 2.0.4.
在Ubuntu 16.04上测试,SDL 2.0.4。
Code on a GitHub repository: https://github.com/**/cpp-cheat/blob/e52ed4b838e2697d8f44ab5bef3e7a170705d48e/sdl/ttf.c
代码在GitHub上的存储库:https://github.com/**/cpp-cheat/blob/e52ed4b838e2697d48e/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;
}
#3
9
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).
这假设您已经正确地初始化SDL_ttf并加载了一个字体。在这个示例中,scoreis是一个int类型,屏幕会被清除并呈现到其他地方(我没有包含该部分)。
For a full working example, check out the tutorial for SDL_ttf in SDL2 at Lazy Foo.
有关一个完整的工作示例,请参阅在Lazy Foo的SDL2中关于SDL_ttf的教程。