🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Problem with lesson 43

Started by
0 comments, last by Katz 13 years ago
Hello !

I'm having troubles with lesson 43. I can't get FreeType to work and display text. I made a test program to try to make it work.
I've changed some things from lesson 43, taken out some things I wouldn't need, changed some variables names to respect my own conventions, and mixed it up a little with the tutorial on FreeType's website.

Problem is I don't get any text. OpenGL works fine, as I get a red rectangle. But no text.
The main problem is I don't really understand all that was done in the tutorial, so I might have changed some stuff I wasn't supposed to... I especially cut a whole lot in the "print()" function (renamed "write()" in my code).

Can someone help me get this code to work? Or point out at least what vital part I'm missing, so I can look it up in the tutorial?

Thanks !

Code follows:
#include <SDL.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <vector>
#include <string>
#include <iostream>

using namespace std;

struct font_data
{
int h;
GLuint *textures;
GLuint listBase;

void init(string fontName, unsigned int h); //create font of required height
void clean(); //clean font data
};

void write(const font_data &ft_font, int x, int y, string text);

//get power of two right above given number
inline int nextP2(int nb)
{
int ret=1;
while(ret < nb)
ret *= 2;
return ret;
}

//create a display lit corresponding to the given character
void makeDList(FT_Face font, char ch, GLuint listBase, GLuint *texBase)
{
if(FT_Load_Char(font, ch, FT_LOAD_RENDER))
cout << "FT_Load_Char failed in makeDList." << endl;
FT_Bitmap &bitmap = font->glyph->bitmap;

//get required with and height to get correct texture size
int width = nextP2(bitmap.width);
int height = nextP2(bitmap.rows);

GLubyte *expandedData = new GLubyte [2*width*height];

for(int j=0;j<height;j++)
{
for(int i=0;i<width;i++)
expandedData[2*(i+j*width)] = expandedData[2*(i+j*width)+1] = (i>=bitmap.width || j>=bitmap.rows) ? 0 : bitmap.buffer[i+bitmap.width*j];
}

glBindTexture(GL_TEXTURE_2D, texBase[ch]);
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, width, height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, expandedData);

delete [] expandedData;

glNewList(listBase + ch, GL_COMPILE);

glBindTexture(GL_TEXTURE_2D, texBase[ch]);

glPushMatrix();

//glTranslatef(font->glyph->left,0,0); //shift character to have right amount of space before
//glTranslatef(0,font->glyph->top - bitmap.rows,0); //move down a little if previous line has lower character
int x = bitmap.width / width; //take empty space around char into account
int y = bitmap.rows / height;

glBegin(GL_QUADS);
glTexCoord2d(0,0);
glVertex2f(0,bitmap.rows);
glTexCoord2d(0,y);
glVertex2f(0,0);
glTexCoord2d(x,y);
glVertex2f(bitmap.width,0);
glTexCoord2d(x,0);
glVertex2f(bitmap.width,bitmap.rows);
glEnd();
glPopMatrix();
//glTranslatef(font->glyph->advance.x * 64,0,0);

glEndList();
}

void font_data::init(string fontName, unsigned int h)
{
textures = new GLuint[128];
this->h=h;

FT_Library library;
if(FT_Init_FreeType(&library))
cout << "Could not initialize Freetype library" << endl;

FT_Face font;
if(FT_New_Face(library, fontName.c_str(), 0, &font))
cout << "Could not open font \"" <<fontName<<"\"."<<endl;
FT_Set_Char_Size(font, h*64,h*64,96,96); //set font size

//allocate resources for textures and display lists
listBase=glGenLists(128);
glGenTextures(128,textures);

//create each of the fonts display lists
for(unsigned char i=0;i<128;i++)
makeDList(font,i,listBase,textures);

FT_Done_Face(font);
FT_Done_FreeType(library);
}

void font_data::clean()
{
glDeleteLists(listBase,128);
glDeleteTextures(128,textures);
delete [] textures;
}

void write(const font_data &ft_font, int x, int y, string text)
{
GLuint font = ft_font.listBase;
glListBase(font);

glPushMatrix();
glLoadIdentity();
glTranslatef(x,y,0); //move to text
glCallLists(text.length(), GL_UNSIGNED_BYTE,text.c_str());
glPopMatrix();
}

int main ( int argc, char** argv )
{
SDL_Init( SDL_INIT_VIDEO );
SDL_SetVideoMode(800, 600, 32, SDL_OPENGL);
//initialize freetype
/*FT_Library freetype;
if(FT_Init_FreeType(&freetype) != 0)
{
cout << "Unable to initialize Freetype library." <<endl;
exit(EXIT_FAILURE);
}*/
//set openGL parameters
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0,800,600,0);
glDisable(GL_DEPTH_TEST); //depth buffering
glEnable(GL_TEXTURE_2D); //texture using
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);

font_data myFont;
myFont.init("../TD/fonts/jester.ttf", 40);

SDL_Event event;
bool quit = false;
while(!quit)
{
glClear(GL_COLOR_BUFFER_BIT);

glColor3ub(255,0,0);
glDisable(GL_TEXTURE_2D);
glBegin(GL_QUADS);
glVertex2d(180,280);
glVertex2d(480,280);
glVertex2d(480,480);
glVertex2d(180,480);
glEnd();
glColor3ub(0,255,0);
glEnable(GL_TEXTURE_2D);
write(myFont,200,300, "Hello World!");

glFlush();
SDL_GL_SwapBuffers();

while (SDL_PollEvent(&event))
{
if(event.type == SDL_QUIT || (event.type == SDL_KEYDOWN && (event.key.keysym.sym == SDLK_ESCAPE || event.key.keysym.sym == SDLK_RETURN)))
quit=true;
}
}

myFont.clean();
SDL_Quit();
}
Advertisement
OK, I solved my own problem, after much looking around.
I had two main problems: One was that my texture coordinates were entered into integers, although they are supposed to by smaller than 1. (Two days for this problem... *facepalm*)
The other was that I am using a different coordinate system: My ordinate axis runs from top to bottom and not bottom to top.

Anyway, working code, if it may help anybody:

#include <SDL.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <vector>
#include <string>
#include <iostream>

using namespace std;

struct font_data
{
int h;
GLuint *textures;
GLuint listBase;

void init(string fontName, unsigned int h); //create font of required height
void clean(); //clean font data
};

void write(const font_data &ft_font, int x, int y, string text);

//get power of two right above given number
inline int nextP2(int nb)
{
int ret=1;
while(ret < nb)
ret *= 2;
return ret;
}

//create a display lit corresponding to the given character
void makeDList(FT_Face font, unsigned char ch, GLuint listBase, GLuint *texBase)
{
if(FT_Load_Char(font, ch, FT_LOAD_RENDER))
cout << "FT_Load_Char failed in makeDList." << endl;
FT_GlyphSlot glyph = font->glyph;
FT_Bitmap &bitmap = glyph->bitmap;

//get required width and height to get correct texture size
int width = nextP2(bitmap.width);
int height = nextP2(bitmap.rows);

GLubyte *expandedData = new GLubyte [2*width*height];

for(int j=0;j<height;j++)
{
for(int i=0;i<width;i++)
{
expandedData[2*(i+j*width)] = 255;
expandedData[2*(i+j*width)+1] = (i>=bitmap.width || j>=bitmap.rows) ? 0 : bitmap.buffer[i+bitmap.width*j];
}
}

glBindTexture(GL_TEXTURE_2D, texBase[ch]);
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, width, height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, expandedData);

delete [] expandedData;

glNewList(listBase + ch, GL_COMPILE);

glBindTexture(GL_TEXTURE_2D, texBase[ch]);

glPushMatrix();
glTranslatef(glyph->bitmap_left,0,0); //shift character to have right amount of space before
glTranslatef(0, (font->bbox.yMax - glyph->metrics.horiBearingY)/64,0); //move down a little if previous line has lower character
double x = (double)bitmap.width /(double)width; //take empty space around char into account
double y = (double)bitmap.rows / (double)height;

glBegin(GL_QUADS);
glTexCoord2d(0,y);
glVertex2f(0,bitmap.rows);
glTexCoord2d(0,0);
glVertex2f(0,0);
glTexCoord2d(x,0);
glVertex2f(bitmap.width,0);
glTexCoord2d(x,y);
glVertex2f(bitmap.width,bitmap.rows);
glEnd();
glPopMatrix();
glTranslatef(glyph->metrics.horiAdvance/64,0,0);

glEndList();
}

void font_data::init(string fontName, unsigned int h)
{
textures = new GLuint[128];
this->h=h;

FT_Library library;
if(FT_Init_FreeType(&library))
cout << "Could not initialize Freetype library" << endl;

FT_Face font;
if(FT_New_Face(library, fontName.c_str(), 0, &font))
cout << "Could not open font \"" <<fontName<<"\"."<<endl;
FT_Set_Char_Size(font, h*64,h*64,96,96); //set font size

//allocate resources for textures and display lists
listBase=glGenLists(128);
glGenTextures(128,textures);

//create each of the fonts display lists
for(unsigned char i=0;i<128;i++)
makeDList(font,i,listBase,textures);

FT_Done_Face(font);
FT_Done_FreeType(library);
}

void font_data::clean()
{
glDeleteLists(listBase,128);
glDeleteTextures(128,textures);
delete [] textures;
}

void write(const font_data &ft_font, int x, int y, string text)
{
GLuint font = ft_font.listBase;
glListBase(font);

glPushMatrix();
glTranslatef(x,y,0); //move to text
glCallLists(text.length(), GL_UNSIGNED_BYTE,text.c_str());
glPopMatrix();
}

int main ( int argc, char** argv )
{
SDL_Init( SDL_INIT_VIDEO );
SDL_SetVideoMode(800, 600, 32, SDL_OPENGL);
//set openGL parameters
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0,800,600,0);
glDisable(GL_DEPTH_TEST); //depth buffering
glEnable(GL_TEXTURE_2D); //texture using
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);

font_data myFont;
myFont.init("../TD/fonts/jester.ttf", 20);

SDL_Event event;
bool quit = false;
while(!quit)
{
glClear(GL_COLOR_BUFFER_BIT);

glColor3ub(255,255,255);
glDisable(GL_TEXTURE_2D);
glBegin(GL_QUADS);
glVertex2d(0,0);
glVertex2d(800,0);
glVertex2d(800,600);
glVertex2d(0,600);
glEnd();
glEnable(GL_TEXTURE_2D);
glColor3ub(180,180,0);
write(myFont,200,300, "Hello World!");

glFlush();
SDL_GL_SwapBuffers();

while (SDL_PollEvent(&event))
{
if(event.type == SDL_QUIT || (event.type == SDL_KEYDOWN && (event.key.keysym.sym == SDLK_ESCAPE || event.key.keysym.sym == SDLK_RETURN)))
quit=true;
}
}

myFont.clean();
SDL_Quit();
}

This topic is closed to new replies.

Advertisement