00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include <vlGraphics/Font.hpp>
00033 #include <vlGraphics/OpenGL.hpp>
00034 #include <vlGraphics/FontManager.hpp>
00035 #include <vlCore/Log.hpp>
00036 #include <vlCore/Say.hpp>
00037 #include <vlCore/FileSystem.hpp>
00038 #include <vlCore/Image.hpp>
00039
00040 #include <ft2build.h>
00041 #include FT_FREETYPE_H
00042
00043 using namespace vl;
00044
00045
00046
00047 #undef __FTERRORS_H__
00048 #define FT_ERRORDEF( e, v, s ) { e, s },
00049 #define FT_ERROR_START_LIST {
00050 #define FT_ERROR_END_LIST { 0, 0 } };
00051
00052 const struct
00053 {
00054 int err_code;
00055 const char* err_msg;
00056 } ft_errors[] =
00057
00058 #include FT_ERRORS_H
00059
00060
00061 const char* get_ft_error_message(int error)
00062 {
00063 int i=0;
00064 while( ft_errors[i].err_msg && ft_errors[i].err_code != error )
00065 ++i;
00066 return ft_errors[i].err_msg;
00067 }
00068
00069
00070
00071
00072 Glyph::~Glyph()
00073 {
00074 if (mTextureHandle)
00075 {
00076 glDeleteTextures(1, &mTextureHandle);
00077 mTextureHandle = 0;
00078 }
00079 }
00080
00081
00082
00083 Font::Font(FontManager* fm)
00084 {
00085 VL_DEBUG_SET_OBJECT_NAME()
00086 mFontManager = fm;
00087 mHeight = 0;
00088 mFT_Face = NULL;
00089 mSmooth = false;
00090 mFreeTypeLoadForceAutoHint = true;
00091 setSize(14);
00092 }
00093
00094 Font::Font(FontManager* fm, const String& font_file, int size)
00095 {
00096 VL_DEBUG_SET_OBJECT_NAME()
00097 mFontManager = fm;
00098 mHeight = 0;
00099 mFT_Face = NULL;
00100 mSmooth = false;
00101 mFreeTypeLoadForceAutoHint = true;
00102 loadFont(font_file);
00103 setSize(size);
00104 }
00105
00106 Font::~Font()
00107 {
00108 releaseFreeTypeData();
00109 }
00110
00111 void Font::releaseFreeTypeData()
00112 {
00113 if (mFT_Face)
00114 {
00115 if (!mFontManager->freeTypeLibrary())
00116 {
00117 vl::Log::error("Font::releaseFreeTypeData(): mFontManager->freeTypeLibrary() is NULL!\n");
00118 VL_TRAP()
00119 }
00120 else
00121 {
00122 FT_Done_Face(mFT_Face);
00123 }
00124 mFT_Face = NULL;
00125 }
00126 }
00127
00128 void Font::setSize(int size)
00129 {
00130 if(mSize != size)
00131 {
00132 mSize = size;
00133
00134 mGlyphMap.clear();
00135 }
00136 }
00137
00138 void Font::loadFont(const String& path)
00139 {
00140 if(path == mFilePath)
00141 return;
00142
00143 mFilePath = path;
00144
00145 mGlyphMap.clear();
00146
00147
00148 if (mFT_Face)
00149 {
00150 FT_Done_Face(mFT_Face);
00151 mFT_Face = NULL;
00152 }
00153
00154 FT_Error error = 0;
00155
00156 ref<VirtualFile> font_file = defFileSystem()->locateFile( filePath() );
00157
00158 if (!font_file)
00159 Log::error( Say("Font::loadFont('%s'): font file not found.\n") << filePath() );
00160
00161 if ( font_file && font_file->load(mMemoryFile) )
00162 {
00163 if ( (int)mMemoryFile.size() == font_file->size() )
00164 {
00165 error = FT_New_Memory_Face( (FT_Library)mFontManager->freeTypeLibrary(),
00166 (FT_Byte*)&mMemoryFile[0],
00167 (int)mMemoryFile.size(),
00168 0,
00169 &mFT_Face );
00170 }
00171 else
00172 Log::error( Say("Font::loadFont('%s'): could not read file.\n") << filePath() );
00173 }
00174
00175 if (error)
00176 {
00177 Log::error(Say("FT_New_Face error (%s): %s\n") << filePath() << get_ft_error_message(error) );
00178 VL_TRAP()
00179 return;
00180 }
00181 }
00182
00183 Glyph* Font::glyph(int character)
00184 {
00185 ref<Glyph>& glyph = mGlyphMap[character];
00186
00187 if (glyph.get() == NULL)
00188 {
00189 glyph = new Glyph;
00190 glyph->setFont(this);
00191
00192
00193
00194 FT_Error error = 0;
00195
00196 error = FT_Set_Char_Size(
00197 mFT_Face,
00198 0,
00199 mSize*64,
00200 96,
00201 96 );
00202
00203 if(error)
00204 {
00205
00206 if ( (mFT_Face->face_flags & FT_FACE_FLAG_SCALABLE) == 0 && mFT_Face->num_fixed_sizes)
00207 {
00208
00209
00210 int best_match_index = -1;
00211 int best_match_size = 0;
00212 for( int i=0; i < mFT_Face->num_fixed_sizes; ++i )
00213 {
00214 int size = mFT_Face->available_sizes[i].y_ppem/64;
00215
00216 if (size <= mSize)
00217 {
00218 if (best_match_index == -1 || (mSize - size) < (mSize - best_match_size) )
00219 {
00220 best_match_index = i;
00221 best_match_size = size;
00222 }
00223 }
00224 }
00225
00226 if (best_match_index == -1)
00227 best_match_index = 0;
00228
00229 error = FT_Select_Size(mFT_Face, best_match_index);
00230 if (error)
00231 Log::error(Say("FT_Select_Size error (%s): %s\n") << filePath() << get_ft_error_message(error) );
00232 VL_CHECK(!error)
00233 }
00234
00235 {
00236 Log::error(Say("FT_Set_Char_Size error (%s): %s\n") << filePath() << get_ft_error_message(error) );
00237 VL_TRAP()
00238 return glyph.get();
00239 }
00240 }
00241
00242 mHeight = mFT_Face->size->metrics.height / 64.0f;
00243
00244
00245
00246
00247
00248
00249
00250
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267 error = FT_Load_Char( mFT_Face, character, freeTypeLoadForceAutoHint() ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT );
00268
00269 if(error)
00270 {
00271 Log::error(Say("FT_Load_Char error (%s): %s\n") << filePath() << get_ft_error_message(error) );
00272 VL_TRAP()
00273 glyph = NULL;
00274 return glyph.get();
00275 }
00276
00277 glyph->setGlyphIndex( FT_Get_Char_Index( mFT_Face, character ) );
00278
00279 error = FT_Render_Glyph(
00280 mFT_Face->glyph,
00281 FT_RENDER_MODE_NORMAL );
00282
00283
00284
00285
00286 if(error)
00287 {
00288
00289
00290 error = FT_Load_Glyph(
00291 mFT_Face,
00292 0,
00293 FT_LOAD_DEFAULT );
00294 glyph->setGlyphIndex(0);
00295
00296 error = FT_Render_Glyph(
00297 mFT_Face->glyph,
00298 FT_RENDER_MODE_NORMAL );
00299 }
00300
00301 if(error)
00302 {
00303 Log::error(Say("FT_Render_Glyph error (%s): %s\n") << filePath() << get_ft_error_message(error) );
00304 VL_TRAP()
00305 glyph = NULL;
00306 return glyph.get();
00307 }
00308
00309 bool ok_format = mFT_Face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY || mFT_Face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO;
00310 ok_format &= mFT_Face->glyph->bitmap.palette_mode == 0;
00311 ok_format &= mFT_Face->glyph->bitmap.pitch > 0 || mFT_Face->glyph->bitmap.buffer == NULL;
00312
00313 if (!ok_format)
00314 {
00315 Log::error( Say("Font::glyph() error (%s): glyph format not supported. Visualization Library currently supports only FT_PIXEL_MODE_GRAY and FT_PIXEL_MODE_MONO.\n") << filePath() );
00316 VL_TRAP()
00317 return glyph.get();
00318 }
00319
00320 if ( mFT_Face->glyph->bitmap.buffer )
00321 {
00322 if (mHeight == 0)
00323 mHeight = (float)mFT_Face->glyph->bitmap.rows;
00324
00325 glyph->setWidth ( mFT_Face->glyph->bitmap.width);
00326 glyph->setHeight( mFT_Face->glyph->bitmap.rows);
00327 glyph->setLeft ( mFT_Face->glyph->bitmap_left);
00328 glyph->setTop ( mFT_Face->glyph->bitmap_top);
00329
00330 VL_CHECK( mFT_Face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY || mFT_Face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO )
00331 VL_CHECK( mFT_Face->glyph->bitmap.palette_mode == 0 )
00332 VL_CHECK( mFT_Face->glyph->bitmap.pitch > 0 )
00333
00334 unsigned int texhdl;
00335 glGenTextures( 1, &texhdl );
00336 glyph->setTextureHandle(texhdl);
00337 VL_glActiveTexture(GL_TEXTURE0);
00338 glBindTexture( GL_TEXTURE_2D, glyph->textureHandle() );
00339
00340 int texsize[] = { 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 0 };
00341 int max_tex_size = 0;
00342 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size);
00343
00344 int w=0, h=0, margin = 1;
00345
00346 for(int i=0; texsize[i]; ++i)
00347 {
00348 if ( (texsize[i] >= glyph->width() + margin*2 && texsize[i] >= glyph->height() + margin*2) || texsize[i+1] > max_tex_size )
00349 {
00350 w = texsize[i];
00351 h = texsize[i];
00352 break;
00353 }
00354 }
00355 VL_CHECK(w)
00356 VL_CHECK(h)
00357
00358 #if(1)
00359
00360 glyph->setS0( 0 );
00361 glyph->setT0( 1 );
00362 glyph->setS1((margin*2 + glyph->width() ) /(float)(w-1) );
00363 glyph->setT1( 1 -(margin*2 + glyph->height() ) /(float)(h-1) );
00364
00365
00366
00367
00368
00369
00370 #else
00371 glyph->setS0((float)margin /(float)w);
00372 glyph->setT0( 1 -(float)margin /(float)h);
00373 glyph->setS1(((float)margin + glyph->width() ) /(float)w);
00374 glyph->setT1( 1 -((float)margin + glyph->height() ) /(float)h);
00375 #endif
00376
00377 ref<Image> img = new Image;
00378 img->allocate2D(w, h, 1, IF_RGBA, IT_UNSIGNED_BYTE);
00379
00380
00381 for(unsigned char *px = img->pixels(), *end = px + img->requiredMemory(); px<end; px+=4)
00382 {
00383 px[0] = 0xFF;
00384 px[1] = 0xFF;
00385 px[2] = 0xFF;
00386 px[3] = 0x0;
00387 }
00388
00389
00390
00391 for(int y=0; y<glyph->height(); y++)
00392 {
00393 for(int x=0; x<glyph->width(); x++)
00394 {
00395 int offset_1 = (x+margin) * 4 + (w-1-y-margin) * img->pitch();
00396 int offset_2 = 0;
00397 if (mFT_Face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO)
00398 offset_2 = x / 8 + y * ::abs(mFT_Face->glyph->bitmap.pitch);
00399 else
00400 offset_2 = x + y * mFT_Face->glyph->bitmap.pitch;
00401
00402 #if (1)
00403 if (mFT_Face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO)
00404 img->pixels()[ offset_1+3 ] = (mFT_Face->glyph->bitmap.buffer[ offset_2 ] >> (7-x%8)) & 0x1 ? 0xFF : 0x0;
00405 else
00406 img->pixels()[ offset_1+3 ] = mFT_Face->glyph->bitmap.buffer[ offset_2 ];
00407 #else
00408
00409 img->pixels()[ offset_1+0 ] = face->glyph->bitmap.buffer[ offset_2 ];
00410 img->pixels()[ offset_1+1 ] = face->glyph->bitmap.buffer[ offset_2 ];
00411 img->pixels()[ offset_1+2 ] = face->glyph->bitmap.buffer[ offset_2 ];
00412 img->pixels()[ offset_1+3 ] = 0xFF;
00413 #endif
00414 }
00415 }
00416
00417 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img->width(), img->height(), 0, img->format(), img->type(), img->pixels() ); VL_CHECK_OGL();
00418
00419 if ( smooth() )
00420 {
00421 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
00422 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
00423 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
00424 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
00425 }
00426 else
00427 {
00428 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
00429 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
00430 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
00431 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
00432 }
00433
00434
00435 if (Has_GL_EXT_texture_filter_anisotropic)
00436 {
00437 float max_anisotropy;
00438 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropy);
00439 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy);
00440 }
00441
00442 VL_CHECK_OGL();
00443 glBindTexture( GL_TEXTURE_2D, 0 );
00444 }
00445
00446 glyph->setAdvance( fvec2( (float)mFT_Face->glyph->advance.x / 64.0f, (float)mFT_Face->glyph->advance.y / 64.0f ) );
00447 }
00448
00449 return glyph.get();
00450 }
00451
00452 void Font::setSmooth(bool smooth)
00453 {
00454 mSmooth = smooth;
00455 std::map<int, ref<Glyph> >::iterator it = mGlyphMap.begin();
00456 for(; it != mGlyphMap.end(); ++it )
00457 {
00458 const ref<Glyph>& glyph = it->second;
00459 if (glyph->textureHandle() == 0)
00460 continue;
00461
00462 glBindTexture( GL_TEXTURE_2D, glyph->textureHandle() );
00463 if (smooth)
00464 {
00465 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
00466 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
00467 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
00468 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
00469 }
00470 else
00471 {
00472 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
00473 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
00474 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
00475 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
00476 }
00477 }
00478 glBindTexture( GL_TEXTURE_2D, 0 );
00479 }
00480