# Freetype and small letters appearing broken

This topic is 3829 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hello I am having an issue with free type. I am using freetype 2.3.5 lib with patented hinting. The letters "i" and "l" seem to be broken. Everything else appears to be fine. I tested this with arial and verdana and a few others. This is at font size 9. I'm not sure what is causing this. Should I post the font code I am using?

##### Share on other sites
Here is the code I am using. Its more or less from NEHE's tutorial #43

class Font{public:	std::string		font_name;	float			font_size;	unsigned int	m_fontList;	unsigned int*	m_textureIDs;	bool			m_bInitialized;	bool			m_bFontSmoothing;	float			font_widths[128];	Font();	Font(std::string font_name, float font_size, bool font_smoothing = true, bool auto_initialize = false);	~Font();	virtual float getLineHeight();	void initialize();protected:	void makeDisplayList ( FT_Face face, char ch, unsigned int list_base, unsigned int * tex_base );public:	float getWidth(std::string str);	virtual float drawText(int x, int y, std::string str);};

Font::Font() : 	m_textureIDs(0), 	m_fontList(0), 	m_bFontSmoothing(true),	m_bInitialized(false){}Font::Font(std::string font_name, float font_size, bool font_smoothing, bool auto_initialize){	this->font_name = font_name;	this->font_size = font_size;	m_bFontSmoothing = font_smoothing;	m_bInitialized = false;	if(auto_initialize)		initialize();		}Font::~Font(){	if(m_bInitialized)	{		glDeleteLists(m_fontList,128);		glDeleteTextures(128,m_textureIDs);		delete [] m_textureIDs;	}}void Font::initialize(){	if(m_bInitialized)		return;	m_bInitialized = true;	int h = (int)font_size;	m_textureIDs = new GLuint[128];	// Create And Initilize A FreeType Font Library.	FT_Library library;	if (FT_Init_FreeType( &library )) 		throw std::runtime_error("FT_Init_FreeType failed");	// The Object In Which FreeType Holds Information On A Given	// Font Is Called A "face".	FT_Face face;	// This Is Where We Load In The Font Information From The File.	// Of All The Places Where The Code Might Die, This Is The Most Likely,	// As FT_New_Face Will Fail If The Font File Does Not Exist Or Is Somehow Broken.	if (FT_New_Face( library, font_name.c_str(), 0, &face )) 		throw std::runtime_error("FT_New_Face failed (there is probably a problem with your font file)");	// For Some Twisted Reason, FreeType Measures Font Size	// In Terms Of 1/64ths Of Pixels.  Thus, To Make A Font	// h Pixels High, We Need To Request A Size Of h*64.	// (h << 6 Is Just A Prettier Way Of Writing h*64)	//FT_Set_Char_Size( face, h << 6, h << 6, 96, 96);	//FT_Set_Char_Size( face, 0, h << 6, 96, 96);	FT_Set_Pixel_Sizes(face, 0, h*72/64);	// Here We Ask OpenGL To Allocate Resources For	// All The Textures And Display Lists Which We	// Are About To Create.  	m_fontList=glGenLists(128);	glGenTextures( 128, m_textureIDs );	// This Is Where We Actually Create Each Of The Fonts Display Lists.	for(unsigned char i=0;i<128;i++)		makeDisplayList(face,i,m_fontList,m_textureIDs);	// We Don't Need The Face Information Now That The Display	// Lists Have Been Created, So We Free The Assosiated Resources.	FT_Done_Face(face);	// Ditto For The Font Library.	FT_Done_FreeType(library);	gpFontManager->insert(this);}void Font::makeDisplayList ( FT_Face face, char ch, unsigned int list_base, unsigned int * tex_base){	// The First Thing We Do Is Get FreeType To Render Our Character	// Into A Bitmap.  This Actually Requires A Couple Of FreeType Commands:	// Load The Glyph For Our Character.	//if(m_bFontSmoothing)	//{	if(FT_Load_Glyph( face, FT_Get_Char_Index( face, ch ), FT_LOAD_DEFAULT ))		throw std::runtime_error("FT_Load_Glyph failed");	//}	//else	//{	//	if(FT_Load_Glyph( face, FT_Get_Char_Index( face, ch ), FT_LOAD_MONOCHROME ))	//		throw std::runtime_error("FT_Load_Glyph failed");	//}	// Move The Face's Glyph Into A Glyph Object.	FT_Glyph glyph;	if(FT_Get_Glyph( face->glyph, &glyph ))		throw std::runtime_error("FT_Get_Glyph failed");	// Convert The Glyph To A Bitmap.	if(m_bFontSmoothing)		FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );	else		FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_MONO, 0, 1 );	FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph;	// This Reference Will Make Accessing The Bitmap Easier.	FT_Bitmap& bitmap=bitmap_glyph->bitmap;		// Use Our Helper Function To Get The Widths Of	// The Bitmap Data That We Will Need In Order To Create	// Our Texture.	int width = nearestPower2( bitmap.width );	int height = nearestPower2( bitmap.rows );	// Allocate Memory For The Texture Data.	unsigned char* expanded_data = new unsigned char[ 2 * width * height];	// Here We Fill In The Data For The Expanded Bitmap.	// Notice That We Are Using A Two Channel Bitmap (One For	// Channel Luminosity And One For Alpha), But We Assign	// Both Luminosity And Alpha To The Value That We	// Find In The FreeType Bitmap. 	// We Use The ?: Operator To Say That Value Which We Use	// Will Be 0 If We Are In The Padding Zone, And Whatever	// Is The FreeType Bitmap Otherwise.	memset(expanded_data, 0, width*height*2);	if(m_bFontSmoothing)	{		for(int j=0; j < bitmap.rows;j++) 		{			for(int i=0; i < bitmap.width; i++)			{				expanded_data[2*(i+j*width)] = 255;				expanded_data[2*(i+j*width)+1] = (i>=bitmap.width || j>=bitmap.rows) ? 0 : bitmap.buffer[i + bitmap.width*j];				//expanded_data[2*(i+j*width)+1] = bitmap.buffer[i + bitmap.width*j];			}		}	}	else	{		for(int j=0; j < bitmap.rows; j++) 		{			for(int i=0; i < bitmap.pitch; i++)			{				for (int l=7; l>=0; l--)				{					if ( (bitmap.buffer[j * bitmap.pitch + i] >> l) & 1 )					{						expanded_data[(j * width * 2) + ((i * 8 + (7 - l)) * 2)] = 255;						expanded_data[(j * width * 2) + ((i * 8 + (7 - l)) * 2) + 1] = 255;					}				}			}		}	}	// Now We Just Setup Some Texture Parameters.	glBindTexture( GL_TEXTURE_2D, tex_base[ch]);	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);	// Here We Actually Create The Texture Itself, Notice	// That We Are Using GL_LUMINANCE_ALPHA To Indicate That	// We Are Using 2 Channel Data.	glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,		GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, expanded_data );	// With The Texture Created, We Don't Need The Expanded Data Anymore.	delete [] expanded_data;	// Now We Create The Display List	glNewList(list_base+ch,GL_COMPILE);	glBindTexture(GL_TEXTURE_2D,tex_base[ch]);	glPushMatrix();	// First We Need To Move Over A Little So That	// The Character Has The Right Amount Of Space	// Between It And The One Before It.	glTranslatef((float)bitmap_glyph->left,0.f,0.f);	// Now We Move Down A Little In The Case That The	// Bitmap Extends Past The Bottom Of The Line 	// This Is Only True For Characters Like 'g' Or 'y'.	glTranslatef(0.f,(float)bitmap_glyph->top-bitmap.rows,0.f);	// Now We Need To Account For The Fact That Many Of	// Our Textures Are Filled With Empty Padding Space.	// We Figure What Portion Of The Texture Is Used By 	// The Actual Character And Store That Information In	// The x And y Variables, Then When We Draw The	// Quad, We Will Only Reference The Parts Of The Texture	// That Contains The Character Itself.	float x=(float)bitmap.width / (float)width;	float y=(float)bitmap.rows / (float)height;	// Here We Draw The Texturemapped Quads. The Bitmap That We Got From FreeType Was Not 	// Oriented Quite Like We Would Like It To Be, But We Link The Texture To The Quad	// In Such A Way That The Result Will Be Properly Aligned.	glBegin(GL_QUADS);	glTexCoord2d(0.f,0.f); glVertex2f(0.f,(float)bitmap.rows);	glTexCoord2d(0.f,y); glVertex2f(0.f,0.f);	glTexCoord2d(x,y); glVertex2f((float)bitmap.width,0.f);	glTexCoord2d(x,0.f); glVertex2f((float)bitmap.width,(float)bitmap.rows);	glEnd();	glPopMatrix();	glTranslatef((float)(face->glyph->advance.x >> 6) ,0.f,0.f);	font_widths[ch] = face->glyph->advance.x >> 6;	// Increment The Raster Position As If We Were A Bitmap Font. (Only Needed If You Want To Calculate Text Length)	//glBitmap(0,0,0,0,face->glyph->advance.x >> 6,0,NULL);	// Finish The Display List	glEndList();	}float Font::getWidth(std::string str){	if(!m_bInitialized)		return -1.f;	float width = 0;	for(int i=0; i < (int)str.size(); i++)		width += font_widths[str];	return width + 3;	//random offset .... i dunno why but it makes the width correct}float Font::getLineHeight(){	return (int)(font_size/.7f);}float Font::drawText(int x, int y, std::string str){	if(!m_bInitialized)		return -1.f;	// We Want A Coordinate System Where Distance Is Measured In Window Pixels.	//pushScreenCoordinateMatrix();	{		glPushAttrib(GL_TRANSFORM_BIT);		GLint   viewport[4];		glGetIntegerv(GL_VIEWPORT, viewport);		glMatrixMode(GL_PROJECTION);		glPushMatrix();		glLoadIdentity();		gluOrtho2D(viewport[0],viewport[2],viewport[1],viewport[3]);		glPopAttrib();	}	// We Make The Height A Little Bigger.  There Will Be Some Space Between Lines.	int h = (int)(font_size/.7f);	// Here Is Some Code To Split The Text That We Have Been	// Given Into A Set Of Lines.  	// This Could Be Made Much Neater By Using	// A Regular Expression Library Such As The One Available From	// boost.org (I've Only Done It Out By Hand To Avoid Complicating	// This Tutorial With Unnecessary Library Dependencies).	const char *start_line=str.c_str();	std::vector<std::string> lines;	const char *c;	for(c=str.c_str();*c;c++) {		if(*c=='\n') {			std::string line;			for(const char *n=start_line;n<c;n++) line.append(1,*n);			lines.push_back(line);			start_line=c+1;		}	}	if(start_line) {		std::string line;		for(const char *n=start_line;n<c;n++) line.append(1,*n);		lines.push_back(line);	}	glPushAttrib(GL_LIST_BIT | GL_CURRENT_BIT  | GL_ENABLE_BIT | GL_TRANSFORM_BIT); 	glMatrixMode(GL_MODELVIEW);	glDisable(GL_LIGHTING);	glDisable(GL_DEPTH_TEST);	glEnable(GL_TEXTURE_2D);	glEnable(GL_BLEND);	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);      	glListBase(m_fontList);	float modelview_matrix[16];     	glGetFloatv(GL_MODELVIEW_MATRIX, modelview_matrix);	//modelview_matrix[14] = 0;	// <- sets the z coord to 0 so that it renders	// This Is Where The Text Display Actually Happens.	// For Each Line Of Text We Reset The Modelview Matrix	// So That The Line's Text Will Start In The Correct Position.	// Notice That We Need To Reset The Matrix, Rather Than Just Translating	// Down By h. This Is Because When Each Character Is	// Drawn It Modifies The Current Matrix So That The Next Character	// Will Be Drawn Immediately After It. 	for(int i=0;i<(int)lines.size();i++) {		glPushMatrix();		glLoadIdentity();		glTranslatef((float)x,(float)y-h*i,0.f);		glMultMatrixf(modelview_matrix);		// The Commented Out Raster Position Stuff Can Be Useful If You Need To		// Know The Length Of The Text That You Are Creating.		// If You Decide To Use It Make Sure To Also Uncomment The glBitmap Command		// In make_dlist().		//glRasterPos2f(0,0);		glCallLists(lines.length(), GL_UNSIGNED_BYTE, lines.c_str());		//float rpos[4];		//glGetFloatv(GL_CURRENT_RASTER_POSITION ,rpos);		//float len=x-rpos[0]; //(Assuming No Rotations Have Happend)		glPopMatrix();	}	glPopAttrib();          	//pop_projection_matrix();	{		glPushAttrib(GL_TRANSFORM_BIT);		glMatrixMode(GL_PROJECTION);		glPopMatrix();		glPopAttrib();	}	return 0;}

##### Share on other sites
Hello,

What do you get if you set GL_TEXTURE_MAG_FILTER/GL_TEXTURE_MIN_FILTER to GL_LINEAR ?

kind regards
Uncle

##### Share on other sites
Thanks for the suggestion, but it has no effect on the results.

1. 1
2. 2
3. 3
Rutin
14
4. 4
khawk
11
5. 5

• 9
• 9
• 11
• 11
• 23
• ### Forum Statistics

• Total Topics
633671
• Total Posts
3013271
×

## Important Information

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!