[OT]Drawing text (SDL_ttf/OpenGL) one character at a time

Hello,

I hope this isn’t too off-topic. I have a project where I need to
display text (filenames, comments, UI labels, etc…). I played
around with some generic UI libraries (agar, guichan), but none of
them had great (read: extant) support for Mac OS, which is my first/
primary platform for my project. So I’ve gone to a couple of
different ideas.

I really like SDL_ttf, because it supports UNICODE as well as UTF-8
rendering. But now I’m left with a choice. Do I:

  1. Render each bit of text into an image/texture and use that, or
  2. Create a series of small textures for each glyph and call them up/
    render them on the fly as needed.

I can DO option 1 now, but it seems like, especially once I get more
widgets going in my program, I’m going to quickly have a LOT of
redundant texture data for the various glyphs. For option 2, I was
figuring on taking each glyph, putting it into a std::map<> and then
iterate through each string I want to render and call up the
appropriate glyph’s texture ID and use the font metrics for drawing
each glyph one at a time.

I know it would be simpler to make an array the size of the ASCII
chart, but I want to be UTF8 enabled. That is, I personally would use
a lot of files with Japanese filenames, and want to be able to display
them.

Anyway, my biggest problem here is that I have looked around and I
have NO idea how to iterate through a string (const char*) by-hand for
each character.

Am I even going about this the right way?

I come from Java… please be gentle?

– Scott

This is a perfectly valid way of approaching the problem, and quite common
as far as I know. Note that if you’re using UTF-8, simply iterating through
a char * isn’t good enough, as a UTF-8 character can be larger than one
byte. However, for the purposes of edification:

const char *string = “I’m a string”;
unsigned int length = strlen(string);
int i;
for(i = 0; i < length; i++)
char c = string[i];

That’s how to get individual bytes from a string. Again, it won’t work for
this problem. You’ll need to find a UTF-8 string library that allows you to
retrieve individual characters from the strings.

Cheers,
JoshOn Wed, Oct 8, 2008 at 9:00 PM, Scott Harper wrote:

Hello,

I hope this isn’t too off-topic. I have a project where I need to display
text (filenames, comments, UI labels, etc…). I played around with some
generic UI libraries (agar, guichan), but none of them had great (read:
extant) support for Mac OS, which is my first/primary platform for my
project. So I’ve gone to a couple of different ideas.

I really like SDL_ttf, because it supports UNICODE as well as UTF-8
rendering. But now I’m left with a choice. Do I:

  1. Render each bit of text into an image/texture and use that, or
  2. Create a series of small textures for each glyph and call them up/render
    them on the fly as needed.

I can DO option 1 now, but it seems like, especially once I get more
widgets going in my program, I’m going to quickly have a LOT of redundant
texture data for the various glyphs. For option 2, I was figuring on taking
each glyph, putting it into a std::map<> and then iterate through each
string I want to render and call up the appropriate glyph’s texture ID and
use the font metrics for drawing each glyph one at a time.

I know it would be simpler to make an array the size of the ASCII chart,
but I want to be UTF8 enabled. That is, I personally would use a lot of
files with Japanese filenames, and want to be able to display them.

Anyway, my biggest problem here is that I have looked around and I have NO
idea how to iterate through a string (const char*) by-hand for each
character.

Am I even going about this the right way?

I come from Java… please be gentle?

– Scott


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

Hello,

I use SDL_ttf in many different 2d projects (games, educational programs with
typing texts). I don’t know OGL but I suppose working with surfaces is
similar textures.

In the begining I was using generated table of surfaces with ASCII chars, but
it was good only for my own tools. I think best (universal) solution is:

  1. Render UTF-8 text.
  2. If you don’t need to change the text, you can blit text on surface (i.e.
    you build the window then blit window title shadow, window title and other
    constant texts on window).

Text is image (Text :: Image) with some additional methods
like ‘settext’, ‘setfont’ etc.–
Dominik

Thursday 09 of October 2008 01:00:25 Scott Harper napisa?(a):

Hello,

I hope this isn’t too off-topic. I have a project where I need to
display text (filenames, comments, UI labels, etc…). I played
around with some generic UI libraries (agar, guichan), but none of
them had great (read: extant) support for Mac OS, which is my first/
primary platform for my project. So I’ve gone to a couple of
different ideas.

I really like SDL_ttf, because it supports UNICODE as well as UTF-8
rendering. But now I’m left with a choice. Do I:

  1. Render each bit of text into an image/texture and use that, or
  2. Create a series of small textures for each glyph and call them up/
    render them on the fly as needed.

I can DO option 1 now, but it seems like, especially once I get more
widgets going in my program, I’m going to quickly have a LOT of
redundant texture data for the various glyphs. For option 2, I was
figuring on taking each glyph, putting it into a std::map<> and then
iterate through each string I want to render and call up the
appropriate glyph’s texture ID and use the font metrics for drawing
each glyph one at a time.

I know it would be simpler to make an array the size of the ASCII
chart, but I want to be UTF8 enabled. That is, I personally would use
a lot of files with Japanese filenames, and want to be able to display
them.

Anyway, my biggest problem here is that I have looked around and I
have NO idea how to iterate through a string (const char*) by-hand for
each character.

Am I even going about this the right way?

I come from Java… please be gentle?

– Scott


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


Pozdrawiam,
Dominik Dagiel
@Dominik_Dagiel
tel. 695-534-932
www.dagiel.pl

If you’re using C++, try utf8-cpp (http://utfcpp.sourceforge.net) for
iteration. There is a later thread about UTF-8 here, you should also
have a look at it. Personally I think there’s little point in using
UTF-8 for in-memory strings, as the operations (iteration, length
calculations etc.) are difficult. UTF-16 std::wstring is here, so why
bother with in-memory UTF-8? (Though it may still be useful as a
transport encoding.)

As for Unicode font rendering, try QuesoGLC (for C-friendly and
OpenGL-alike APIs) or OGLFT or FTGL (for C++ OO APIs). FTGL doesn’t
support Unicode, OGLFT requires Qt’s QString for this, and GLC
supports UTF-(8|16|32) natively.

Alexander Shpilkin schrieb:

If you’re using C++, try utf8-cpp (http://utfcpp.sourceforge.net) for
iteration. There is a later thread about UTF-8 here, you should also
have a look at it. Personally I think there’s little point in using
UTF-8 for in-memory strings, as the operations (iteration, length
calculations etc.) are difficult. UTF-16 std::wstring is here, so why
bother with in-memory UTF-8? (Though it may still be useful as a
transport encoding.)

UTF16 is exactly as complicated as UTF8 if you want to do it correctly.

It is, but you can limit yourself to UCS2 and be happy with this, as
you probably don’t want ideograms and exotic scripts in game menus.
This is not a generic (and always correct) approach, but it may work
in this specific case.

AlexOn 12/10/2008, Albert Zeyer <albert.zeyer at rwth-aachen.de> wrote:

Alexander Shpilkin schrieb:

If you’re using C++, try utf8-cpp (http://utfcpp.sourceforge.net) for
iteration. There is a later thread about UTF-8 here, you should also
have a look at it. Personally I think there’s little point in using
UTF-8 for in-memory strings, as the operations (iteration, length
calculations etc.) are difficult. UTF-16 std::wstring is here, so why
bother with in-memory UTF-8? (Though it may still be useful as a
transport encoding.)

UTF16 is exactly as complicated as UTF8 if you want to do it correctly.


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

I tried using std::wstring, actually, and at least for console
printing (printf and wprintf) that I use for debugging, it seems to
break and stop printing anything thereafter. My system doesn’t crash,
it just kind of stops printing text to the console. I’m not sure what
the deal is with that.

Also, it seems that on OSX, all my internal strings are stored as as
UTF-8… or at least, I can call something like:

printf(“Hello, ???\n”);

…and it outputs it correctly to my console. I could be completely
wrong in my assumption of the factors at play here. The problem I ran
into was the issue where the lines:

wchar_t* wide_string = L"Hello, ???";
wprintf( wide_string );

…don’t display any output at all. So I’ve been looking for a
solution to help me out. (Thanks, by the way, for the library
reference! I think that my ultimate solution may include that.)

What I’ve done for the interim is to use the UTF-8 to UNICODE 16
conversion from SDL_ttf and track both a UTF-8 version (a simple c
string, I guess) and an array of Uint16 characters for storing the 16-
bit codepoint and using that to refer back to my codepoint/texture ID
map. The assumption was that if I ever CHANGE the string, I’ll just
have to re-create the Uint16 array. I may still try to incorporate
one of these solutions as a better option, since the SDL_ttf code is
LGPL, and I’m not sure I want to go that route necessarily. (I may,
I’m just not sure yet. (: )

– ScottOn Oct 12, 2008, at 12:17 PM, Alexander Shpilkin wrote:

It is, but you can limit yourself to UCS2 and be happy with this, as
you probably don’t want ideograms and exotic scripts in game menus.
This is not a generic (and always correct) approach, but it may work
in this specific case.

Alex

On 12/10/2008, Albert Zeyer <albert.zeyer at rwth-aachen.de> wrote:

Alexander Shpilkin schrieb:

If you’re using C++, try utf8-cpp (http://utfcpp.sourceforge.net)
for
iteration. There is a later thread about UTF-8 here, you should also
have a look at it. Personally I think there’s little point in using
UTF-8 for in-memory strings, as the operations (iteration, length
calculations etc.) are difficult. UTF-16 std::wstring is here, so
why
bother with in-memory UTF-8? (Though it may still be useful as a
transport encoding.)

UTF16 is exactly as complicated as UTF8 if you want to do it
correctly.


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


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

Alexander Shpilkin wrote:

If you’re using C++, try utf8-cpp (http://utfcpp.sourceforge.net) for
iteration. There is a later thread about UTF-8 here, you should also
have a look at it. Personally I think there’s little point in using
UTF-8 for in-memory strings, as the operations (iteration, length
calculations etc.) are difficult. UTF-16 std::wstring is here, so why
bother with in-memory UTF-8? (Though it may still be useful as a
transport encoding.)

Two points:

  1. The operations that are difficult in UTF-8 are just as difficult in
    UTF-16 due to surrogate pairs. Even in UTF-32, you have to worry about
    combining characters.

  2. wchar_t is 16 bit on some platforms and 32 bit on others, so the
    "natural" encoding for std::wstring could be either UTF-16 or UTF-32.
    At least with UTF-8, you don’t have to worry about platform variations.>

As for Unicode font rendering, try QuesoGLC (for C-friendly and
OpenGL-alike APIs) or OGLFT or FTGL (for C++ OO APIs). FTGL doesn’t
support Unicode, OGLFT requires Qt’s QString for this, and GLC
supports UTF-(8|16|32) natively.


Rainer Deyke - rainerd at eldwood.com

Thank you, Rayner, I didn’t know about any systems with wchar_t ==
uint32_t. Anyways, this should be easy to solve like—
template class StringSwitch;
template<> class StringSwitch<uint16_t> {
const GLCenum RESULT = GLC_UCS2;
}
template<> class StringSwitch<uint32_t> {
const GLCenum RESULT = GLC_UCS4;
}
const GLCenum GLC_WSTRING = StringSwitch<wchar_t>::RESULT;

And to make my point clear: I’m speaking about not actually UTF-16 but
UCS2, because you probably won’t have symbols others than those from
BMP in the game menus, and there’ll be no surrogate pairs to worry
about.

Alex

Thank you, Rayner, I didn’t know about any systems with wchar_t ==
uint32_t. Anyways, this should be easy to solve like

AFAIK every major system except windows has wchar_t == uint32_t, quick test:
#include
int main() { std::cerr << sizeof(wchar_t) << ‘\n’; }

Linux (32bit): 4
MacOSX (32bit): 4On Mon, Oct 13, 2008 at 12:37 PM, Alexander Shpilkin wrote:


Bye,
Gabry

Alexander Shpilkin wrote:

Thank you, Rayner, I didn’t know about any systems with wchar_t ==
uint32_t. Anyways, this should be easy to solve like


template class StringSwitch;
template<> class StringSwitch<uint16_t> {
const GLCenum RESULT = GLC_UCS2;
}
template<> class StringSwitch<uint32_t> {
const GLCenum RESULT = GLC_UCS4;
}
const GLCenum GLC_WSTRING = StringSwitch<wchar_t>::RESULT;

Actually wchar_t is a distinct type, so that won’t work. You would have
to do something like this:

template class StringSwitch;
template<> class StringSwitch<2> {
const GLCenum RESULT = GLC_UCS2;
}
template<> class StringSwitch<4> {
const GLCenum RESULT = GLC_UCS4;
}
const GLCenum GLC_WSTRING = StringSwitch<sizeof(wchar_t)>::RESULT;

…and then you still have to worry about working with and testing two
different unicode formats.

And to make my point clear: I’m speaking about not actually UTF-16 but
UCS2, because you probably won’t have symbols others than those from
BMP in the game menus, and there’ll be no surrogate pairs to worry
about.

This works until you encounter a character outside the BMP. If you’re
just displaying your own text, OK. If you’re dealing with file names or
user-entered text, not so good.–
Rainer Deyke - rainerd at eldwood.com

And to make my point clear: I’m speaking about not actually UTF-16
but
UCS2, because you probably won’t have symbols others than those from
BMP in the game menus, and there’ll be no surrogate pairs to worry
about.

This works until you encounter a character outside the BMP. If
you’re just displaying your own text, OK. If you’re dealing with
file names or user-entered text, not so good.

And I DO want to deal with filenames at least. I seem to recall there
being some discussion before about, if you want to enter text that
cannot be unpit just by pressing a single key on the keyboard (Chinese
text, Japanese from a non-Japanese keyboard not in kana-mode, are two
that I know about) you need to have some kind of Input Method Editor
in your program, and while many OSes include these, there’s not
currently any way to utilize the various OS IMEs from within an SDL
application. Was this correct or can it actually be done?

– Scott

???
…as a man’s knowledge widens, ever the way he can follow grows
narrower; until at last he chooses nothing, but does only and wholely
what he must do…
? Ursula K. Le Guin “A Wizard of Earthsea”

To the original idea by Scott Harper:

Given all that (accents, CJK, surrogate pairs etc.) it’ll be very
difficult to render strings one character at a time. It should be no
problem to render from scratch every frame and/or keep persistent
string renderings in memory. Alternatively you can use character
bitmaps for dynamic strings (that are generated by the program and
don’t use those problem codepoints by design) and persistent one-time
string rendering for static ones.

Alex

And about IMEs: sorry, I don’t know anything about these issues
personally, but it looks like there are some interesting things in a
thread named “[SDL] Some old new things about IME and XIM support.” in
2007 mailing list archives.

Cheers,
Alex