C/C++ & OpenGL - Lightweight TTF Text Rendering (Ver 0.2)

Whether you're a newbie or an experienced programmer, any questions, help, or just talk of any language will be welcomed here.

Moderator: Coders of Rage

Post Reply
User avatar
RyanPridgeon
Chaos Rift Maniac
Chaos Rift Maniac
Posts: 447
Joined: Sun Sep 21, 2008 1:34 pm
Current Project: "Triangle"
Favorite Gaming Platforms: PC
Programming Language of Choice: C/C++
Location: UK
Contact:

C/C++ & OpenGL - Lightweight TTF Text Rendering (Ver 0.2)

Post by RyanPridgeon »

This is for all you people who want to render normal .ttf font files into text on the screen, without having to use SDL_ttf and convert it to gl textures, or use some other bloated library.

First, you'll need this small library to include and link
http://freetype.sourceforge.net/index2.html

To use my code, simply make a new font structure like this, and use loadFont(), supplying a filepath and font size

Code: Select all

struct Font* newfont;
newfont = loadFont("arial.ttf", 20);
The above code would load the font file "arial.ttf" in size 20

Then to render, put this in your rendering code

Code: Select all

glOrtho(0, 640, 0, 480, 0, 10);
printFont(newfont, "Hello, world!");
The above code would write "Hello, world!" on the screen

To finish using a font, call deleteFont on it

Code: Select all

deleteFont(newfont);
Here is the code

font.h

Code: Select all

/*All code copyright to Ryan Pridgeon, 2009
If you wish to use this code, you must include these credits
in your code, and give credit in your application/documentation
Thankyou
*/
#ifndef RYAN_FONT
#define RYAN_FONT

#include <GL/gl.h>

struct Font{
    GLuint textures[128];
    GLuint displaylist;
    float h;
};

struct Font* loadFont(char*, int);

int printFont(struct Font*, char*);

int deleteFont(struct Font*);

#endif // TANK_FONT

font.c

Code: Select all

/*All code copyright to Ryan Pridgeon, 2009
If you wish to use this code, you must include these credits
in your code, and give credit in your application/documentation
Thankyou
*/
#include "font.h"

#include <ft2build.h>
#include <freetype/freetype.h>
#include <freetype/ftglyph.h>
#include <freetype/ftoutln.h>
#include <freetype/fttrigon.h>
#include <GL/gl.h>
#include <string.h>

int nextPower(int val){
    int x = 1;
    while(x<val){
        x <<= 1;
    }
    return x;
}

struct Font* loadFont(char* filepath, int height){

    struct Font* temp;
    FT_Library lib;
    FT_Face face;
    FT_Glyph glyph;
    FT_Bitmap* bitmap;
    FT_BitmapGlyph* bitglyph;
    int w, h, xpos, ypos;
    unsigned char i;
    GLubyte* buffer;
    float texpropx, texpropy;

    temp = (struct Font*)malloc(sizeof(struct Font));

    glGenTextures(128, temp->textures);
    temp->displaylist = glGenLists(128);

    FT_Init_FreeType(&lib);
    FT_New_Face(lib, filepath, 0, &face);
    FT_Set_Char_Size(face, height << 6, height << 6, 96, 96);

    for (i=0;i<128;i++){
        // get bitmap
        FT_Load_Glyph(face, FT_Get_Char_Index(face, i), FT_LOAD_DEFAULT);
        FT_Get_Glyph(face->glyph, &glyph);
        FT_Glyph_To_Bitmap(&glyph, ft_render_mode_normal, 0, 1);
        bitglyph = (FT_BitmapGlyph*)&glyph;
        bitmap = &((FT_BitmapGlyph)glyph)->bitmap;
        w= 1;
        while(w<bitmap->width)
            w *= 2;
        h= 1;
        while(h<bitmap->rows)
            h *= 2;
        // make bitmap
        buffer = (GLubyte*)calloc(sizeof(GLubyte)*2*w*h, 1);
        for (ypos=0;ypos<bitmap->rows;ypos++){
            for (xpos=0;xpos<bitmap->width;xpos++){
                buffer[2*(xpos+ypos*w)] = bitmap->buffer[xpos+ypos*bitmap->width];
                buffer[2*(xpos+ypos*w)+1] = bitmap->buffer[xpos+ypos*bitmap->width];
            }
        }

        glBindTexture(GL_TEXTURE_2D, temp->textures[i]);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, buffer);

        // make display list (for nicely formatted text)
        glPushMatrix();
        glNewList(temp->displaylist+i, GL_COMPILE);
        glBindTexture(GL_TEXTURE_2D, temp->textures[i]);
        glPushMatrix();
        glTranslatef((*bitglyph)->left, (*bitglyph)->top-bitmap->rows, 0);
        // proportions of the texture that are the font (not padding)
        texpropx = (float)bitmap->width / (float)w;
        texpropy = (float)bitmap->rows / (float)h;

        glBegin(GL_QUADS);
         glTexCoord2f(0, 0);                glVertex3f(0, bitmap->rows, 0);
         glTexCoord2f(0, texpropy);         glVertex3f(0, 0, 0);
         glTexCoord2f(texpropx, texpropy);  glVertex3f(bitmap->width, 0, 0);
         glTexCoord2f(texpropx, 0);         glVertex3f(bitmap->width, bitmap->rows, 0);
        glEnd();
        glPopMatrix();
        glTranslatef(face->glyph->advance.x >> 6, 0, 0);
        glEndList();
        glPopMatrix();

        free(buffer);
    }

    FT_Done_Face(face);

    FT_Done_FreeType(lib);

    return temp;
}

int printFont(struct Font* temp, char* text){
    glListBase(temp->displaylist);
    glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);
    return 0;
}

int deleteFont(struct Font* temp){
    glDeleteTextures(128, temp->textures);
    glDeleteLists(temp->displaylist, 128);
    free(temp);
    return 0;
}

Ryan Pridgeon
C, C++, C#, Java, ActionScript 3, HaXe, PHP, VB.Net, Pascal
Music | Blog
Post Reply