Can you use any function to render more than a line of text in a surface?
If you can't do this, what whould be the way to go? I am doing the following: Create a surface (not sure if should be a software or a hardware one) and then create as many surfaces as lines my text have, then blitting all the surfaces, and freeing all the surfaces. But this turns to be very slow. This is the code:
void Text::updateSurface() {
if (surface != NULL) {
SDL_FreeSurface(surface);
}
TTF_Font * font = TTF_OpenFont(fontPath.c_str(),size);
if (font == NULL) {
ERROR("Null font"< }
int maxWidth = 0;
int totalHeight = 0;
std::vector surfaces;
for (size_t i=0; i
SDL_Surface * partialSurface = TTF_RenderText_Solid(font, lines[i].c_str(), color);
if (partialSurface == NULL) {
ERROR("surface == NULL: "< }
surfaces.push_back(partialSurface);
totalHeight += partialSurface->h;
maxWidth = std::max(maxWidth, partialSurface->w);
}
TTF_CloseFont(font);
surface = SDL::allocateSurface(maxWidth,totalHeight);
if (backgroundColor != NULL) {
SDL_FillRect(surface, NULL, SDL_MapRGB(surface->format,backgroundColor->r, backgroundColor->g, backgroundColor->b));
}
totalHeight = 0;
for (size_t i = 0; i < surfaces.size(); i++) {
SDL_Rect dst = {0, totalHeight, 0, 0};
switch(aligment) {
case ALIGMENT_RIGHT:
dst.x = maxWidth - surfaces[i]->w;
break;
case ALIGMENT_CENTER:
dst.x = (maxWidth - surfaces[i]->w) / 2;
break;
case ALIGMENT_LEFT:
default:
break;
}
totalHeight += surfaces[i]->h;
SDL_BlitSurface(surfaces[i],NULL,surface,&dst);
SDL_FreeSurface(surfaces[i]);
}
}
This is the code for SDL::allocateSurface(...)
static SDL_Surface * allocateSurface(int width, int height, int bpp = -1, Uint32 flags = 0)
SDL_Surface * SDL::allocateSurface(int width, int height, int bpp, Uint32 flags) {
if (bpp == -1) {
bpp = SDL::bpp; //SDL_GetVideoInfo()->vfmt->BitsPerPixel;
}
if (flags == 0) {
flags = SDL_HWSURFACE;
}
Uint32 rmask, gmask, bmask, amask;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
rmask = 0xff000000;
gmask = 0x00ff0000;
bmask = 0x0000ff00;
amask = 0x000000ff;
#else
rmask = 0x000000ff;
gmask = 0x0000ff00;
bmask = 0x00ff0000;
amask = 0xff000000;
#endif
return SDL_CreateRGBSurface(flags, width, height, bpp, rmask, gmask, bmask, amask);
}
Answer
Don't render text directly with SDL_TTF. It's not efficient, at all. Use SDL_TTF to generate a glyph atlas, or use a tool like AngelCode BMFont. You can get glyph metrics (Width, Height, x advance, etc.) using TTF_LineSkip to find the vertical distance, and TTF_GlyphMetrics.
At this point, you can render text yourself. By putting the font glyphs into an atlas, and storing glyph metrics, you can easily render multiple lines, render each glyph in a different style or even font, do various effects, etc. By batching your glyph draws, you can be way more efficient than using SDL_TTF naively. There's no need to copy whole lines into temporary SDL buffers which are copied to your real output.
It's harder, but worth it. Easy toy render APIs are just that: toys.
No comments:
Post a Comment