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

OgreFont.cpp

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002 This source file is a part of OGRE
00003 (Object-oriented Graphics Rendering Engine)
00004 
00005 For the latest info, see http://www.ogre3d.org/
00006 
00007 Copyright © 2000-2002 The OGRE Team
00008 Also see acknowledgements in Readme.html
00009 
00010 This library is free software; you can redistribute it and/or modify it
00011 under the terms of the GNU Lesser General Public License (LGPL) as 
00012 published by the Free Software Foundation; either version 2.1 of the 
00013 License, or (at your option) any later version.
00014 
00015 This library is distributed in the hope that it will be useful, but 
00016 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
00017 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
00018 License for more details.
00019 
00020 You should have received a copy of the GNU Lesser General Public License 
00021 along with this library; if not, write to the Free Software Foundation, 
00022 Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA or go to
00023 http://www.gnu.org/copyleft/lesser.txt
00024 -------------------------------------------------------------------------*/
00025 #include "OgreStableHeaders.h"
00026 
00027 #include "OgreFont.h"
00028 #include "OgreMaterialManager.h"
00029 #include "OgreTextureManager.h"
00030 #include "OgreFontManager.h"
00031 #include "OgreSDDataChunk.h"
00032 #include "OgreLogManager.h"
00033 #include "OgreStringConverter.h"
00034 #include "OgreRenderWindow.h"
00035 #include "OgreException.h"
00036 #include "OgreBlendMode.h"
00037 #include "OgreTextureUnitState.h"
00038 #include "OgreTechnique.h"
00039 #include "OgrePass.h"
00040 #include "OgreMaterial.h"
00041 #include <ft2build.h>
00042 #include FT_FREETYPE_H
00043 #include FT_GLYPH_H
00044 
00045 
00046 
00047 namespace Ogre
00048 {
00049     //---------------------------------------------------------------------
00050     
00051     //---------------------------------------------------------------------
00052     Font::Font( const String& name)
00053     {
00054         mName = name;
00055         mType = FT_TRUETYPE;
00056         mpMaterial = NULL;
00057         mSource = "";
00058         mTtfSize = 0;
00059         mTtfResolution = 0;
00060         mAntialiasColour = false;
00061 
00062 
00063 
00064     }
00065     //---------------------------------------------------------------------
00066     Font::~Font()
00067     {
00068 
00069     }
00070     //---------------------------------------------------------------------
00071     void Font::setType(FontType ftype)
00072     {
00073         mType = ftype;
00074     }
00075     //---------------------------------------------------------------------
00076     FontType Font::getType(void) const
00077     {
00078         return mType;
00079     }
00080     //---------------------------------------------------------------------
00081     void Font::setSource(const String& source)
00082     {
00083         mSource = source;
00084     }
00085     //---------------------------------------------------------------------
00086     void Font::setTrueTypeSize(Real ttfSize)
00087     {
00088         mTtfSize = ttfSize;
00089     }
00090     //---------------------------------------------------------------------
00091     void Font::setTrueTypeResolution(uint ttfResolution)
00092     {
00093         mTtfResolution = ttfResolution;
00094     }
00095     //---------------------------------------------------------------------
00096     const String& Font::getSource(void) const
00097     {
00098         return mSource;
00099     }
00100     //---------------------------------------------------------------------
00101     Real Font::getTrueTypeSize(void) const
00102     {
00103         return mTtfSize;
00104     }
00105     //---------------------------------------------------------------------
00106     uint Font::getTrueTypeResolution(void) const
00107     {
00108         return mTtfResolution;
00109     }
00110     //---------------------------------------------------------------------
00111     std::pair< uint, uint > Font::StrBBox( const String & text, Real char_height, RenderWindow & window )
00112     {
00113         std::pair< uint, uint > ret( 0, 0 );
00114         Real vsX, vsY, veX, veY;
00115         unsigned int w, h; 
00116         
00117         // These are not used, but are required byt the function calls.
00118         unsigned int cdepth;
00119         int left, top;
00120 
00121         window.getMetrics( w, h, cdepth, left, top );
00122 
00123         for( uint i = 0; i < text.length(); i++ )
00124         {
00125             getGlyphTexCoords( text[ i ], vsX, vsY, veX, veY );
00126 
00127             // Calculate view-space width and height of char
00128             vsY = char_height;
00129             vsX = getGlyphAspectRatio( text[ i ] ) * char_height;
00130 
00131             ret.second += vsX * w;
00132             if( vsY * h > ret.first || ( i && text[ i - 1 ] == '\n' ) )
00133                 ret.first += vsY * h;
00134         }
00135 
00136         return ret;
00137     }
00138     //---------------------------------------------------------------------
00139     void Font::load()
00140     {
00141         if (!mIsLoaded)
00142         {
00143             // Create a new material
00144             if( !( mpMaterial = reinterpret_cast< Material * >( 
00145                 MaterialManager::getSingleton().create( "Fonts/" + mName ) ) ) )
00146             {
00147                 Except(Exception::ERR_INTERNAL_ERROR, 
00148                     "Error creating new material!", "Font::load" );
00149             }
00150 
00151             TextureUnitState *texLayer;
00152             bool blendByAlpha = true;
00153             if (mType == FT_TRUETYPE)
00154             {
00155                 createTextureFromFont();
00156                 texLayer = mpMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0);
00157                 // Always blend by alpha
00158                 blendByAlpha = true;
00159             }
00160             else
00161             {
00162                 texLayer = mpMaterial->getTechnique(0)->getPass(0)->createTextureUnitState(mSource);
00163                 Texture* tex = (Texture*)TextureManager::getSingleton().load(mSource);
00164                 if (!tex)
00165                     Except( Exception::ERR_ITEM_NOT_FOUND, "Could not find texture " + mSource,
00166                         "Font::load" );
00167                 blendByAlpha = tex->hasAlpha();
00168             }
00169             // Clamp to avoid fuzzy edges
00170             texLayer->setTextureAddressingMode( TextureUnitState::TAM_CLAMP );
00171 
00172             // Set up blending
00173             if (blendByAlpha)
00174             {
00175                 mpMaterial->setSceneBlending( SBT_TRANSPARENT_ALPHA );
00176             }
00177             else
00178             {
00179                 // Use add if no alpha (assume black background)
00180                 mpMaterial->setSceneBlending(SBT_ADD);
00181             }
00182         }
00183         mIsLoaded = true;
00184     }
00185     //---------------------------------------------------------------------
00186     void Font::unload()
00187     {
00188         mIsLoaded = false;
00189     }
00190     //---------------------------------------------------------------------
00191     void Font::createTextureFromFont(void)
00192     {
00193         FT_Library ftLibrary;
00194         // Init freetype
00195         if( FT_Init_FreeType( &ftLibrary ) )
00196             Except( Exception::ERR_INTERNAL_ERROR, "Could not init FreeType library!",
00197             "Font::Font");
00198 
00199         uint i, l, m, n;
00200         int j, k;
00201 
00202         FT_Face face;
00203         // Add a gap between letters vert and horz
00204         // prevents nasty artefacts when letters are too close together
00205         uint char_spacer = 5;
00206 
00207         // Locate ttf file
00208         SDDataChunk ttfchunk;
00209         FontManager::getSingleton()._findResourceData(mSource, ttfchunk);
00210         // Load font
00211         if( FT_New_Memory_Face( ftLibrary, ttfchunk.getPtr(), (FT_Long)ttfchunk.getSize() , 0, &face ) )
00212             Except( Exception::ERR_INTERNAL_ERROR, 
00213             "Could not open font face!", "Font::createTextureFromFont" );
00214 
00215 
00216         // Convert our point size to freetype 26.6 fixed point format
00217         FT_F26Dot6 ftSize = (FT_F26Dot6)(mTtfSize * (1 << 6));
00218         if( FT_Set_Char_Size( face, ftSize, 0, mTtfResolution, 0 ) )
00219             Except( Exception::ERR_INTERNAL_ERROR, 
00220             "Could not set char size!", "Font::createTextureFromFont" );
00221 
00222         FILE *fo_def = stdout;
00223 
00224         int max_height = 0, max_width = 0, max_bear = 0;
00225 
00226         uint startGlyph = 33;
00227         uint endGlyph = 167;
00228 
00229         // Calculate maximum width, height and bearing
00230         for( i = startGlyph, l = 0, m = 0, n = 0; i < endGlyph; i++ )
00231         {
00232             FT_Load_Char( face, i, FT_LOAD_RENDER );
00233 
00234             if( ( 2 * ( face->glyph->bitmap.rows << 6 ) - face->glyph->metrics.horiBearingY ) > max_height )
00235                 max_height = ( 2 * ( face->glyph->bitmap.rows << 6 ) - face->glyph->metrics.horiBearingY );
00236             if( face->glyph->metrics.horiBearingY > max_bear )
00237                 max_bear = face->glyph->metrics.horiBearingY;
00238 
00239             if( (face->glyph->advance.x >> 6 ) + ( face->glyph->metrics.horiBearingX >> 6 ) > max_width)
00240                 max_width = (face->glyph->advance.x >> 6 ) + ( face->glyph->metrics.horiBearingX >> 6 );
00241         }
00242 
00243         // Now work out how big our texture needs to be
00244         size_t rawSize = (max_width + char_spacer) * 
00245                             ((max_height >> 6) + char_spacer) * 
00246                             (endGlyph - startGlyph + 1);
00247 
00248         size_t tex_side = Math::Sqrt(rawSize);
00249         // just in case the size might chop a glyph in half, add another glyph width/height
00250         tex_side += std::max(max_width, (max_height>>6));
00251         // Now round up to nearest power of two, max out at 4096
00252         size_t roundUpSize = 0;
00253         for (i = 0; i < 12 && roundUpSize < tex_side; ++i)
00254             roundUpSize = 1 << i;
00255         
00256         tex_side = roundUpSize;
00257         size_t data_width = tex_side * 4;
00258 
00259         LogManager::getSingleton().logMessage("Font " + mName + "using texture size " +
00260             StringConverter::toString(tex_side) + "x" + StringConverter::toString(tex_side)); 
00261 
00262         uchar* imageData = new uchar[tex_side * tex_side * 4];
00263         // Reset content
00264         memset(imageData, 0, tex_side * tex_side * 4);
00265 
00266         for( i = startGlyph, l = 0, m = 0, n = 0; i < endGlyph; i++ )
00267         {
00268             FT_Error ftResult;
00269 
00270             // Load & render glyph
00271             ftResult = FT_Load_Char( face, i, FT_LOAD_RENDER );
00272             if (ftResult)
00273             {
00274                 // problem loading this glyph, continue
00275                 LogManager::getSingleton().logMessage("Info: cannot load character " +
00276                     StringConverter::toString(i) + " in font " + mName);
00277                 continue;
00278             }
00279 
00280             FT_Int advance = (face->glyph->advance.x >> 6 ) + ( face->glyph->metrics.horiBearingX >> 6 );
00281 
00282             unsigned char* buffer = face->glyph->bitmap.buffer;
00283 
00284             if (!buffer)
00285             {
00286                 // Yuck, FT didn't detect this but generated a null pointer!
00287                 LogManager::getSingleton().logMessage("Info: Freetype returned null for character " +
00288                     StringConverter::toString(i) + " in font " + mName);
00289                 continue;
00290             }
00291 
00292             int y_bearnig = ( max_bear >> 6 ) - ( face->glyph->metrics.horiBearingY >> 6 );
00293 
00294             for( j = 0; j < face->glyph->bitmap.rows; j++ )
00295             {
00296                 int row = j + m + y_bearnig;
00297                 uchar* pDest = &imageData[(row * data_width) + l * 4];   
00298                 for( k = 0; k < face->glyph->bitmap.width; k++ )
00299                 {
00300                     if (mAntialiasColour)
00301                     {
00302                         // Use the same greyscale pixel for all components RGBA
00303                         *pDest++= *buffer;
00304                         *pDest++= *buffer;
00305                         *pDest++= *buffer;
00306                     }
00307                     else
00308                     {
00309                         // Clamp colour to full white or off
00310                         if (*buffer > 0)
00311                         {
00312                             *pDest++= 0xFF;
00313                             *pDest++= 0xFF;
00314                             *pDest++= 0xFF;
00315                         }
00316                         else
00317                         {
00318                             *pDest++= 0;
00319                             *pDest++= 0;
00320                             *pDest++= 0;
00321                         }
00322                     }
00323                     // Always use the greyscale value for alpha
00324                     *pDest++= *buffer++;
00325                 }
00326             }
00327 
00328             this->setGlyphTexCoords( i, 
00329                 (Real)l / (Real)tex_side,  // u1
00330                 (Real)m / (Real)tex_side,  // v1
00331                 (Real)( l + ( face->glyph->advance.x >> 6 ) ) / (Real)tex_side, // u2
00332                 ( m + ( max_height >> 6 ) ) / (Real)tex_side // v2
00333                 );
00334 
00335             // Advance a column
00336             l += (advance + char_spacer);
00337 
00338             // If at end of row
00339             if( tex_side - 1 < l + ( advance ) )
00340             {
00341                 m += ( max_height >> 6 ) + char_spacer;
00342                 l = n = 0;
00343             }
00344         }
00345 
00346         SDDataChunk imgchunk(imageData, tex_side * tex_side * 4);
00347 
00348         Image img; 
00349         img.loadRawData( imgchunk, tex_side, tex_side, PF_A8R8G8B8 );
00350 
00351 
00352         String texName = mName + "Texture";
00353         // Load texture with no mipmaps
00354         TextureManager::getSingleton().loadImage( texName , img, TEX_TYPE_2D, 0  );
00355         TextureUnitState* t = mpMaterial->getTechnique(0)->getPass(0)->createTextureUnitState( texName );
00356         // Allow min/mag filter, but no mip
00357         t->setTextureFiltering(FO_LINEAR, FO_LINEAR, FO_NONE);
00358         // SDDatachunk will delete imageData
00359 
00360         FT_Done_FreeType(ftLibrary);
00361     }
00362 
00363 
00364 }

Copyright © 2002-2003 by The OGRE Team
Last modified Fri May 14 23:22:09 2004