# Visualization Library

A lightweight C++ OpenGL middleware for 2D/3D graphics

[Home] [Tutorials] [All Classes] [Grouped Classes]

- Main Page
- Related Pages
- Namespaces
- Classes
- Files

- File List
- File Members

# D:/VL/BuildSystem/VL_DISTRO/Visualization_Library_SDK/src/vlGraphics/Font.cpp

Go to the documentation of this file.

    00001 /**************************************************************************************/
    00002 /*                                                                                    */
    00003 /*  Visualization Library                                                             */
    00004 /*  http://www.visualizationlibrary.org                                               */
    00005 /*                                                                                    */
    00006 /*  Copyright (c) 2005-2010, Michele Bosi                                             */
    00007 /*  All rights reserved.                                                              */
    00008 /*                                                                                    */
    00009 /*  Redistribution and use in source and binary forms, with or without modification,  */
    00010 /*  are permitted provided that the following conditions are met:                     */
    00011 /*                                                                                    */
    00012 /*  - Redistributions of source code must retain the above copyright notice, this     */
    00013 /*  list of conditions and the following disclaimer.                                  */
    00014 /*                                                                                    */
    00015 /*  - Redistributions in binary form must reproduce the above copyright notice, this  */
    00016 /*  list of conditions and the following disclaimer in the documentation and/or       */
    00017 /*  other materials provided with the distribution.                                   */
    00018 /*                                                                                    */
    00019 /*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND   */
    00020 /*  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED     */
    00021 /*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE            */
    00022 /*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR  */
    00023 /*  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    */
    00024 /*  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;      */
    00025 /*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON    */
    00026 /*  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT           */
    00027 /*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS     */
    00028 /*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                      */
    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 // FreeType error table construction start ------------------------------------------
    00046 // taken from "fterrors.h" example
    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 // FreeType error table construction end ------------------------------------------
    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 // Glyph
    00071 //-----------------------------------------------------------------------------
    00072 Glyph::~Glyph()
    00073 {
    00074   if (mTextureHandle)
    00075   {
    00076     glDeleteTextures(1, &mTextureHandle);
    00077     mTextureHandle = 0;
    00078   }
    00079 }
    00080 //-----------------------------------------------------------------------------
    00081 // Font
    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     // removes all the cached glyphs
    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   // removes all the cached glyphs
    00145   mGlyphMap.clear();
    00146
    00147   // remove FreeType font face object
    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     // create the glyph
    00193
    00194     FT_Error error = 0;
    00195
    00196     error = FT_Set_Char_Size(
    00197               mFT_Face, /* handle to face object           */
    00198               0,        /* char_width in 1/64th of points  */
    00199               mSize*64, /* char_height in 1/64th of points */
    00200               96,       /* horizontal device resolution    */
    00201               96 );     /* vertical device resolution      */
    00202
    00203     if(error)
    00204     {
    00205       // Log::error(Say("FT_Set_Char_Size error: %s\n") << get_ft_error_message(error) );
    00206       if ( (mFT_Face->face_flags & FT_FACE_FLAG_SCALABLE) == 0 && mFT_Face->num_fixed_sizes)
    00207       {
    00208         // look for the size which is less or equal to the given size
    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           // skip bigger characters
    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       // else
    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     // using FT_Load_Char instead of FT_Get_Char_Index + FT_Load_Glyph works better, probably
    00245     // FreeType performs some extra tricks internally to better support less reliable fonts...
    00246
    00247     // FT_UInt glyph_index = FT_Load_Char( mFT_Face, character, FT_LOAD_DEFAULT );
    00248     // glyph->glyphIndex() = glyph_index;
    00249     //FT_UInt glyph_index = FT_Get_Char_Index( mFT_Face, character );
    00250     //glyph->glyphIndex() = glyph_index;
    00252     //FT_Int32 load_flags = FT_LOAD_DEFAULT;
    00253     //error = FT_Load_Glyph(
    00254     //          mFT_Face,         /* handle to face object */
    00255     //          glyph_index,  /* glyph index           */
    00256     //          load_flags ); /* load flags, see below */
    00257     //if(error)
    00258     //{
    00259     //  Log::error(Say("FT_Load_Glyph error: %s") << get_ft_error_message(error) );
    00260     //  VL_TRAP()
    00261     //  return glyph;
    00262     //}
    00263
    00264     // Note with FT 2.3.9 FT_LOAD_DEFAULT worked well, with FT 2.4 instead we ned FT_LOAD_FORCE_AUTOHINT
    00265     // This might work well with VL's font but it might be suboptimal for other fonts.
    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,  /* glyph slot */
    00281               FT_RENDER_MODE_NORMAL ); /* render mode: FT_RENDER_MODE_MONO or FT_RENDER_MODE_NORMAL */
    00282
    00283     // fonts like webdings.ttf generate an error when an unsupported char code is requested instead of
    00284     // reverting to char code 0, so we have to do it by hand...
    00285
    00286     if(error)
    00287     {
    00288       // Log::error(Say("FT_Render_Glyph error: %s") << get_ft_error_message(error) );
    00289       // VL_TRAP()
    00290       error = FT_Load_Glyph(
    00291                 mFT_Face,/* handle to face object */
    00292                 0,       /* glyph index           */
    00293                 FT_LOAD_DEFAULT ); /* load flags, see below */
    00294       glyph->setGlyphIndex(0);
    00295
    00296       error = FT_Render_Glyph(
    00297                 mFT_Face->glyph,  /* glyph slot */
    00298                 FT_RENDER_MODE_NORMAL ); /* render mode: FT_RENDER_MODE_MONO or 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       // tex coords DO include the border
    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       // tex coords DO NOT include the border
    00366       //glyph->setS0((float)margin /(float)(w-1));
    00367       //glyph->setT0( 1 -(float)margin /(float)(h-1));
    00368       //glyph->setS1(((float)margin + glyph->width() ) /(float)(w-1));
    00369       //glyph->setT1( 1 -((float)margin + glyph->height() ) /(float)(h-1));
    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       // init to all transparent white
    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       // maps the glyph on the texture leaving a 1px margin
    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           // debug code
    00409           img->pixels()[ offset_1+0 ] = face->glyph->bitmap.buffer[ offset_2 ]; // 0xFF;
    00410           img->pixels()[ offset_1+1 ] = face->glyph->bitmap.buffer[ offset_2 ]; // 0xFF;
    00411           img->pixels()[ offset_1+2 ] = face->glyph->bitmap.buffer[ offset_2 ]; // 0xFF;
    00412           img->pixels()[ offset_1+3 ] = 0xFF; // face->glyph->bitmap.buffer[ offset_2 ];
    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       // sets anisotropy to the maximum supported
    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 //-----------------------------------------------------------------------------

Visualization Library v2011.09.1162 Reference Documentation
Copyright 2005-2011 Michele Bosi. All rights reserved.
Updated on Thu Jan 26 2012 00:43:37.
Permission is granted to use this page to write and publish articles regarding Visualization Library.