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, mTtfResolution ) )
    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 Sun Nov 28 19:48:24 2004