TIGSource Forums

Developer => Technical => Topic started by: Hima on May 20, 2009, 08:09:04 PM



Title: SDL + OpenGL : Need help with UTF8 Truetype font rendering
Post by: Hima on May 20, 2009, 08:09:04 PM
Hello everyone.

I'm still learning OpenGL and SDL. Now I can draw 2D texture with rotating, scaling and alpha blending and all that stuff. However, when it comes to text rendering, it seems like it is really mess in OpenGL :(

I've been doing some search and found out that you can use SDL_TTF to render the font on the surface, blit that surface on another surface, and convert the last surface into a texture. Problem is, you have to do this every single frame ( create surface->blit->convert to texture->freesurface->destroy texture) So it can be pretty slow. And plus, you won't be able to use alpha blend or transparency ( not that I know of anyway)

So my question is, what should I do with true type font text rendering with OpenGL? I have heard of Freetype, but I don't really know how to use it ( OpenGL newbie, sorry :( ) My main concern is that I want it to be able to render my language, which is Thai. And in order to do that, it needs to support UTF-8. Bitmap font is out of the question since my language won't support that, due to the weird vowels that can go above or below most of the alphabets.

So, any suggestions? Thank you in advance :)


Title: Re: SDL + OpenGL : Need help with UTF8 Truetype font rendering
Post by: lulzapricot on May 20, 2009, 08:21:09 PM
Problem is, you have to do this every single frame ( create surface->blit->convert to texture->freesurface->destroy texture) So it can be pretty slow.

If you need the text to change dynamically you could have it blit/render the surface text only when it is updated, or if it is static text you could have an initial function that would do all this once?  Sorry if I'm misunderstanding here.

And plus, you won't be able to use alpha blend or transparency ( not that I know of anyway)

There is transparency as well as alpha blending in sdl =D.  I was always under the impression that the alpha blending is slow in SDL though, but upon some testing it seems very fast(Still feel it is slow deep down though, dispite my tests.).

Code:
AlphaBlendedSurface = SDL_DisplayFormatAlpha(LoadedImage);

With .png anyways.


Hope I could help.



Title: Re: SDL + OpenGL : Need help with UTF8 Truetype font rendering
Post by: Hima on May 20, 2009, 08:40:30 PM

If you need the text to change dynamically you could have it blit/render the surface text only when it is updated, or if it is static text you could have an initial function that would do all this once?  Sorry if I'm misunderstanding here.
Oh you understand it correctly. The text will be changed dynamically though, since I want to use it for game message box and all that as well. So caching the texture won't work in this case :(

There is transparency as well as alpha blending in sdl =D.  I was always under the impression that the alpha blending is slow in SDL though, but upon some testing it seems very fast(Still feel it is slow deep down though, dispite my tests.).
Hmmm I'm not sure if that would work with blitting the surface made from SDL_TTF. Here's my code. It might help to know what I'm doing wrong.

Code:
void DrawText(char *text, TTF_Font *font, SDL_Color color,int x, int y)
{
    SDL_Surface *srcSurface;
    SDL_Surface *destSurface;
    GLuint texture;
    int w, h;

    srcSurface = TTF_RenderUTF8_Blended(font,text, color);

/* Convert the rendered text to a known format */
w = Math.nextpoweroftwo(srcSurface.w);
h = Math.nextpoweroftwo(srcSurface.h);

destSurface = SDL_CreateRGBSurface(0, w, h, 32,
0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);

    SDL_BlitSurface(srcSurface, null, destSurface, null);

    //Make a texture from the blitted surface.
    texture = ResourceManager.get().makeTextureFromSurface(destSurface);
    // Start drawing
    glLoadIdentity();
    glBindTexture(GL_TEXTURE_2D, texture);
glColor3f(1.0f, 1.0f, 1.0f);
    glTranslatef(x, y, 0.0f);
// Draw a quad at location
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(0    , 0, 0);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(w, 0, 0);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(w, h, 0);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(0, h, 0);
glEnd();
//I have no idea what is glFinish() for....
//glFinish();

// Clean up
SDL_FreeSurface(srcSurface);
SDL_FreeSurface(destSurface);
glDeleteTextures(1, &texture);
}

The code is actually in D programming language though. I'm still new to it as well, so it looks more like C++   :durr:


Title: Re: SDL + OpenGL : Need help with UTF8 Truetype font rendering
Post by: mcc on May 21, 2009, 01:07:20 AM
What I use is FreeType+FTGL (http://homepages.paradise.net.nz/henryj/code/) and the FTGL Texture Font object, which supports alpha blending out of the box. (I can post some of my sample code if that would be helpful.) I do not know for sure if FTGL supports Unicode or alternate character sets, but I know Freetype does, so if FTGL does not support extended character sets it should be trivial to modify it so it does.


Title: Re: SDL + OpenGL : Need help with UTF8 Truetype font rendering
Post by: Alex May on May 21, 2009, 01:16:01 AM
I use BMFont (http://www.angelcode.com/products/bmfont/) and wrote my own text rendering routine.

Why do you need actual TTF rendering, particularly? It seems easier just to render out a texture of the font and use that.


Title: Re: SDL + OpenGL : Need help with UTF8 Truetype font rendering
Post by: Overkill on May 21, 2009, 01:33:21 AM
You could just render a bunch of font glyphs onto textures (like letters and numbers and simple punctuation). Then just use those glyphs to construct the messages you want to display. This way you get the savings of not blitting onto surfaces constantly. You draw one quad per character.

You could make the glyph texture cache load new characters as you require them, also (thus accomodating for the other printable UTF-8 characters). The lookup should be relatively fast since you could keep a mapping from characters to glyph textures. And you could even optimize this by sharing textures between glyphs and just blitting subregions of that texture.


Title: Re: SDL + OpenGL : Need help with UTF8 Truetype font rendering
Post by: Hima on May 21, 2009, 04:09:21 AM
What I use is FreeType+FTGL (http://homepages.paradise.net.nz/henryj/code/) and the FTGL Texture Font object, which supports alpha blending out of the box. (I can post some of my sample code if that would be helpful.) I do not know for sure if FTGL supports Unicode or alternate character sets, but I know Freetype does, so if FTGL does not support extended character sets it should be trivial to modify it so it does.

Yes, please do. There is already a Freetype library for D programming language, so this should be another option for me to consider. Thank you! :)

I use BMFont (http://www.angelcode.com/products/bmfont/) and wrote my own text rendering routine.

Why do you need actual TTF rendering, particularly? It seems easier just to render out a texture of the font and use that.

This is because my language vowels can be placed either on top or below any alphabets. Also, there are special character modification that can go on top of those vowels to change the pronunciation and meaning of the word. If I understand correctly, with Bitmap font, I have to handle all these rendering rule myself, which I believe it would be a lot of work. So I would like to find the other solutions first before going with this one.

You could just render a bunch of font glyphs onto textures (like letters and numbers and simple punctuation). Then just use those glyphs to construct the messages you want to display. This way you get the savings of not blitting onto surfaces constantly. You draw one quad per character.

You could make the glyph texture cache load new characters as you require them, also (thus accomodating for the other printable UTF-8 characters). The lookup should be relatively fast since you could keep a mapping from characters to glyph textures. And you could even optimize this by sharing textures between glyphs and just blitting subregions of that texture.

Honestly, I don't know what a glyph is...but this sounds like a bitmap font, no? Sorry if I misunderstand anything. But if it is the same approach as bitmap font, I'd suffer the same problem of complex rendering rule like what I've answered Alex May. I tried my languag with SDL_TTF and it handles the rendering pretty well, so it would be nice to do that with OpenGL as well. I don't want to write different render rule for different languages myself :(


Thank you for taking time to answer, guys. Really appreciate it :)


Title: Re: SDL + OpenGL : Need help with UTF8 Truetype font rendering
Post by: Alex May on May 21, 2009, 05:35:45 AM
Ah, I see. Well, good luck. I am not too familiar with TTF rendering.


Title: Re: SDL + OpenGL : Need help with UTF8 Truetype font rendering
Post by: Hima on May 21, 2009, 06:45:43 AM
After I had been searching for more information about glyph, I found this tutorial about text rendering in OpenGL, written in D programming language.

http://dmedia.dprogramming.com/?n=Tutorials.TextRendering1

From what I've skim through, I think the tutorial use what Overkill suggest. Making a glymph texture and use that to render each character of the text.

It also support my language and it seems like it works fine with all those weird vowels! I'll try that and see how it work for me :D Thanks for the help folks!


Title: Re: SDL + OpenGL : Need help with UTF8 Truetype font rendering
Post by: muku on May 21, 2009, 08:48:31 AM
Hey, you're using D! I'm too. I have a font rendering class that does what people have described (create a texture which contains lots of glyphs and then render single characters as quads). I don't know if this approach will work for Thai, unfortunately. But anyway you can view my code here: http://pastebin.com/m3804d76b (http://pastebin.com/m3804d76b). It's pretty messy, but maybe you can take something away from it.


Title: Re: SDL + OpenGL : Need help with UTF8 Truetype font rendering
Post by: Hima on May 21, 2009, 09:36:24 AM
Nice to know that there's another D programmer here :) I'm very new to D but I like it so far!

And thanks for the code :D I see you're using Derelict too. Right now I'm having a problem when I try to load DerelictFT. This is an error it gives me.

Code:
derelict.util.exception.SharedLibProcLoadException: Failed to load proc FT_Select_Size from shared library freetype.dll

Am I doing anything wrong? I'm using the latest version of Derelict with Tango and dmd 1.043.

EDIT : Problem solved. The dll that I used is outdated. Replaced with the new dll and everything load just fine.

--------------------------------------------------------------------

I don't think I understand most of the code in that link, due to many call to Freetype libraries that I'm not used to. Could you please explain the code a little bit? Or is there any tutorial for a beginner?  ( Or maybe I should learn more OpenGL before doing this :'( )


Title: Re: SDL + OpenGL : Need help with UTF8 Truetype font rendering
Post by: muku on May 22, 2009, 06:24:55 PM
I don't think I understand most of the code in that link, due to many call to Freetype libraries that I'm not used to. Could you please explain the code a little bit? Or is there any tutorial for a beginner?  ( Or maybe I should learn more OpenGL before doing this :'( )

Yeah, FT can be pretty rough to get started with, it took me a while myself. There's a quite useful tutorial on the official site though:

http://www.freetype.org/freetype2/docs/tutorial/step1.html

Just ask if you need more specific help!

EDIT: This is a very helpful read as well: http://www.freetype.org/freetype2/docs/glyphs/index.html


Title: Re: SDL + OpenGL : Need help with UTF8 Truetype font rendering
Post by: mcc on May 22, 2009, 11:47:51 PM
Here is some simple sample code for using the FTGL library (http://homepages.paradise.net.nz/henryj/code/). It is C++ but as I understand D should be easy to convert to.

This code assumes the existence of two global variables named "surfaceh" and "surfacew", these being the height and width in pixels of your display surface. I get these by just reading the "h" and "w" members of the structure returned by SDL_SetVideoMode.

Be aware your projection and model matrices will be all messed up after you call drawText().

Code:
// Leave these at the top of your file:
#include "FTGLTextureFont.h"
FTFont* uiFont = NULL;
GLuint ftex;
static float tempTexture[] = { 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0};

void orthoText() { // Puts screen in a 1:1 pixel:point relationship
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-surfacew/2, surfacew/2, -surfaceh/2, surfaceh/2, -1.0, 5.0);
    glScalef(2.0*aspect, 2.0, 1.0);
    glMatrixMode(GL_MODELVIEW);
}

#define ERROR(...) fprintf (stderr, __VA_ARGS__) /* Or whatever. */
void Quit(int code) { SDL_Quit(); exit(code); }  /* Or whatever. */

// Call this once, near the beginning of your program, with the desired point size as argument.
void initFont(int size) {
    if (uiFont)
        delete uiFont;

    uiFont = new FTGLTextureFont("/PATH/TO/FONT/FILE/DroidSans.ttf");

    if ( !uiFont ){
        ERROR("Couldn't open font file: %s\n", fontfile);
        Quit(1);
    }

    if ( uiFont->Error() ){
        ERROR("Couldn't open font file (error %d): %s\n", (int)uiFont->Error(), fontfile);
        Quit(1);
    }

    uiFont->FaceSize(size);
    // uiFontHeight = uiFont->LineHeight(); // If needed

    glGenTextures(1, &ftex);
    glBindTexture(GL_TEXTURE_2D, ftex);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 4, 4, 0, GL_RGB, GL_FLOAT, tempTexture);
}

// Call this when you want to draw something. x and y are in range -1..1
void drawText(string text, double x, double y) {
    orthoText();
    glLoadIdentity();
    glColor3f(0.0,0.0,0.0); // Or whatever
    glTranslatef(x*surfaceh/2, y*surfaceh/2, 0);

    glEnable( GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, ftex);
    uiFont->Render(text.c_str());
    glDisable( GL_TEXTURE_2D);
}

Most of this code I adapted from public domain sample code, so consider this code snippet public domain too.