/* A quick and simple opengl font library that uses GNU freetype2, written and distributed as part of a tutorial for nehe.gamedev.net. Sven Olsen, 2003 edited by Ben Ruyl */ //Include our header file. #include "freetype.h" #include "menumain.h" #include "gamemain.h" using namespace std; vector charlist_extended; namespace freetype { ///This function gets the first power of 2 >= the ///int that we pass it. inline int next_p2 ( int a ) { int rval=1; while(rvalglyph, &glyph )) throw std::runtime_error("FT_Get_Glyph failed"); //Convert the glyph to a bitmap. FT_Glyph_To_Bitmap( &glyph, ft_render_mode_normal, 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 = next_p2( bitmap.width ); int height = next_p2( bitmap.rows ); //Allocate memory for the texture data. GLubyte* expanded_data = new GLubyte[ 2 * width * height]; //Here we fill in the data for the expanded bitmap. //Notice that we are using two channel bitmap (one for //luminocity and one for alpha), but we assign //both luminocity and alpha to the value that we //find in the FreeType bitmap. //We use the ?: operator so that value which we use //will be 0 if we are in the padding zone, and whatever //is the the Freetype bitmap otherwise. for(int j=0; j =bitmap.width || j>=bitmap.rows) ? 0 : bitmap.buffer[i + bitmap.width*j]; } } //Now we just setup some texture paramaters. glBindTexture( GL_TEXTURE_2D, tex_pos); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); //Here we actually create the texture itself, notice //that we are using GL_LUMINANCE_ALPHA to indicate that //we are using 2 channel data. gluBuild2DMipmaps( GL_TEXTURE_2D, 2, width, height, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, expanded_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 to expanded data anymore delete [] expanded_data; //So now we can create the display list glNewList(list_pos,GL_COMPILE); glBindTexture(GL_TEXTURE_2D,tex_pos); 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(bitmap_glyph->left,0,0); //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,bitmap_glyph->top-bitmap.rows,0); //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 we contain the character itself. float x=(float)bitmap.width / (float)width, y=(float)bitmap.rows / (float)height; //Here we draw the texturemaped quads. //The bitmap that we got from FreeType was not //oriented quite like we would like it to be, //so we need to link the texture to the quad //so that the result will be properly aligned. 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(face->glyph->advance.x >> 6 ,0,0); // glTranslatef(bitmap.width,0,0); // store the width of every character. Later on we use this to center text glEndList(); GlyphInfo newglyph; newglyph.charcode = ch; newglyph.width = face->glyph->advance.x >> 6; charwidth.push_back(newglyph); //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); //Finnish the display list } void CreateExtendedCharset(FT_Face face) { charlist_extended.resize(0); for (int k = 0; k < 50; k++) for (int i = 0; i < FLanguage[k].length(); i++) { if (FLanguage[k][i] > 0x007F) { bool found = false; for (int j = 0; j < charlist_extended.size(); j++) if (charlist_extended[j].charcode == FLanguage[k][i]) { found = true; break; } if (found == false) { GlyphsPos newglyph; newglyph.charcode = FLanguage[k][i]; newglyph.listpos = glGenLists(1); glGenTextures(1, &newglyph.texture); make_dlist(face, FLanguage[k][i], newglyph.listpos, newglyph.texture); charlist_extended.push_back(newglyph); } } } } void font_data::init(const char * fname, unsigned int h) { //Allocate some memory to store the texture ids. textures = new GLuint[128]; this->h=h; //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 die if the font file does not exist or is somehow broken. if (FT_New_Face( library, fname, 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 writting h*64) FT_Set_Char_Size(face, h << 6, h << 6, 96, 96); //Here we ask opengl to allocate resources for //all the textures and displays lists which we //are about to create. list_base=glGenLists(128); glGenTextures(128, textures); charwidth.resize(0); //This is where we actually create each of the fonts display lists. for(int i=0;i<128;i++) make_dlist(face, i, list_base + i, textures[i]); CreateExtendedCharset(face); //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 library. FT_Done_FreeType(library); } void font_data::clean() { glDeleteLists(list_base,128); glDeleteTextures(128,textures); for (int j = 0; j < charlist_extended.size(); j++) { glDeleteLists(charlist_extended[j].listpos, 1); glDeleteTextures(1, &charlist_extended[j].texture); } delete [] textures; } /// A fairly straight forward function that pushes /// a projection matrix that will make object world /// coordinates identical to window coordinates. inline void 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(); } /// Pops the projection matrix without changing the current /// MatrixMode. inline void pop_projection_matrix() { glPushAttrib(GL_TRANSFORM_BIT); glMatrixMode(GL_PROJECTION); glPopMatrix(); glPopAttrib(); } }