Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members  

ttf.cpp

00001 //FILE:         ttf.cpp
00002 //AUTHOR:       Nathan Cournia <nathan@cournia.com>
00003 
00004 #include "image.h"
00005 #include "utils.h"
00006 #include "ttf.h"
00007 
00009 unsigned int gl::ttf::s_library_refs = 0;
00010 FT_Library gl::ttf::s_library = NULL;
00011 
00013 gl::ttf::ttf( void ): m_face( NULL )
00014 { 
00015         //increase ref to freetype library
00016         ++s_library_refs;
00017 }
00018 
00020 gl::ttf::ttf( const gl::ttf& cpy ):
00021         m_texture( cpy.m_texture ),
00022         m_name( cpy.m_name )
00023 { }
00024 
00026 gl::ttf::~ttf( void )
00027 { 
00028         //delete glyph hash data
00029         glyph_hash::iterator i = m_glyphs.begin( );
00030         while( i != m_glyphs.end( ) ) {
00031                 delete i->second;
00032                 m_glyphs.erase( i );
00033                 i = m_glyphs.begin( );
00034         }
00035 
00036         //we no longer need freetype library, decrease ref count
00037         --s_library_refs;
00038 
00039         //delete freetype face info
00040         FT_Done_Face( m_face );
00041         
00042         //check if we should should shutdown freetype
00043         if( s_library_refs < 1 ) {
00044                 FT_Done_FreeType( s_library );
00045         }
00046 }
00047 
00048 
00049 
00051 void
00052 gl::ttf::render_string( real_t &x, real_t &y, real_t size, 
00053         const std::string& text ) const
00054 {
00055         //bind the texture
00056         m_texture.bind( );
00057         
00058         //for each character in the string
00059         const glyph *ch;
00060         glyph_hash::const_iterator gi;
00061         for( unsigned int i = 0; i < text.length( ); ++i ) {
00062                 //is the glyph a space
00063                 if( text[ i ] == ' ' ) {
00064                         x += size / 2.0;
00065                 }
00066                 
00067                 //get the glyph
00068                 gi = m_glyphs.find( text[ i ] );
00069                 if( gi == m_glyphs.end( ) ) {
00070                         //unknown glyph
00071                         continue;
00072                 }
00073                 ch = gi->second;
00074 
00075                 /*
00076                 std::cerr << text[ i ] << ": bottom left: " << ch->bx << " " << ch->by
00077                         << " top right: " << ch->tx << " " << ch->ty
00078                         << " aspect: " << ch->aspect << std::endl;
00079                 */
00080                 
00081                 //render the glyph as a triangle strip
00082                 glBegin( GL_TRIANGLE_STRIP );
00083                         //upper left
00084                         glTexCoord2f( ch->bx, ch->ty );
00085                         glVertex2f( x, y + size );
00086                         
00087                         //lower left
00088                         glTexCoord2f( ch->bx, ch->by );
00089                         glVertex2f( x, y );
00090         
00091                         
00092                         //upper right
00093                         x += ch->aspect * size;
00094                         glTexCoord2f( ch->tx, ch->ty );
00095                         glVertex2f( x, y + size );
00096         
00097                         //lower right
00098                         glTexCoord2f( ch->tx, ch->by );
00099                         glVertex2f( x, y );
00100                 glEnd( );
00101         }
00102 
00103         //update y
00104         y = y + size;
00105 }
00106 
00108 gl::ttf*
00109 gl::ttf::load( const std::string& filename, unsigned int size )
00110 {
00111         //for all errors
00112         FT_Error error;
00113 
00114         //do we need to init free type
00115         if( s_library_refs < 1 ) {
00116                 //init freetype
00117                 error =  FT_Init_FreeType( &s_library );
00118                 if( error ) return NULL;
00119         }
00120 
00121         //open font
00122         FT_Face face;
00123         error = FT_New_Face( s_library, filename.c_str( ), 0, &face );
00124         if( error ) {
00125                 return NULL;
00126         }
00127 
00128         //make sure the font is scalable
00129         if( !FT_IS_SCALABLE( face ) ) {
00130                 FT_Done_Face( face );
00131                 return NULL;
00132         }
00133 
00134         //set character size
00135         error = FT_Set_Pixel_Sizes( face, 0, size );
00136         if( error ) {
00137                 FT_Done_Face( face );
00138                 return NULL;
00139         }
00140 
00141         //kerning info
00142         //FT_Bool kerning = FT_HAS_KERNING( face );
00143         
00144         //create ttf object
00145         ttf *font = new ttf;
00146 
00147         //set freetype face data
00148         font->m_face = face;
00149 
00150         //set font name
00151         font->m_name = filename;
00152 
00153         //set font size
00154         //font->m_size = size;
00155 
00156         //set baseline
00157         //font->m_baseline = -((GLfloat)face->descender) / 
00158         //      ((GLfloat)face->height) * size;
00159         //std::cerr << "baseline: " << font->m_baseline << std::endl;
00160 
00161         //get glyph info from freetype
00162         FT_GlyphSlot slot = face->glyph;
00163         FT_UInt glyph_index;
00164 
00165         //ready pen position
00166         recti pen;
00167         pen.set_xy( 0, 0 );
00168 
00169         //create an image
00170         image::image_t img( 512, 512, image::image_t::RGBA, image::image_t::BYTE );
00171         memset( (void*)img.get_pixels( ), 0, 512 * 512 * 4 ); //aiieeee! evil
00172 
00173         //character to cache
00174         static std::string text = "()ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890!@#$%^&*_+-={}|[]\\:;\"'<,>.?/~`";
00175         
00176         int above_max = -100;
00177         int below_max = -100;
00178 
00179         for( unsigned int i = 0; i < text.length( ); ++i ) {
00180                 char c = text[ i ];
00181                 glyph_index = FT_Get_Char_Index( face, c );
00182 
00183                 //convert the glyph to a bitmap
00184                 error = FT_Load_Glyph( face, glyph_index, FT_LOAD_RENDER );
00185                 if( error ) {
00186                         continue;
00187                 }
00188 
00189                 if( slot->bitmap_top > above_max ) {
00190                         above_max = slot->bitmap_top;
00191                 }
00192 
00193                 if( (slot->bitmap.rows - slot->bitmap_top) > below_max ) {
00194                         below_max = slot->bitmap.rows - slot->bitmap_top;
00195                 }
00196         }
00197 
00198         int line_height = above_max + below_max; //how many pixels (height) a line of text is
00199         int line = line_height + 2; //current draw position (y) in pixels
00200         int width, top;
00201         glyph *pglyph;
00202 
00203         for( unsigned int i = 0; i < text.length( ); ++i ) {
00204                 char c = text[ i ];
00205                 glyph_index = FT_Get_Char_Index( face, c );
00206 
00207                 //convert the glyph to a bitmap
00208                 error = FT_Load_Glyph( face, glyph_index, FT_LOAD_RENDER );
00209                 if( error ) {
00210                         std::cerr << "error: '" << filename << "': could not render glyph: '" << c << "'" << std::endl;
00211                         continue;
00212                 }
00213                 
00214                 if( (slot->bitmap.width < 1) || (slot->bitmap.rows < 1) ) {
00215                         std::cerr << "error: '" << filename << "': could not render glyph: '" << c << "'" << std::endl;
00216                         continue;
00217                 }
00218 
00219                 //create new glyph
00220                 pglyph = new glyph;
00221 
00222                 //create a tempory image to store the glyph for blitting
00223                 image::image_t tmp( slot->bitmap.width, slot->bitmap.rows,
00224                         image::image_t::RGBA, image::image_t::BYTE );
00225 
00226                 //copy the glyph bitmap to the new image
00227                 tmp.seek( 0, 0 ); //set draw position
00228 
00229                 //for each row in source image
00230                 for( unsigned int j = 0; j < slot->bitmap.rows; ++j ) {
00231                         //move current position to the proper row, account for padding (pitch)
00232                         unsigned char *p = slot->bitmap.buffer + ( slot->bitmap.pitch * j );
00233 
00234                         //for each column in row
00235                         for( unsigned int k = 0; k < slot->bitmap.width; ++k ) {
00236                                 //write white pixel with alpha value
00237                                 //tmp.write( 255, 0, 0, 255 - *(p++) );
00238                                 tmp.write( 255, 255, 255, *(p++) );
00239                         }
00240                 }
00241 
00242                 //will the glyph not fit on this line
00243                 //width = slot->bitmap_left + (slot->advance.x >> 6);
00244                 //std::cerr << "left: " << slot->bitmap_left << std::endl;
00245                 if( slot->bitmap_left > 0 ) {
00246                         width = slot->bitmap_left + slot->bitmap_left + slot->bitmap.width;
00247                 } else {
00248                         width = slot->bitmap.width;
00249                 }
00250 
00251                 if( pen.x + width >= 512 ) {
00252                         //the glyph wont fit on line, move to next line
00253                         line += line_height + 1;
00254                         pen.x = 0;
00255                 }
00256 
00257                 //compute top drawing position
00258                 //std::cerr << "top: " << slot->bitmap_top << " rows: " << slot->bitmap.rows << std::endl;
00259                 //top = line - slot->bitmap_top;
00260 
00261                 /*
00262                 if( slot->bitmap_top > above_max ) {
00263                         above_max = slot->bitmap_top;
00264                 }
00265 
00266                 if( (slot->bitmap.rows - slot->bitmap_top) > below_max ) {
00267                         below_max = slot->bitmap.rows - slot->bitmap_top;
00268                 }
00269                 */
00270 
00271                 //set glyph width
00272                 //pglyph->width = width;
00273 
00274                 //std::cerr << "under hang: " << c << ": " << slot->bitmap.rows - slot->bitmap_top << std::endl;
00275 
00276                 //set glyph uv info
00277                 /*
00278                 pglyph->bx = ((GLfloat)(pen.x)) / 512.0;
00279                 pglyph->by = 1.0 - (((GLfloat)(top + slot->bitmap.rows)) / 512.0);
00280                 pglyph->tx = ((GLfloat)(pen.x + width)) / 512.0;
00281                 pglyph->ty = 1.0 - (((GLfloat)(top)) / 512.0);
00282                 pglyph->aspect = ((GLfloat)(width)) / ((GLfloat)(slot->bitmap.rows));
00283                 */
00284 
00285                 pglyph->bx = pen.x;
00286                 pglyph->by = line;
00287 
00288                 //std::cerr << c << ": bx: " << pglyph->bx << std::endl;
00289 
00290                 //setting blitting position
00291                 if( slot->bitmap_left > 0 ) {
00292                         pen.x += slot->bitmap_left;
00293                 }
00294                 pen.y = line - slot->bitmap_top;
00295 
00296                 //blit the glyph onto the master image
00297                 img.blit( tmp, pen );
00298 
00299                 //move to the pen in the x dir to next draw position
00300                 pen.x += (slot->advance.x >> 6) + 2;
00301                 //pen.x += slot->bitmap_left + slot->bitmap.width;
00302 
00303                 //set the glyph info internally
00304                 font->m_glyphs[ c ] = pglyph;
00305 
00306                 pglyph->tx = pen.x;
00307                 
00308                 //std::cerr << c << ": width: " << slot->bitmap.width << " pitch: " << slot->bitmap.pitch << " height: " << slot->bitmap.rows << std::endl;
00309         }
00310 
00311         //compute uv coords
00312         glyph_hash::iterator i = font->m_glyphs.begin( );
00313         float w, h, max;
00314         //float max = above_max + below_max;
00315         if( max < 0.0 ) max = 1.0;
00316         while( i != font->m_glyphs.end( ) ) {
00317                 pglyph = i->second;
00318 
00319                 //get width
00320                 w = pglyph->tx - pglyph->bx;
00321                 
00322                 //std::cerr << i->first << ": bx2: " << pglyph->bx << std::endl;
00323                 //compute u
00324                 pglyph->bx /= 512.0;
00325                 pglyph->tx /= 512.0;
00326 
00327                 //compute v
00328                 pglyph->ty = pglyph->by - static_cast<GLfloat>( above_max );
00329                 pglyph->by = pglyph->by + static_cast<GLfloat>( below_max );
00330                 h = pglyph->by - pglyph->ty;
00331                 pglyph->ty = 1.0 - (pglyph->ty / 512.0);
00332                 pglyph->by = 1.0 - (pglyph->by / 512.0);
00333 
00334                 //aspect
00335                 pglyph->aspect = w / h;
00336 
00337                 //next glyph
00338                 ++i;
00339         }
00340 
00341         //std::cerr << "line: " << size << " actual: " << above_max + below_max << std::endl;
00342 
00343         //set baseline
00344         if( below_max > 0.0 ) {
00345                 font->m_baseline = (above_max + below_max) / below_max;
00346         } else {
00347                 font->m_baseline = below_max;
00348         }
00349 
00350         //flip the image for opengl
00351         img.flip_horizontal( );
00352 
00353         //load the image with all glyphs on it into opengl
00354         font->m_texture = gl::texture::load( &img, false, GL_LINEAR, GL_LINEAR );
00355         if( !font->m_texture ) {
00356                 //something went wrong when sending the image to opengl
00357                 //deleting font will ensure proper destruction of font data
00358                 delete font;
00359         }
00360 
00361         /*
00362         i = font->m_glyphs.begin( );
00363         //glyph_hash::iterator i = font->m_glyphs.begin( );
00364         while( i != font->m_glyphs.end( ) ) {
00365                 pglyph = i->second;
00366                 std::cerr << i->first << ": bottom left: " << pglyph->bx << " " << pglyph->by
00367                         << " top right: " << pglyph->tx << " " << pglyph->ty
00368                         << " aspect: " << pglyph->aspect << std::endl;
00369                 ++i;
00370         }
00371         */
00372         
00373         //return the loaded font
00374         return font;
00375 }
00376                 
00377 
00378         
00379         
00380         
00381 

Generated on Tue Feb 11 18:49:42 2003 for uber by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002