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