00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "MyGUI_Precompiled.h"
00024 #include "MyGUI_ResourceTrueTypeFont.h"
00025 #include "MyGUI_Common.h"
00026 #include "MyGUI_DataManager.h"
00027 #include "MyGUI_RenderManager.h"
00028
00029 #ifdef MYGUI_USE_FREETYPE
00030 #include <ft2build.h>
00031 #include FT_FREETYPE_H
00032 #include FT_GLYPH_H
00033 #endif // MYGUI_USE_FREETYPE
00034
00035 namespace MyGUI
00036 {
00037
00038 const unsigned char FONT_MASK_SELECT = 0x88;
00039 const unsigned char FONT_MASK_SELECT_DEACTIVE = 0x60;
00040 const unsigned char FONT_MASK_SPACE = 0x00;
00041 const unsigned char FONT_MASK_CHAR = 0xFF;
00042 const size_t MIN_FONT_TEXTURE_WIDTH = 256;
00043
00044 ResourceTrueTypeFont::ResourceTrueTypeFont() :
00045 mTtfSize(0),
00046 mTtfResolution(0),
00047 mAntialiasColour(false),
00048 mDistance(0),
00049 mSpaceWidth(0),
00050 mTabWidth(0),
00051 mCursorWidth(2),
00052 mSelectionWidth(2),
00053 mOffsetHeight(0),
00054 mHeightPix(0),
00055 mTexture(nullptr)
00056 {
00057 }
00058
00059 ResourceTrueTypeFont::~ResourceTrueTypeFont()
00060 {
00061 if (mTexture != nullptr)
00062 {
00063 RenderManager::getInstance().destroyTexture(mTexture);
00064 mTexture = nullptr;
00065 }
00066 }
00067
00068 GlyphInfo* ResourceTrueTypeFont::getGlyphInfo(Char _id)
00069 {
00070 for (VectorRangeInfo::iterator iter=mVectorRangeInfo.begin(); iter!=mVectorRangeInfo.end(); ++iter)
00071 {
00072 GlyphInfo* info = iter->getInfo(_id);
00073 if (info == nullptr) continue;
00074 return info;
00075 }
00076
00077 return &mSpaceGlyphInfo;
00078 }
00079
00080 void ResourceTrueTypeFont::addGlyph(GlyphInfo * _info, Char _index, int _left, int _top, int _right, int _bottom, int _finalw, int _finalh, float _aspect, int _addHeight)
00081 {
00082 _info->codePoint = _index;
00083 _info->uvRect.left = (float)_left / (float)_finalw;
00084 _info->uvRect.top = (float)(_top + _addHeight) / (float)_finalh;
00085 _info->uvRect.right = (float)( _right ) / (float)_finalw;
00086 _info->uvRect.bottom = ( _bottom + _addHeight ) / (float)_finalh;
00087 _info->width = _right - _left;
00088 }
00089
00090 void ResourceTrueTypeFont::initialise()
00091 {
00092
00093 #ifdef MYGUI_USE_FREETYPE
00094
00095 mTexture = RenderManager::getInstance().createTexture(MyGUI::utility::toString((size_t)this, "_TrueTypeFont"));
00096
00097
00098 FT_Library ftLibrary;
00099
00100 if( FT_Init_FreeType( &ftLibrary ) ) MYGUI_EXCEPT("Could not init FreeType library!");
00101
00102
00103 FT_Face face;
00104
00105
00106 IDataStream* datastream = DataManager::getInstance().getData(mSource);
00107 MYGUI_ASSERT(datastream, "Could not open font face!");
00108
00109 size_t datasize = datastream->size();
00110 uint8* data = new uint8[datasize];
00111 datastream->read(data, datasize);
00112 delete datastream;
00113
00114 if ( FT_New_Memory_Face( ftLibrary, data, (FT_Long)datasize, 0, &face ) )
00115 MYGUI_EXCEPT("Could not open font face!");
00116
00117
00118 FT_F26Dot6 ftSize = (FT_F26Dot6)(mTtfSize * (1 << 6));
00119 if ( FT_Set_Char_Size( face, ftSize, 0, mTtfResolution, mTtfResolution ) )
00120 MYGUI_EXCEPT("Could not set char size!");
00121
00122 int max_height = 0, max_bear = 0;
00123
00124 int spec_len = mCursorWidth + mSelectionWidth + mSelectionWidth + mSpaceWidth + mTabWidth + (mDistance * 5);
00125 int len = mDistance + spec_len;
00126 int height = 0;
00127
00128 size_t finalWidth = MIN_FONT_TEXTURE_WIDTH;
00129
00130 while (mTtfSize*mTtfResolution > finalWidth*6) finalWidth *= 2;
00131
00132 for (VectorRangeInfo::iterator iter=mVectorRangeInfo.begin(); iter!=mVectorRangeInfo.end(); ++iter)
00133 {
00134 for (Char index=iter->first; index<=iter->last; ++index)
00135 {
00136
00137
00138 if (checkHidePointCode(index)) continue;
00139
00140 if (FT_Load_Char( face, index, FT_LOAD_RENDER )) continue;
00141 if (nullptr == face->glyph->bitmap.buffer) continue;
00142 FT_Int advance = (face->glyph->advance.x >> 6 ) + ( face->glyph->metrics.horiBearingX >> 6 );
00143
00144 if ( ( 2 * ( face->glyph->bitmap.rows << 6 ) - face->glyph->metrics.horiBearingY ) > max_height )
00145 max_height = ( 2 * ( face->glyph->bitmap.rows << 6 ) - face->glyph->metrics.horiBearingY );
00146
00147 if ( face->glyph->metrics.horiBearingY > max_bear )
00148 max_bear = face->glyph->metrics.horiBearingY;
00149
00150 len += (advance + mDistance);
00151 if ( int(finalWidth - 1) < (len + advance + mDistance) ) { height ++; len = mDistance;}
00152
00153 }
00154 }
00155
00156 max_height >>= 6;
00157 max_bear >>= 6;
00158
00159 size_t finalHeight = (height+1) * (max_height + mDistance) + mDistance;
00160
00161
00162 while (finalHeight > finalWidth)
00163 {
00164 finalHeight /= 2;
00165 finalWidth *= 2;
00166 }
00167
00168
00169 size_t needHeight = 1;
00170 while (needHeight < finalHeight) needHeight <<= 1;
00171 finalHeight = needHeight;
00172
00173 float textureAspect = (float)finalWidth / (float)finalHeight;
00174
00175 const size_t pixel_bytes = 2;
00176 size_t data_width = finalWidth * pixel_bytes;
00177 size_t data_size = finalWidth * finalHeight * pixel_bytes;
00178
00179 MYGUI_LOG(Info, "ResourceTrueTypeFont '" << getResourceName() << "' using texture size " << finalWidth << " x " << finalHeight);
00180 MYGUI_LOG(Info, "ResourceTrueTypeFont '" << getResourceName() << "' using real height " << max_height << " pixels");
00181 mHeightPix = max_height;
00182
00183 uint8* imageData = new uint8[data_size];
00184
00185 for (size_t i = 0; i < data_size; i += pixel_bytes)
00186 {
00187 imageData[i + 0] = 0xFF;
00188 imageData[i + 1] = 0x00;
00189 }
00190
00191
00192 len = mDistance;
00193 height = mDistance;
00194 FT_Int advance = 0;
00195
00196
00197
00198
00199 advance = mSpaceWidth;
00200
00201
00202 if ( int(finalWidth - 1) < (len + advance + mDistance) ) { height += max_height + mDistance; len = mDistance; }
00203
00204 for (int j = 0; j < max_height; j++ )
00205 {
00206 int row = j + (int)height;
00207 uint8* pDest = &imageData[(row * data_width) + len * pixel_bytes];
00208 for (int k = 0; k < advance; k++ )
00209 {
00210 *pDest++= FONT_MASK_CHAR;
00211 *pDest++= FONT_MASK_SPACE;
00212 }
00213 }
00214
00215 addGlyph(&mSpaceGlyphInfo, FontCodeType::Space, len, height, len + advance, height + max_height, finalWidth, finalHeight, textureAspect, mOffsetHeight);
00216 len += (advance + mDistance);
00217
00218
00219
00220
00221 advance = mTabWidth;
00222
00223
00224 if ( int(finalWidth - 1) < (len + advance + mDistance) ) { height += max_height + mDistance; len = mDistance; }
00225
00226 for (int j = 0; j < max_height; j++ )
00227 {
00228 int row = j + (int)height;
00229 uint8* pDest = &imageData[(row * data_width) + len * pixel_bytes];
00230 for (int k = 0; k < advance; k++ )
00231 {
00232 *pDest++= FONT_MASK_CHAR;
00233 *pDest++= FONT_MASK_SPACE;
00234 }
00235 }
00236
00237 addGlyph(&mTabGlyphInfo, FontCodeType::Tab, len, height, len + advance, height + max_height, finalWidth, finalHeight, textureAspect, mOffsetHeight);
00238 len += (advance + mDistance);
00239
00240
00241
00242
00243 advance = mSelectionWidth;
00244 for (int j = 0; j < max_height; j++ )
00245 {
00246 int row = j + (int)height;
00247 uint8* pDest = &imageData[(row * data_width) + len * pixel_bytes];
00248 for(int k = 0; k < advance; k++ )
00249 {
00250 *pDest++= FONT_MASK_CHAR;
00251 *pDest++= FONT_MASK_SELECT;
00252 }
00253 }
00254
00255
00256 if ( int(finalWidth - 1) < (len + advance + mDistance) ) { height += max_height + mDistance; len = mDistance; }
00257
00258 addGlyph(&mSelectGlyphInfo, FontCodeType::Selected, len, height, len + advance, height + max_height, finalWidth, finalHeight, textureAspect, mOffsetHeight);
00259 len += (advance + mDistance);
00260
00261
00262
00263
00264 advance = mSelectionWidth;
00265
00266
00267 if ( int(finalWidth - 1) < (len + advance + mDistance) ) { height += max_height + mDistance; len = mDistance; }
00268
00269 for (int j = 0; j < max_height; j++ )
00270 {
00271 int row = j + (int)height;
00272 uint8* pDest = &imageData[(row * data_width) + len * pixel_bytes];
00273 for(int k = 0; k < advance; k++ )
00274 {
00275 *pDest++= FONT_MASK_CHAR;
00276 *pDest++= FONT_MASK_SELECT_DEACTIVE;
00277 }
00278 }
00279
00280 addGlyph(&mSelectDeactiveGlyphInfo, FontCodeType::SelectedBack, len, height, len + advance, height + max_height, finalWidth, finalHeight, textureAspect, mOffsetHeight);
00281 len += (advance + mDistance);
00282
00283
00284
00285
00286 advance = mCursorWidth;
00287
00288
00289 if ( int(finalWidth - 1) < (len + advance + mDistance) ) { height += max_height + mDistance; len = mDistance; }
00290
00291 for (int j = 0; j < max_height; j++ )
00292 {
00293 int row = j + (int)height;
00294 uint8* pDest = &imageData[(row * data_width) + len * pixel_bytes];
00295 for(int k = 0; k < advance; k++ )
00296 {
00297 *pDest++= (k&1) ? 0 : 0xFF;
00298 *pDest++= FONT_MASK_CHAR;
00299 }
00300 }
00301
00302 addGlyph(&mCursorGlyphInfo, FontCodeType::Cursor, len, height, len + advance, height + max_height, finalWidth, finalHeight, textureAspect, mOffsetHeight);
00303 len += (advance + mDistance);
00304
00305
00306
00307
00308 FT_Error ftResult;
00309 for (VectorRangeInfo::iterator iter=mVectorRangeInfo.begin(); iter!=mVectorRangeInfo.end(); ++iter)
00310 {
00311 size_t pos = 0;
00312 for (Char index=iter->first; index<=iter->last; ++index, ++pos)
00313 {
00314
00315 if (checkHidePointCode(index)) continue;
00316
00317 GlyphInfo& info = iter->range.at(pos);
00318
00319 ftResult = FT_Load_Char( face, index, FT_LOAD_RENDER );
00320 if (ftResult)
00321 {
00322
00323 MYGUI_LOG(Warning, "cannot load character " << index << " in font " << getResourceName());
00324 continue;
00325 }
00326
00327 FT_Int glyph_advance = (face->glyph->advance.x >> 6 );
00328 unsigned char* buffer = face->glyph->bitmap.buffer;
00329
00330 if (nullptr == buffer)
00331 {
00332
00333 MYGUI_LOG(Warning, "Freetype returned nullptr for character " << index << " in font " << getResourceName());
00334 continue;
00335 }
00336
00337 int y_bearnig = max_bear - ( face->glyph->metrics.horiBearingY >> 6 );
00338
00339
00340 if ( int(finalWidth - 1) < (len + face->glyph->bitmap.width + mDistance) ) { height += max_height + mDistance; len = mDistance; }
00341
00342 for (int j = 0; j < face->glyph->bitmap.rows; j++ )
00343 {
00344 int row = j + (int)height + y_bearnig;
00345 uint8* pDest = &imageData[(row * data_width) + (len + ( face->glyph->metrics.horiBearingX >> 6 )) * pixel_bytes];
00346 for (int k = 0; k < face->glyph->bitmap.width; k++ )
00347 {
00348 if (mAntialiasColour) *pDest++= *buffer;
00349 else *pDest++= FONT_MASK_CHAR;
00350 *pDest++= *buffer;
00351 buffer++;
00352 }
00353 }
00354
00355 addGlyph(&info, index, len, height, len + glyph_advance, height + max_height, finalWidth, finalHeight, textureAspect, mOffsetHeight);
00356 len += (glyph_advance + mDistance);
00357
00358 }
00359 }
00360
00361
00362
00363 RangeInfo info(FontCodeType::Selected, FontCodeType::Tab);
00364 info.setInfo(FontCodeType::Selected, &mSelectGlyphInfo);
00365 info.setInfo(FontCodeType::SelectedBack, &mSelectDeactiveGlyphInfo);
00366 info.setInfo(FontCodeType::Cursor, &mCursorGlyphInfo);
00367 info.setInfo(FontCodeType::Tab, &mTabGlyphInfo);
00368
00369 mVectorRangeInfo.push_back(info);
00370
00371
00372 mTexture->createManual(finalWidth, finalHeight, TextureUsage::Static | TextureUsage::Write, PixelFormat::L8A8);
00373
00374 void* buffer_ptr = mTexture->lock(TextureUsage::Write);
00375 memcpy(buffer_ptr, imageData, data_size);
00376 mTexture->unlock();
00377
00378 delete[] imageData;
00379 delete data;
00380
00381 FT_Done_FreeType(ftLibrary);
00382
00383 #else // MYGUI_USE_FREETYPE
00384
00385 MYGUI_LOG(Error, "ResourceTrueTypeFont '" << getResourceName() << "' - Ttf font disabled. Define MYGUI_USE_FREETYE if you need ttf fonts.");
00386
00387 #endif // MYGUI_USE_FREETYPE
00388
00389 }
00390
00391 void ResourceTrueTypeFont::addCodePointRange(Char _first, Char _second)
00392 {
00393 mVectorRangeInfo.push_back(RangeInfo(_first, _second));
00394 }
00395
00396 void ResourceTrueTypeFont::addHideCodePointRange(Char _first, Char _second)
00397 {
00398 mVectorHideCodePoint.push_back(PairCodePoint(_first, _second));
00399 }
00400
00401
00402 bool ResourceTrueTypeFont::checkHidePointCode(Char _id)
00403 {
00404 for (VectorPairCodePoint::iterator iter=mVectorHideCodePoint.begin(); iter!=mVectorHideCodePoint.end(); ++iter)
00405 {
00406 if (iter->isExist(_id)) return true;
00407 }
00408 return false;
00409 }
00410
00411 void ResourceTrueTypeFont::clearCodePointRanges()
00412 {
00413 mVectorRangeInfo.clear();
00414 mVectorHideCodePoint.clear();
00415 }
00416
00417 void ResourceTrueTypeFont::deserialization(xml::ElementPtr _node, Version _version)
00418 {
00419 Base::deserialization(_node, _version);
00420
00421 xml::ElementEnumerator node = _node->getElementEnumerator();
00422 while (node.next())
00423 {
00424 if (node->getName() == "Property")
00425 {
00426 const std::string& key = node->findAttribute("key");
00427 const std::string& value = node->findAttribute("value");
00428 if (key == "Source") mSource = value;
00429 else if (key == "Size") mTtfSize = utility::parseFloat(value);
00430 else if (key == "Resolution") mTtfResolution = utility::parseUInt(value);
00431 else if (key == "Antialias") mAntialiasColour = utility::parseBool(value);
00432 else if (key == "SpaceWidth") mSpaceWidth = utility::parseInt(value);
00433 else if (key == "TabWidth") mTabWidth = utility::parseInt(value);
00434
00435 else if (key == "Distance") mDistance = utility::parseInt(value);
00436 else if (key == "OffsetHeight") mOffsetHeight = utility::parseInt(value);
00437 }
00438 else if (node->getName() == "Codes")
00439 {
00440 xml::ElementEnumerator range = node->getElementEnumerator();
00441 while (range.next("Code"))
00442 {
00443 std::string range_value;
00444 std::vector<std::string> parse_range;
00445
00446 if (range->findAttribute("range", range_value))
00447 {
00448 parse_range = utility::split(range_value);
00449 if (!parse_range.empty())
00450 {
00451 int first = utility::parseInt(parse_range[0]);
00452 int last = parse_range.size() > 1 ? utility::parseInt(parse_range[1]) : first;
00453 addCodePointRange(first, last);
00454 }
00455 }
00456
00457 else if (range->findAttribute("hide", range_value))
00458 {
00459 parse_range = utility::split(range_value);
00460 if (!parse_range.empty())
00461 {
00462 int first = utility::parseInt(parse_range[0]);
00463 int last = parse_range.size() > 1 ? utility::parseInt(parse_range[1]) : first;
00464 addHideCodePointRange(first, last);
00465 }
00466 }
00467 }
00468 }
00469 }
00470
00471
00472 initialise();
00473 }
00474
00475 }