Sign in to follow this  
Starfox

OpenGL FreeType2 Trouble

Recommended Posts

I've been trying to replace the font rendering engine I'm using that someone else wrote with one of my own (for licensing reasons) based on FreeType 2. I wrote a simple app to test string-to-GL-texture rendering, but I'm seeing corruption in some characters and I've been trying to pin point the problem with no luck so far. I think I might need a second pair of eyes with more FreeType2 experience if possible - my code is based entirely on the FreeType2 first tutorial sample. Here's what the rendering looks like:

[url="http://www.flickr.com/photos/59098813@N06/5928212372/"]Picture[/url]


(This is supposed to be "ABCDE".)

and here's the code:
[code]

#include <cassert>

#include <iostream>

#include <algorithm>

using std::max;

#ifdef _WIN32
#include <GL/glut.h>
#endif

#if defined(__APPLE__) && defined(__MACH__)
#include <OpenGL/OpenGL.h>
#include <GLUT/glut.h>
#endif

#include <ft2build.h>
#include FT_FREETYPE_H

#include <stdio.h>
#include <string.h>
#include <math.h>

#include <ft2build.h>
#include FT_FREETYPE_H

GLuint Texture;
float ScreenWidth = 1280;
float ScreenHeight = 720;
float TextWidth;
float TextHeight;

void display()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, ScreenWidth - 1, 0, ScreenHeight - 1, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
const int OffsetX = 100;
const int OffsetY = 100;
glTranslatef(OffsetX, OffsetY, 0);
const float Scale = 4.0;
glScalef(Scale, Scale, Scale);
glClearColor(0, 1, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, Texture);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_NEAREST );
// when texture area is large, bilinear filter the original
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBegin(GL_QUADS);
glColor3f(1, 0, 0);
glTexCoord2f(0.0, 0.0);
glVertex3f(-0, -0, 0);
glTexCoord2f(0.0, 1.0);
glVertex3f(-0, TextHeight, 0);
glTexCoord2f(1.0, 1.0);
glVertex3f(TextWidth, TextHeight, 0);
glTexCoord2f(1.0, 0.0);
glVertex3f(TextWidth, -0, 0);
glEnd();
glutSwapBuffers();
}

void idle()
{
glutPostRedisplay();
}

struct int2
{
int x;
int y;
};

struct extents
{
int2 size;
int2 offset;
};

extents text_extents(const char* const Text, FT_Face& Face)
{
FT_GlyphSlot Slot = Face->glyph;
extents Result;
Result.size.x = Result.size.y = 0;
Result.offset.x = Result.offset.y = 0;
int num_chars = strlen(Text);
FT_Vector pen;
FT_Error error;
pen.x = pen.y = 0;
long MaximumHeight = 0;
for (int n = 0; n < num_chars; n++ )
{
/* load glyph image into the slot (erase previous one) */
error = FT_Load_Char( Face, Text[n], FT_LOAD_RENDER );
if ( error )
continue; /* ignore errors */
//
FT_Glyph_Metrics Metrics = Slot->metrics;
MaximumHeight = max(MaximumHeight, Metrics.height / 64);
Result.size.x += (Metrics.horiAdvance / 64);
}
Result.size.y = MaximumHeight;
return Result;
}

int main (int argc, const char * argv[])
{

// insert code here...
std::cout << "Hello, World!\n";
int x = 1;
char* y = "dummy";
glutInit(&x, &y);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowSize(1280, 720);
glutInitWindowPosition(100,100);
glutCreateWindow("FreeType2");
glutDisplayFunc(display);
glutIdleFunc(idle);
//
FT_Library library;
FT_Face face;

FT_GlyphSlot slot;
FT_Matrix matrix; /* transformation matrix */
FT_UInt glyph_index;
FT_Vector pen; /* untransformed origin */
FT_Error error;

char* filename;
char* text;

double angle;
int target_height;
int n, num_chars;

filename = "font.ttf"; /* first argument */
text = "ABCDE"; /* second argument */
num_chars = strlen( text );
angle = ( 180.0 / 360.0 ) * 3.14159 * 2.0; /* use 25 degrees */

error = FT_Init_FreeType( &library ); /* initialize library */
/* error handling omitted */
using namespace std;

error = FT_New_Face( library, filename, 0, &face ); /* create face object */
/* error handling omitted */

/* use 50pt at 100dpi */
error = FT_Set_Char_Size( face, 50 * 64, 50 * 64,
100, 0 ); /* set character size */
/* error handling omitted */

slot = face->glyph;

/* set up matrix */
matrix.xx = (FT_Fixed) 1.0 * 0x10000L;
matrix.xy = 0;
matrix.yx = 0;
matrix.yy = (FT_Fixed) -1.0 * 0x10000L;
//
int2 CalcSize = text_extents(text, face).size;
TextWidth = CalcSize.x;
TextHeight = CalcSize.y;
cout << "String " << text << " W: " << TextWidth << " H: " << TextHeight << endl;
glGenTextures(1, &Texture);
glBindTexture(GL_TEXTURE_2D, Texture);
unsigned char* ClearData = new unsigned char [CalcSize.x * CalcSize.y];
std::fill(ClearData, ClearData + (CalcSize.x * CalcSize.y), 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, CalcSize.x, CalcSize.y, 0, GL_ALPHA, GL_UNSIGNED_BYTE, ClearData);
delete [] ClearData;
GLuint GLError = glGetError();
if(GLError != GL_NO_ERROR)
{
cout << "GL Error: " << GLError << endl;
}
//
pen.x = pen.y = 0;
int2 Offset;
Offset.x = Offset.y = 0;
FT_Set_Transform( face, &matrix, &pen );
for ( n = 0; n < num_chars; n++ )
{
/* load glyph image into the slot (erase previous one) */
error = FT_Load_Char( face, text[n], FT_LOAD_RENDER );
if ( error )
{
cout << "Load char error!\n";
continue; /* ignore errors */
}
//
unsigned int height = slot->bitmap.rows;
unsigned int width = slot->bitmap.width;
void* data = (slot->bitmap.buffer);
cout << "Upload - offset X: " << Offset.x << " offset Y: " << Offset.y << endl;
cout << "Upload - Width : " << width << " Height : " << height << endl;
glTexSubImage2D(GL_TEXTURE_2D, 0, Offset.x, Offset.y, width, height, GL_ALPHA, GL_UNSIGNED_BYTE, data);
Offset.x += (slot->metrics.horiAdvance / 64);
//
cout << "Char: " << text[n] << " W: " << width << " H: " << height << endl;
cout << "Pitch: " << slot->bitmap.pitch << endl;
cout << "Expected Pitch: " << (width) << endl;
if((slot->bitmap.pitch) != width)
{
cout << "!!! ERROR: Pitches don't match nominal value!\n";
}
cout << "*****\n";
//

/* increment pen position */
pen.x += slot->advance.x;
pen.y += slot->advance.y;
}
//
FT_Done_Face ( face );
FT_Done_FreeType( library );
glutMainLoop();
return 0;
}

[/code]

Any ideas?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this