00001
00002
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
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
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
00037 --s_library_refs;
00038
00039
00040 FT_Done_Face( m_face );
00041
00042
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
00056 m_texture.bind( );
00057
00058
00059 const glyph *ch;
00060 glyph_hash::const_iterator gi;
00061 for( unsigned int i = 0; i < text.length( ); ++i ) {
00062
00063 if( text[ i ] == ' ' ) {
00064 x += size / 2.0;
00065 }
00066
00067
00068 gi = m_glyphs.find( text[ i ] );
00069 if( gi == m_glyphs.end( ) ) {
00070
00071 continue;
00072 }
00073 ch = gi->second;
00074
00075
00076
00077
00078
00079
00080
00081
00082 glBegin( GL_TRIANGLE_STRIP );
00083
00084 glTexCoord2f( ch->bx, ch->ty );
00085 glVertex2f( x, y + size );
00086
00087
00088 glTexCoord2f( ch->bx, ch->by );
00089 glVertex2f( x, y );
00090
00091
00092
00093 x += ch->aspect * size;
00094 glTexCoord2f( ch->tx, ch->ty );
00095 glVertex2f( x, y + size );
00096
00097
00098 glTexCoord2f( ch->tx, ch->by );
00099 glVertex2f( x, y );
00100 glEnd( );
00101 }
00102
00103
00104 y = y + size;
00105 }
00106
00108 gl::ttf*
00109 gl::ttf::load( const std::string& filename, unsigned int size )
00110 {
00111
00112 FT_Error error;
00113
00114
00115 if( s_library_refs < 1 ) {
00116
00117 error = FT_Init_FreeType( &s_library );
00118 if( error ) return NULL;
00119 }
00120
00121
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
00129 if( !FT_IS_SCALABLE( face ) ) {
00130 FT_Done_Face( face );
00131 return NULL;
00132 }
00133
00134
00135 error = FT_Set_Pixel_Sizes( face, 0, size );
00136 if( error ) {
00137 FT_Done_Face( face );
00138 return NULL;
00139 }
00140
00141
00142
00143
00144
00145 ttf *font = new ttf;
00146
00147
00148 font->m_face = face;
00149
00150
00151 font->m_name = filename;
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162 FT_GlyphSlot slot = face->glyph;
00163 FT_UInt glyph_index;
00164
00165
00166 recti pen;
00167 pen.set_xy( 0, 0 );
00168
00169
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 );
00172
00173
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
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;
00199 int line = line_height + 2;
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
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
00220 pglyph = new glyph;
00221
00222
00223 image::image_t tmp( slot->bitmap.width, slot->bitmap.rows,
00224 image::image_t::RGBA, image::image_t::BYTE );
00225
00226
00227 tmp.seek( 0, 0 );
00228
00229
00230 for( unsigned int j = 0; j < slot->bitmap.rows; ++j ) {
00231
00232 unsigned char *p = slot->bitmap.buffer + ( slot->bitmap.pitch * j );
00233
00234
00235 for( unsigned int k = 0; k < slot->bitmap.width; ++k ) {
00236
00237
00238 tmp.write( 255, 255, 255, *(p++) );
00239 }
00240 }
00241
00242
00243
00244
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
00253 line += line_height + 1;
00254 pen.x = 0;
00255 }
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285 pglyph->bx = pen.x;
00286 pglyph->by = line;
00287
00288
00289
00290
00291 if( slot->bitmap_left > 0 ) {
00292 pen.x += slot->bitmap_left;
00293 }
00294 pen.y = line - slot->bitmap_top;
00295
00296
00297 img.blit( tmp, pen );
00298
00299
00300 pen.x += (slot->advance.x >> 6) + 2;
00301
00302
00303
00304 font->m_glyphs[ c ] = pglyph;
00305
00306 pglyph->tx = pen.x;
00307
00308
00309 }
00310
00311
00312 glyph_hash::iterator i = font->m_glyphs.begin( );
00313 float w, h, max;
00314
00315 if( max < 0.0 ) max = 1.0;
00316 while( i != font->m_glyphs.end( ) ) {
00317 pglyph = i->second;
00318
00319
00320 w = pglyph->tx - pglyph->bx;
00321
00322
00323
00324 pglyph->bx /= 512.0;
00325 pglyph->tx /= 512.0;
00326
00327
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
00335 pglyph->aspect = w / h;
00336
00337
00338 ++i;
00339 }
00340
00341
00342
00343
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
00351 img.flip_horizontal( );
00352
00353
00354 font->m_texture = gl::texture::load( &img, false, GL_LINEAR, GL_LINEAR );
00355 if( !font->m_texture ) {
00356
00357
00358 delete font;
00359 }
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374 return font;
00375 }
00376
00377
00378
00379
00380
00381