SDL2 + OpenGL+ SDL_ttf and rendering text question

I am porting my program from mac/windows to the iPad. Up until now, I have been using the GLUT functions for drawing text, such as:
glutBitmapCharacter (GLUT_BITMAP_HELVETICA_10,theString[i]);

But those functions are not supported on the iPad, so I am trying to use SDL_ttf for text.

There are 2 examples that demonstrate SDL_ttf.
http://lackeyccg.com/glfont.c shows how things are done with OpenGL.
http://lackeyccg.com/showfont.c shows how things are done with just SDL.
I’m not sure what is the better method for my uses.

I am using text for essentially 3 kinds of uses:

Labels for things like buttons and menus.

Text for text fields.
?

And text labels that appear in 3D space. (The text itself is flat, but it appears in 3D OpenGL space.)
??

If I understand things correctly, with SDL_ttf, fonts are loaded and then you can use those fonts to create surface images, or load those images into opengl which you can refer to later by the texture id. In either case, it seems like you need to store a unique image in memory for each unique bit of text. Alternatively, you can generate this image every time you display the text, but it seems like generating the image every display cycle, while simpler to implement, would be a drag on the system. Is that correct, or could I simply generate everything I need every display cycle and not suffer a performance hit?
What I think might be the best thing to do is create some persistent record of all text images. Whenever a new word or phrase is needed (or with different style, like italics or bold) then a new entry to the record is added for that surface image (or opengl texture id). This is pretty straight-forward for something like a button label, but a text field seems to be more complicated. I think the best approach for a text field would be to store in the record only those lines of the text field that are currently visible, and have a separate entry for each line.

Another idea is to persistently store the images for all of a font’s glyphs, and then generate any needed word or phrase by cobbling them together. I would hope that SDL_ttf does this for me somehow to save me all the work. I would love to be able to just call a function, passing it a string to display, its X,Y,Z coordinates, it’s color, and size, and it would just draw it to the screen with all of the complex stuff like memory management and kerning all done behind the scenes. Does anyone know if anything like that already exists? All I can currently find is functions like?TTF_RenderText_Solid?that create a surface image that I then have to manage in a complex way as stated above.

As far as the text labels that appear in 3D space, I am not sure but I think this requires the opengl method like in the?glfont.c?example instead of the pure SDL method.

Does anyone have any suggestions for me? Do you think I am thinking about things in the right manner? How have you handled rendering both non-dynamic and dynamic text with SDL_ttf?

Any insight you have on this subject would be helpful.

Thanks in advance.

-Trevor

2012/5/24 Trev

**
I am porting my program from mac/windows to the iPad. Up until now, I have
been using the GLUT functions for drawing text, such as:
glutBitmapCharacter (GLUT_BITMAP_HELVETICA_10,theString[i]);

But those functions are not supported on the iPad, so I am trying to use
SDL_ttf for text.

There are 2 examples that demonstrate SDL_ttf.
http://lackeyccg.com/glfont.c shows how things are done with OpenGL.
http://lackeyccg.com/showfont.c shows how things are done with just SDL.
I’m not sure what is the better method for my uses.

Both methods basically do the same, even though the SDL method does it
behind the scenes with SDL_CreateTextureFromSurface, they create a
"software" surface where SDL_ttf renders the text, then copy it to a
"hardware" texture and render that.

As far as the text labels that appear in 3D space, I am not sure but I
think this requires the opengl method like in the glfont.c example instead
of the pure SDL method.

Does anyone have any suggestions for me? Do you think I am thinking about
things in the right manner? How have you handled rendering both non-dynamic
and dynamic text with SDL_ttf?

I generally render the text to a software surface, copy it to a texture and
render it using SDL, I don’t think there’s a way around it because SDL_ttf
is fundamentally CPU centered and rendering GPU centered, and you have to
bridge those eventually…if there’s a lot of text or it is constantly
changing, maybe you can do the glyphs thing (uploading all symbols to a
texture and render them “by hand”), but it really depends on the
application you are developing. You could, in theory, render fonts using
only geometry or shaders, but it seems the technology is not there yet:


Gabriel.

You’re right that generating the textures for each new string every cycle
will not perform well. Preloading the glyphs from a font to a texture set
and assembling on the fly instead seems to work alright for me. The
relevant parts I’ve mashed into the example program below (c++/sdl2). But
this approach is only for game text. It’s not great for regular
applications where the standard OS widgets are familiar, complete and
comfortable for people. So, for the text areas and things, you might want
to be using a GUI library such as GTK+… but if you do choose to render
letters as individual textures, feel free to have at the code here (note
the paths to fonts at lines 102-105).

http://codepad.org/QS26ciMDOn Thu, May 24, 2012 at 10:56 PM, Trev wrote:

**
I am porting my program from mac/windows to the iPad. Up until now, I have
been using the GLUT functions for drawing text, such as:
glutBitmapCharacter (GLUT_BITMAP_HELVETICA_10,theString[i]);

But those functions are not supported on the iPad, so I am trying to use
SDL_ttf for text.

There are 2 examples that demonstrate SDL_ttf.
http://lackeyccg.com/glfont.c shows how things are done with OpenGL.
http://lackeyccg.com/showfont.c shows how things are done with just SDL.
I’m not sure what is the better method for my uses.

I am using text for essentially 3 kinds of uses:

Labels for things like buttons and menus.

Text for text fields.
?

And text labels that appear in 3D space. (The text itself is flat, but it
appears in 3D OpenGL space.)
??

If I understand things correctly, with SDL_ttf, fonts are loaded and then
you can use those fonts to create surface images, or load those images into
opengl which you can refer to later by the texture id. In either case, it
seems like you need to store a unique image in memory for each unique bit
of text. Alternatively, you can generate this image every time you display
the text, but it seems like generating the image every display cycle, while
simpler to implement, would be a drag on the system. Is that correct, or
could I simply generate everything I need every display cycle and not
suffer a performance hit?
What I think might be the best thing to do is create some persistent
record of all text images. Whenever a new word or phrase is needed (or with
different style, like italics or bold) then a new entry to the record is
added for that surface image (or opengl texture id). This is pretty
straight-forward for something like a button label, but a text field seems
to be more complicated. I think the best approach for a text field would be
to store in the record only those lines of the text field that are
currently visible, and have a separate entry for each line.

Another idea is to persistently store the images for all of a font’s
glyphs, and then generate any needed word or phrase by cobbling them
together. I would hope that SDL_ttf does this for me somehow to save me all
the work. I would love to be able to just call a function, passing it a
string to display, its X,Y,Z coordinates, it’s color, and size, and it
would just draw it to the screen with all of the complex stuff like memory
management and kerning all done behind the scenes. Does anyone know if
anything like that already exists? All I can currently find is functions
like TTF_RenderText_Solid that create a surface image that I then have to
manage in a complex way as stated above.

As far as the text labels that appear in 3D space, I am not sure but I
think this requires the opengl method like in the glfont.c example instead
of the pure SDL method.

Does anyone have any suggestions for me? Do you think I am thinking about
things in the right manner? How have you handled rendering both non-dynamic
and dynamic text with SDL_ttf?

Any insight you have on this subject would be helpful.

Thanks in advance.

-Trevor


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

Chris Bush wrote:

You’re right that generating the textures for each new string every cycle will not perform well. Preloading the glyphs from a font to a texture set and assembling on the fly instead seems to work alright for me. The relevant parts I’ve mashed into the example program below (c++/sdl2). But this approach is only for game text. It’s not great for regular applications where the standard OS widgets are familiar, complete and comfortable for people. So, for the text areas and things, you might want to be using a GUI library such as GTK+… but if you do choose to render letters as individual textures, feel free to have at the code here (note the paths to fonts at lines 102-105).

http://codepad.org/QS26ciMD (http://codepad.org/QS26ciMD)

That seems like a great example code and is pretty close to exactly what I am looking for.

I have a minor tweak that I think is an improvement. If you pass some RGB values to void Text_ure::write(float x, float y, float lh, float r,float g,float b), then you can dynamically change the color of the font without having to reload it. Just make sure you pass a white color to TTF_RenderText_Blended when the glyph images are being created initially. And you can pass RGB values to write_left_aligned so it in turn can pass them to Text_ure::write. That leaves you with:
Code:
void write_left_aligned( // write
Text_ure Lettercase[], // with letter case
const char
s, // input C string
float top, float left, // upper left corner
float fontsize, // size
float lineheight, // line height factor - 1 is normal
float kerning, // letter spacing factor - 1 is normal
float width, // column width,
float r,float g,float b) //Font color

And that one function is all you need from that point on.

Oh, yes… the function could be improved in many ways. However, you could
just use glColor4f(r, g, b, a); prior to calling the write_left_aligned
function. The color will be as set without needing to reload the textures.On Fri, May 25, 2012 at 5:15 PM, Trev wrote:

**

Chris Bush wrote:

You’re right that generating the textures for each new string every
cycle will not perform well. Preloading the glyphs from a font to a texture
set and assembling on the fly instead seems to work alright for me. The
relevant parts I’ve mashed into the example program below (c++/sdl2). But
this approach is only for game text. It’s not great for regular
applications where the standard OS widgets are familiar, complete and
comfortable for people. So, for the text areas and things, you might want
to be using a GUI library such as GTK+… but if you do choose to render
letters as individual textures, feel free to have at the code here (note
the paths to fonts at lines 102-105).

http://codepad.org/QS26ciMD

That seems like a great example code and is pretty close to exactly what I
am looking for.

I have a minor tweak that I think is an improvement. If you pass some RGB
values to void Text_ure::write(float x, float y, float lh, float r,float
g,float b), then you can dynamically change the color of the font without
having to reload it. Just make sure you pass a white color to
TTF_RenderText_Blended when the glyph images are being created initially.
And you can pass RGB values to write_left_aligned so it in turn can pass
them to Text_ure::write. That leaves you with:

Code:

void write_left_aligned( // write
Text_ure Lettercase[], // with letter case
const char
s, // input C string
float top, float left, // upper left corner
float fontsize, // size
float lineheight, // line height factor - 1 is normal
float kerning, // letter spacing factor - 1 is normal
float width, // column width,
float r,float g,float b) //Font color

And that one function is all you need from that point on.


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

Chris Bush wrote:

Oh, yes… the function could be improved in many ways. However, you could just use glColor4f(r, g, b, a); prior to calling the write_left_aligned function. The color will be as set without needing to reload the textures.

I tried my hand at making the code more easy to use. I appreciate suggestions for improvement.
http://forums.libsdl.org/viewtopic.php?t=8194

It’s neat. I like the prospective alignment feature. One might go in the
direction of creating something like a paragraph class that you can create,
position on the plane, set the typeface and kerning and so on, and fill and
refill with text. I think setting the color in the glyph drawing function
might not be optimal, since for a given input to DrawText you must pass and
set the colors to each letter. Anyway, it looks useful. Thanks for leaving
the credit.

ChrisOn Sat, May 26, 2012 at 8:39 AM, Trev wrote:

**

Chris Bush wrote:

Oh, yes… the function could be improved in many ways. However, you
could just use glColor4f(r, g, b, a); prior to calling the
write_left_aligned function. The color will be as set without needing to
reload the textures.

I tried my hand at making the code more easy to use. I appreciate
suggestions for improvement.
http://forums.libsdl.org/viewtopic.php?t=8194


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

Chris Bush wrote:

It’s neat. I like the prospective alignment feature. One might go in the direction of creating something like a paragraph class that you can create, position on the plane, set the typeface and kerning and so on, and fill and refill with text. I think setting the color in the glyph drawing function might not be optimal, since for a given input to DrawText you must pass and set the colors to each letter. Anyway, it looks useful. Thanks for leaving the credit.

Chris

I guess you’re right about the color. I think it would be better to set the color before. This could be done in another function, like:

Code:
void DrawStringX(int FontId,char str[],float top, float left,float lineheight,float kerning,float width,int Alignment,float Red,float Green,float Blue,float Alpha)
{
glColor4f(Red,Green,Blue,Alpha);
gFontRecord.DrawText(FontId,
str, //Now any text can be written here
40,12, // upper left corner
1.0, // line height factor. 1 is normal
1.0, // letter spacing factor. 1 is normal
600, // column wrap width, 0 disables wrapping
TEXT_ALIGNMENT_LEFT); // text alignment, see TextAlignmentTypes. Not yet implemented, defaults to TEXT_ALIGNMENT_LEFT
}

That provides the same interface, but a lot less function calls to glColor4f.