Font.cpp 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016
  1. //
  2. // Copyright (c) 2008-2013 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "Precompiled.h"
  23. #include "Context.h"
  24. #include "Deserializer.h"
  25. #include "FileSystem.h"
  26. #include "Font.h"
  27. #include "Graphics.h"
  28. #include "Log.h"
  29. #include "MemoryBuffer.h"
  30. #include "Profiler.h"
  31. #include "ResourceCache.h"
  32. #include "StringUtils.h"
  33. #include "Texture2D.h"
  34. #include "UI.h"
  35. #include "XMLFile.h"
  36. #include <ft2build.h>
  37. #include FT_FREETYPE_H
  38. #include FT_TRUETYPE_TABLES_H
  39. #include "DebugNew.h"
  40. namespace Urho3D
  41. {
  42. static const int MIN_POINT_SIZE = 1;
  43. static const int MAX_POINT_SIZE = 96;
  44. /// FreeType library subsystem.
  45. class FreeTypeLibrary : public Object
  46. {
  47. OBJECT(FreeTypeLibrary);
  48. public:
  49. /// Construct.
  50. FreeTypeLibrary(Context* context) :
  51. Object(context)
  52. {
  53. FT_Error error = FT_Init_FreeType(&library_);
  54. if (error)
  55. LOGERROR("Could not initialize FreeType library");
  56. }
  57. /// Destruct.
  58. virtual ~FreeTypeLibrary()
  59. {
  60. FT_Done_FreeType(library_);
  61. }
  62. FT_Library GetLibrary() const { return library_; }
  63. private:
  64. /// FreeType library.
  65. FT_Library library_;
  66. };
  67. MutableGlyph::MutableGlyph() :
  68. glyphIndex_(M_MAX_UNSIGNED)
  69. {
  70. }
  71. FontGlyph::FontGlyph() :
  72. used_(false),
  73. page_(M_MAX_UNSIGNED)
  74. {
  75. }
  76. FontFace::FontFace(Font* font) :
  77. font_(font),
  78. face_(0),
  79. hasKerning_(false),
  80. bitmapSize_(0)
  81. {
  82. }
  83. FontFace::~FontFace()
  84. {
  85. if (face_)
  86. {
  87. FT_Done_Face((FT_Face)face_);
  88. face_ = 0;
  89. }
  90. if (font_)
  91. {
  92. // When a face is unloaded, deduct the used texture data size from the parent font
  93. unsigned totalTextureSize = 0;
  94. for (unsigned i = 0; i < textures_.Size(); ++i)
  95. totalTextureSize += textures_[i]->GetWidth() * textures_[i]->GetHeight();
  96. font_->SetMemoryUse(font_->GetMemoryUse() - totalTextureSize);
  97. }
  98. for (List<MutableGlyph*>::Iterator i = mutableGlyphs_.Begin(); i != mutableGlyphs_.End(); ++i)
  99. delete *i;
  100. mutableGlyphs_.Clear();
  101. }
  102. const FontGlyph* FontFace::GetGlyph(unsigned c)
  103. {
  104. HashMap<unsigned, unsigned>::ConstIterator i = glyphMapping_.Find(c);
  105. if (i != glyphMapping_.End())
  106. {
  107. FontGlyph& glyph = glyphs_[i->second_];
  108. // Render glyph if not yet resident in a page texture (FreeType mode only)
  109. if (glyph.page_ == M_MAX_UNSIGNED)
  110. RenderGlyph(i->second_);
  111. // If mutable glyphs in use, move to the front of the list
  112. if (mutableGlyphs_.Size() && glyph.iterator_ != mutableGlyphs_.End())
  113. {
  114. MutableGlyph* mutableGlyph = *glyph.iterator_;
  115. mutableGlyphs_.Erase(glyph.iterator_);
  116. mutableGlyphs_.PushFront(mutableGlyph);
  117. glyph.iterator_ = mutableGlyphs_.Begin();
  118. }
  119. glyph.used_ = true;
  120. return &glyph;
  121. }
  122. else
  123. return 0;
  124. }
  125. short FontFace::GetKerning(unsigned c, unsigned d) const
  126. {
  127. if (!hasKerning_)
  128. return 0;
  129. if (c == '\n' || d == '\n')
  130. return 0;
  131. unsigned leftIndex = 0;
  132. unsigned rightIndex = 0;
  133. HashMap<unsigned, unsigned>::ConstIterator leftIt = glyphMapping_.Find(c);
  134. if (leftIt != glyphMapping_.End())
  135. leftIndex = leftIt->second_;
  136. else
  137. return 0;
  138. HashMap<unsigned, unsigned>::ConstIterator rightIt = glyphMapping_.Find(d);
  139. if (rightIt != glyphMapping_.End())
  140. rightIndex = rightIt->second_;
  141. else
  142. return 0;
  143. HashMap<unsigned, unsigned>::ConstIterator kerningIt = glyphs_[leftIndex].kerning_.Find(rightIndex);
  144. if (kerningIt != glyphs_[leftIndex].kerning_.End())
  145. return kerningIt->second_;
  146. else
  147. return 0;
  148. }
  149. bool FontFace::IsDataLost() const
  150. {
  151. for (unsigned i = 0; i < textures_.Size(); ++i)
  152. {
  153. if (textures_[i]->IsDataLost())
  154. return true;
  155. }
  156. return false;
  157. }
  158. bool FontFace::RenderAllGlyphs(int maxWidth, int maxHeight)
  159. {
  160. assert(font_ && face_ && textures_.Empty());
  161. allocator_ = AreaAllocator(FONT_TEXTURE_MIN_SIZE, FONT_TEXTURE_MIN_SIZE, maxWidth, maxHeight);
  162. for (unsigned i = 0; i < glyphs_.Size(); ++i)
  163. {
  164. if (glyphs_[i].width_ && glyphs_[i].height_)
  165. {
  166. int x, y;
  167. // Reserve an empty border between glyphs for filtering
  168. if (allocator_.Allocate(glyphs_[i].width_ + 1, glyphs_[i].height_ + 1, x, y))
  169. {
  170. glyphs_[i].x_ = x;
  171. glyphs_[i].y_ = y;
  172. glyphs_[i].page_ = 0;
  173. }
  174. else
  175. {
  176. // When allocation fails, reset the page of all glyphs allocated so far
  177. for (unsigned j = 0; j <= i; ++j)
  178. glyphs_[j].page_ = M_MAX_UNSIGNED;
  179. return false;
  180. }
  181. }
  182. else
  183. {
  184. glyphs_[i].x_ = 0;
  185. glyphs_[i].y_ = 0;
  186. glyphs_[i].page_ = 0;
  187. }
  188. }
  189. // Create image for rendering all the glyphs, clear to black
  190. SharedPtr<Image> image(new Image(font_->GetContext()));
  191. image->SetSize(allocator_.GetWidth(), allocator_.GetHeight(), 1);
  192. unsigned char* imageData = image->GetData();
  193. memset(imageData, 0, image->GetWidth() * image->GetHeight());
  194. int loadMode = font_->GetSubsystem<UI>()->GetForceAutoHint() ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT;
  195. // Render glyphs
  196. for (unsigned i = 0; i < glyphs_.Size(); ++i)
  197. RenderGlyphBitmap(i, imageData + glyphs_[i].y_ * image->GetWidth() + glyphs_[i].x_, image->GetWidth(), loadMode);
  198. // Load image into a texture, increment memory usage of the parent font
  199. SharedPtr<Texture2D> texture = font_->LoadFaceTexture(image);
  200. if (!texture)
  201. {
  202. for (unsigned i = 0; i < glyphs_.Size(); ++i)
  203. glyphs_[i].page_ = M_MAX_UNSIGNED;
  204. return false;
  205. }
  206. textures_.Push(texture);
  207. font_->SetMemoryUse(font_->GetMemoryUse() + image->GetWidth() * image->GetHeight());
  208. LOGDEBUG(ToString("Font face %s (%dpt) uses a static page texture of size %dx%d", GetFileName(font_->GetName()).CString(), pointSize_,
  209. texture->GetWidth(), texture->GetHeight()));
  210. return true;
  211. }
  212. void FontFace::RenderGlyph(unsigned index)
  213. {
  214. assert(font_ && face_);
  215. FontGlyph& glyph = glyphs_[index];
  216. // If glyph is empty, just set the current page
  217. if (!glyph.width_ || !glyph.height_)
  218. {
  219. glyph.x_ = 0;
  220. glyph.y_ = 0;
  221. glyph.page_ = textures_.Size() - 1;
  222. return;
  223. }
  224. int loadMode = font_->GetSubsystem<UI>()->GetForceAutoHint() ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT;
  225. if (!mutableGlyphs_.Size())
  226. {
  227. // Not using mutable glyphs: try to allocate from current page, reserve next page if fails
  228. int x, y;
  229. if (!allocator_.Allocate(glyph.width_ + 1, glyph.height_ + 1, x, y))
  230. {
  231. SetupNextTexture(textures_[0]->GetWidth(), textures_[0]->GetHeight());
  232. // This always succeeds, as it is the first allocation of an empty page
  233. allocator_.Allocate(glyph.width_ + 1, glyph.height_ + 1, x, y);
  234. }
  235. glyph.x_ = x;
  236. glyph.y_ = y;
  237. glyph.page_ = textures_.Size() - 1;
  238. if (!bitmap_ || (int)bitmapSize_ < glyph.width_ * glyph.height_)
  239. {
  240. bitmapSize_ = glyph.width_ * glyph.height_;
  241. bitmap_ = new unsigned char[bitmapSize_];
  242. }
  243. RenderGlyphBitmap(index, bitmap_.Get(), glyph.width_, loadMode);
  244. textures_.Back()->SetData(0, glyph.x_, glyph.y_, glyph.width_, glyph.height_, bitmap_.Get());
  245. }
  246. else
  247. {
  248. // Using mutable glyphs: overwrite the least recently used glyph
  249. List<MutableGlyph*>::Iterator it = --mutableGlyphs_.End();
  250. MutableGlyph* mutableGlyph = *it;
  251. if (mutableGlyph->glyphIndex_ != M_MAX_UNSIGNED)
  252. glyphs_[mutableGlyph->glyphIndex_].page_ = M_MAX_UNSIGNED;
  253. glyph.x_ = mutableGlyph->x_;
  254. glyph.y_ = mutableGlyph->y_;
  255. glyph.page_ = 0;
  256. glyph.iterator_ = it;
  257. mutableGlyph->glyphIndex_ = index;
  258. if (!bitmap_)
  259. {
  260. bitmapSize_ = cellWidth_ * cellHeight_;
  261. bitmap_ = new unsigned char[bitmapSize_];
  262. }
  263. // Clear the cell bitmap before rendering to ensure padding
  264. memset(bitmap_.Get(), 0, cellWidth_ * cellHeight_);
  265. RenderGlyphBitmap(index, bitmap_.Get(), cellWidth_, loadMode);
  266. textures_[0]->SetData(0, glyph.x_, glyph.y_, cellWidth_, cellHeight_, bitmap_.Get());
  267. }
  268. }
  269. void FontFace::RenderGlyphBitmap(unsigned index, unsigned char* dest, unsigned pitch, int loadMode)
  270. {
  271. const FontGlyph& glyph = glyphs_[index];
  272. if (!glyph.width_ || !glyph.height_)
  273. return;
  274. FT_Face face = (FT_Face)face_;
  275. FT_GlyphSlot slot = face->glyph;
  276. FT_Load_Glyph(face, index, loadMode);
  277. FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL);
  278. if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO)
  279. {
  280. for (int y = 0; y < slot->bitmap.rows; ++y)
  281. {
  282. unsigned char* src = slot->bitmap.buffer + slot->bitmap.pitch * y;
  283. unsigned char* rowDest = dest + y * pitch;
  284. for (int x = 0; x < slot->bitmap.width; ++x)
  285. rowDest[x] = (src[x >> 3] & (0x80 >> (x & 7))) ? 255 : 0;
  286. }
  287. }
  288. else
  289. {
  290. for (int y = 0; y < slot->bitmap.rows; ++y)
  291. {
  292. unsigned char* src = slot->bitmap.buffer + slot->bitmap.pitch * y;
  293. unsigned char* rowDest = dest + y * pitch;
  294. for (int x = 0; x < slot->bitmap.width; ++x)
  295. rowDest[x] = src[x];
  296. }
  297. }
  298. }
  299. void FontFace::SetupNextTexture(int width, int height)
  300. {
  301. // If several dynamic textures are needed, use the maximum size to pack as many as possible to one texture
  302. allocator_ = AreaAllocator(width, height);
  303. SharedPtr<Texture2D> texture = font_->CreateFaceTexture();
  304. texture->SetSize(width, height, Graphics::GetAlphaFormat());
  305. SharedArrayPtr<unsigned char> emptyBitmap(new unsigned char[width * height]);
  306. memset(emptyBitmap.Get(), 0, width * height);
  307. texture->SetData(0, 0, 0, width, height, emptyBitmap.Get());
  308. textures_.Push(texture);
  309. font_->SetMemoryUse(font_->GetMemoryUse() + width * height);
  310. LOGDEBUG(ToString("Font face %s (%dpt) is using %d dynamic page textures of size %dx%d", GetFileName(font_->GetName()).CString(),
  311. pointSize_, textures_.Size(), width, height));
  312. }
  313. void FontFace::SetupMutableGlyphs(int textureWidth, int textureHeight, int maxWidth, int maxHeight)
  314. {
  315. assert(mutableGlyphs_.Empty());
  316. SetupNextTexture(textureWidth, textureHeight);
  317. cellWidth_ = maxWidth + 1;
  318. cellHeight_ = maxHeight + 1;
  319. // Allocate as many mutable glyphs as possible
  320. int x, y;
  321. while (allocator_.Allocate(cellWidth_, cellHeight_, x, y))
  322. {
  323. MutableGlyph* glyph = new MutableGlyph();
  324. glyph->x_ = x;
  325. glyph->y_ = y;
  326. mutableGlyphs_.Push(glyph);
  327. }
  328. LOGDEBUG(ToString("Font face %s (%dpt) is using %d mutable glyphs", GetFileName(font_->GetName()).CString(), pointSize_,
  329. mutableGlyphs_.Size()));
  330. }
  331. Font::Font(Context* context) :
  332. Resource(context),
  333. fontDataSize_(0),
  334. fontType_(FONT_NONE)
  335. {
  336. }
  337. Font::~Font()
  338. {
  339. // To ensure FreeType deallocates properly, first clear all faces, then release the raw font data
  340. ReleaseFaces();
  341. fontData_.Reset();
  342. }
  343. void Font::RegisterObject(Context* context)
  344. {
  345. context->RegisterFactory<Font>();
  346. }
  347. bool Font::Load(Deserializer& source)
  348. {
  349. PROFILE(LoadFont);
  350. // In headless mode, do not actually load, just return success
  351. Graphics* graphics = GetSubsystem<Graphics>();
  352. if (!graphics)
  353. return true;
  354. faces_.Clear();
  355. fontDataSize_ = source.GetSize();
  356. if (fontDataSize_)
  357. {
  358. fontData_ = new unsigned char[fontDataSize_];
  359. if (source.Read(&fontData_[0], fontDataSize_) != fontDataSize_)
  360. return false;
  361. }
  362. else
  363. {
  364. fontData_.Reset();
  365. return false;
  366. }
  367. String ext = GetExtension(GetName());
  368. if (ext == ".ttf" || ext == ".otf" || ext == ".woff")
  369. fontType_ = FONT_FREETYPE;
  370. else if (ext == ".xml" || ext == ".fnt")
  371. fontType_ = FONT_BITMAP;
  372. SetMemoryUse(fontDataSize_);
  373. return true;
  374. }
  375. bool Font::SaveXML(Serializer& dest, int pointSize, bool usedGlyphs)
  376. {
  377. FontFace* fontFace = GetFace(pointSize);
  378. if (!fontFace)
  379. return false;
  380. PROFILE(FontSaveXML);
  381. SharedPtr<FontFace> packedFontFace;
  382. if (usedGlyphs)
  383. {
  384. // Save used glyphs only, try to pack them first
  385. packedFontFace = Pack(fontFace);
  386. if (packedFontFace)
  387. fontFace = packedFontFace;
  388. else
  389. return false;
  390. }
  391. SharedPtr<XMLFile> xml(new XMLFile(context_));
  392. XMLElement rootElem = xml->CreateRoot("font");
  393. // Information
  394. XMLElement childElem = rootElem.CreateChild("info");
  395. String fileName = GetFileName(GetName());
  396. childElem.SetAttribute("face", fileName);
  397. childElem.SetAttribute("size", String(pointSize));
  398. // Common
  399. childElem = rootElem.CreateChild("common");
  400. childElem.SetInt("lineHeight", fontFace->rowHeight_);
  401. unsigned pages = fontFace->textures_.Size();
  402. childElem.SetInt("pages", pages);
  403. // Construct the path to store the texture
  404. String pathName;
  405. File* file = dynamic_cast<File*>(&dest);
  406. if (file)
  407. // If serialize to file, use the file's path
  408. pathName = GetPath(file->GetName());
  409. else
  410. // Otherwise, use the font resource's path
  411. pathName = "Data/" + GetPath(GetName());
  412. // Pages
  413. childElem = rootElem.CreateChild("pages");
  414. for (unsigned i = 0; i < pages; ++i)
  415. {
  416. XMLElement pageElem = childElem.CreateChild("page");
  417. pageElem.SetInt("id", i);
  418. String texFileName = fileName + "_" + String(i) + ".png";
  419. pageElem.SetAttribute("file", texFileName);
  420. // Save the font face texture to image file
  421. SaveFaceTexture(fontFace->textures_[i], pathName + texFileName);
  422. }
  423. // Chars and kernings
  424. XMLElement charsElem = rootElem.CreateChild("chars");
  425. unsigned numGlyphs = fontFace->glyphs_.Size();
  426. charsElem.SetInt("count", numGlyphs);
  427. XMLElement kerningsElem;
  428. bool hasKerning = fontFace->hasKerning_;
  429. if (hasKerning)
  430. kerningsElem = rootElem.CreateChild("kernings");
  431. for (HashMap<unsigned, unsigned>::ConstIterator i = fontFace->glyphMapping_.Begin(); i != fontFace->glyphMapping_.End(); ++i)
  432. {
  433. // Char
  434. XMLElement charElem = charsElem.CreateChild("char");
  435. charElem.SetInt("id", i->first_);
  436. FontGlyph glyph = fontFace->glyphs_[i->second_];
  437. charElem.SetInt("x", glyph.x_);
  438. charElem.SetInt("y", glyph.y_);
  439. charElem.SetInt("width", glyph.width_);
  440. charElem.SetInt("height", glyph.height_);
  441. charElem.SetInt("xoffset", glyph.offsetX_);
  442. charElem.SetInt("yoffset", glyph.offsetY_);
  443. charElem.SetInt("xadvance", glyph.advanceX_);
  444. charElem.SetInt("page", glyph.page_);
  445. // Kerning
  446. if (hasKerning)
  447. {
  448. for (HashMap<unsigned, unsigned>::ConstIterator j = glyph.kerning_.Begin(); j != glyph.kerning_.End(); ++j)
  449. {
  450. // To conserve space, only write when amount is non zero
  451. if (j->second_ == 0)
  452. continue;
  453. XMLElement kerningElem = kerningsElem.CreateChild("kerning");
  454. kerningElem.SetInt("first", i->first_);
  455. kerningElem.SetInt("second", j->first_);
  456. kerningElem.SetInt("amount", j->second_);
  457. }
  458. }
  459. }
  460. return xml->Save(dest);
  461. }
  462. FontFace* Font::GetFace(int pointSize)
  463. {
  464. // In headless mode, always return null
  465. Graphics* graphics = GetSubsystem<Graphics>();
  466. if (!graphics)
  467. return 0;
  468. // For bitmap font type, always return the same font face provided by the font's bitmap file regardless of the actual requested point size
  469. if (fontType_ == FONT_BITMAP)
  470. pointSize = 0;
  471. else
  472. pointSize = Clamp(pointSize, MIN_POINT_SIZE, MAX_POINT_SIZE);
  473. HashMap<int, SharedPtr<FontFace> >::Iterator i = faces_.Find(pointSize);
  474. if (i != faces_.End())
  475. {
  476. if (!i->second_->IsDataLost())
  477. return i->second_;
  478. else
  479. {
  480. // Erase and reload face if texture data lost (OpenGL mode only)
  481. faces_.Erase(i);
  482. }
  483. }
  484. PROFILE(GetFontFace);
  485. switch (fontType_)
  486. {
  487. case FONT_FREETYPE:
  488. return GetFaceFreeType(pointSize);
  489. case FONT_BITMAP:
  490. return GetFaceBitmap(pointSize);
  491. default:
  492. return 0;
  493. }
  494. }
  495. void Font::ReleaseFaces()
  496. {
  497. faces_.Clear();
  498. }
  499. SharedPtr<Texture2D> Font::CreateFaceTexture()
  500. {
  501. SharedPtr<Texture2D> texture(new Texture2D(context_));
  502. texture->SetMipsToSkip(QUALITY_LOW, 0); // No quality reduction
  503. texture->SetNumLevels(1); // No mipmaps
  504. texture->SetAddressMode(COORD_U, ADDRESS_BORDER);
  505. texture->SetAddressMode(COORD_V, ADDRESS_BORDER),
  506. texture->SetBorderColor(Color(0.0f, 0.0f, 0.0f, 0.0f));
  507. return texture;
  508. }
  509. SharedPtr<Texture2D> Font::LoadFaceTexture(SharedPtr<Image> image)
  510. {
  511. SharedPtr<Texture2D> texture = CreateFaceTexture();
  512. if (!texture->Load(image, true))
  513. {
  514. LOGERROR("Could not load texture from image resource");
  515. return SharedPtr<Texture2D>();
  516. }
  517. return texture;
  518. }
  519. FontFace* Font::GetFaceFreeType(int pointSize)
  520. {
  521. // Create & initialize FreeType library if it does not exist yet
  522. FreeTypeLibrary* freeType = GetSubsystem<FreeTypeLibrary>();
  523. if (!freeType)
  524. context_->RegisterSubsystem(freeType = new FreeTypeLibrary(context_));
  525. // Ensure the FreeType library is kept alive as long as TTF font resources exist
  526. freeType_ = freeType;
  527. UI* ui = GetSubsystem<UI>();
  528. int maxTextureSize = ui->GetMaxFontTextureSize();
  529. FT_Face face;
  530. FT_Error error;
  531. FT_Library library = freeType->GetLibrary();
  532. if (pointSize <= 0)
  533. {
  534. LOGERROR("Zero or negative point size");
  535. return 0;
  536. }
  537. if (!fontDataSize_)
  538. {
  539. LOGERROR("Font not loaded");
  540. return 0;
  541. }
  542. error = FT_New_Memory_Face(library, &fontData_[0], fontDataSize_, 0, &face);
  543. if (error)
  544. {
  545. LOGERROR("Could not create font face");
  546. return 0;
  547. }
  548. error = FT_Set_Char_Size(face, 0, pointSize * 64, FONT_DPI, FONT_DPI);
  549. if (error)
  550. {
  551. FT_Done_Face(face);
  552. LOGERROR("Could not set font point size " + String(pointSize));
  553. return 0;
  554. }
  555. SharedPtr<FontFace> newFace(new FontFace(this));
  556. newFace->face_ = face;
  557. FT_GlyphSlot slot = face->glyph;
  558. unsigned numGlyphs = 0;
  559. // Build glyph mapping
  560. FT_UInt glyphIndex;
  561. FT_ULong charCode = FT_Get_First_Char(face, &glyphIndex);
  562. while (glyphIndex != 0)
  563. {
  564. numGlyphs = Max((int)glyphIndex + 1, (int)numGlyphs);
  565. newFace->glyphMapping_[charCode] = glyphIndex;
  566. charCode = FT_Get_Next_Char(face, charCode, &glyphIndex);
  567. }
  568. LOGDEBUG(ToString("Font face %s (%dpt) has %d glyphs", GetFileName(GetName()).CString(), pointSize, numGlyphs));
  569. // Load each of the glyphs to see the sizes & store other information
  570. int maxWidth = 0;
  571. int maxHeight = 0;
  572. int loadMode = ui->GetForceAutoHint() ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT;
  573. int ascender = face->size->metrics.ascender >> 6;
  574. int descender = face->size->metrics.descender >> 6;
  575. // Check if the font's OS/2 info gives different (larger) values for ascender & descender
  576. TT_OS2* os2Info = (TT_OS2*)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
  577. if (os2Info)
  578. {
  579. ascender = Max(ascender, os2Info->usWinAscent * face->size->metrics.y_ppem / face->units_per_EM);
  580. ascender = Max(ascender, os2Info->sTypoAscender * face->size->metrics.y_ppem / face->units_per_EM);
  581. descender = Max(descender, os2Info->usWinDescent * face->size->metrics.y_ppem / face->units_per_EM);
  582. descender = Max(descender, os2Info->sTypoDescender * face->size->metrics.y_ppem / face->units_per_EM);
  583. }
  584. // Store point size and row height. Use the maximum of ascender + descender, or the face's stored default row height
  585. newFace->pointSize_ = pointSize;
  586. newFace->rowHeight_ = Max(ascender + descender, face->size->metrics.height >> 6);
  587. newFace->glyphs_.Reserve(numGlyphs);
  588. for (unsigned i = 0; i < numGlyphs; ++i)
  589. {
  590. FontGlyph newGlyph;
  591. error = FT_Load_Glyph(face, i, loadMode);
  592. if (!error)
  593. {
  594. // Note: position within texture will be filled later
  595. newGlyph.width_ = (short)Max(slot->metrics.width >> 6, slot->bitmap.width);
  596. newGlyph.height_ = (short)Max(slot->metrics.height >> 6, slot->bitmap.rows);
  597. newGlyph.offsetX_ = (short)(slot->metrics.horiBearingX >> 6);
  598. newGlyph.offsetY_ = (short)(ascender - (slot->metrics.horiBearingY >> 6));
  599. newGlyph.advanceX_ = (short)(slot->metrics.horiAdvance >> 6);
  600. maxWidth = Max(maxWidth, newGlyph.width_);
  601. maxHeight = Max(maxHeight, newGlyph.height_);
  602. }
  603. else
  604. {
  605. newGlyph.width_ = 0;
  606. newGlyph.height_ = 0;
  607. newGlyph.offsetX_ = 0;
  608. newGlyph.offsetY_ = 0;
  609. newGlyph.advanceX_ = 0;
  610. }
  611. newFace->glyphs_.Push(newGlyph);
  612. }
  613. // Store kerning if face has kerning information
  614. if (FT_HAS_KERNING(face))
  615. {
  616. newFace->hasKerning_ = true;
  617. for (unsigned i = 0; i < numGlyphs; ++i)
  618. {
  619. for (unsigned j = 0; j < numGlyphs; ++j)
  620. {
  621. FT_Vector vector;
  622. FT_Get_Kerning(face, i, j, FT_KERNING_DEFAULT, &vector);
  623. newFace->glyphs_[i].kerning_[j] = (short)(vector.x >> 6);
  624. }
  625. }
  626. }
  627. // Now try to pack into the smallest possible texture. If face does not fit into one texture, enable dynamic mode where
  628. // glyphs are only created as necessary
  629. if (newFace->RenderAllGlyphs(maxTextureSize, maxTextureSize))
  630. {
  631. FT_Done_Face(face);
  632. newFace->face_ = 0;
  633. }
  634. else
  635. {
  636. if (ui->GetUseMutableGlyphs())
  637. newFace->SetupMutableGlyphs(maxTextureSize, maxTextureSize, maxWidth, maxHeight);
  638. else
  639. newFace->SetupNextTexture(maxTextureSize, maxTextureSize);
  640. }
  641. faces_[pointSize] = newFace;
  642. return newFace;
  643. }
  644. FontFace* Font::GetFaceBitmap(int pointSize)
  645. {
  646. SharedPtr<XMLFile> xmlReader(new XMLFile(context_));
  647. MemoryBuffer memoryBuffer(fontData_, fontDataSize_);
  648. if (!xmlReader->Load(memoryBuffer))
  649. {
  650. LOGERROR("Could not load XML file");
  651. return 0;
  652. }
  653. XMLElement root = xmlReader->GetRoot("font");
  654. if (root.IsNull())
  655. {
  656. LOGERROR("Could not find Font element");
  657. return 0;
  658. }
  659. XMLElement pagesElem = root.GetChild("pages");
  660. if (pagesElem.IsNull())
  661. {
  662. LOGERROR("Could not find Pages element");
  663. return 0;
  664. }
  665. SharedPtr<FontFace> newFace(new FontFace(this));
  666. XMLElement infoElem = root.GetChild("info");
  667. if (!infoElem.IsNull())
  668. newFace->pointSize_ = infoElem.GetInt("size");
  669. XMLElement commonElem = root.GetChild("common");
  670. newFace->rowHeight_ = commonElem.GetInt("lineHeight");
  671. unsigned pages = commonElem.GetInt("pages");
  672. newFace->textures_.Reserve(pages);
  673. ResourceCache* resourceCache = GetSubsystem<ResourceCache>();
  674. String fontPath = GetPath(GetName());
  675. unsigned totalTextureSize = 0;
  676. XMLElement pageElem = pagesElem.GetChild("page");
  677. for (unsigned i = 0; i < pages; ++i)
  678. {
  679. if (pageElem.IsNull())
  680. {
  681. LOGERROR("Could not find Page element for page: " + String(i));
  682. return 0;
  683. }
  684. // Assume the font image is in the same directory as the font description file
  685. String textureFile = fontPath + pageElem.GetAttribute("file");
  686. // Load texture manually to allow controlling the alpha channel mode
  687. SharedPtr<File> fontFile = resourceCache->GetFile(textureFile);
  688. SharedPtr<Image> fontImage(new Image(context_));
  689. if (!fontFile || !fontImage->Load(*fontFile))
  690. {
  691. LOGERROR("Failed to load font image file");
  692. return 0;
  693. }
  694. SharedPtr<Texture2D> texture = LoadFaceTexture(fontImage);
  695. if (!texture)
  696. return 0;
  697. newFace->textures_.Push(texture);
  698. totalTextureSize += fontImage->GetWidth() * fontImage->GetHeight() * fontImage->GetComponents();
  699. pageElem = pageElem.GetNext("page");
  700. }
  701. XMLElement charsElem = root.GetChild("chars");
  702. int count = charsElem.GetInt("count");
  703. newFace->glyphs_.Reserve(count);
  704. unsigned index = 0;
  705. XMLElement charElem = charsElem.GetChild("char");
  706. while (!charElem.IsNull())
  707. {
  708. int id = charElem.GetInt("id");
  709. FontGlyph glyph;
  710. glyph.x_ = charElem.GetInt("x");
  711. glyph.y_ = charElem.GetInt("y");
  712. glyph.width_ = charElem.GetInt("width");
  713. glyph.height_ = charElem.GetInt("height");
  714. glyph.offsetX_ = charElem.GetInt("xoffset");
  715. glyph.offsetY_ = charElem.GetInt("yoffset");
  716. glyph.advanceX_ = charElem.GetInt("xadvance");
  717. glyph.page_ = charElem.GetInt("page");
  718. newFace->glyphs_.Push(glyph);
  719. newFace->glyphMapping_[id] = index++;
  720. charElem = charElem.GetNext("char");
  721. }
  722. XMLElement kerningsElem = root.GetChild("kernings");
  723. if (kerningsElem.IsNull())
  724. newFace->hasKerning_ = false;
  725. else
  726. {
  727. XMLElement kerningElem = kerningsElem.GetChild("kerning");
  728. while (!kerningElem.IsNull())
  729. {
  730. int first = kerningElem.GetInt("first");
  731. HashMap<unsigned, unsigned>::Iterator i = newFace->glyphMapping_.Find(first);
  732. if (i != newFace->glyphMapping_.End())
  733. {
  734. int second = kerningElem.GetInt("second");
  735. int amount = kerningElem.GetInt("amount");
  736. FontGlyph& glyph = newFace->glyphs_[i->second_];
  737. glyph.kerning_[second] = amount;
  738. }
  739. kerningElem = kerningElem.GetNext("kerning");
  740. }
  741. }
  742. LOGDEBUG(ToString("Bitmap font face %s has %d glyphs", GetFileName(GetName()).CString(), count));
  743. SetMemoryUse(GetMemoryUse() + totalTextureSize);
  744. faces_[pointSize] = newFace;
  745. return newFace;
  746. }
  747. unsigned Font::ConvertFormatToNumComponents(unsigned format)
  748. {
  749. if (format == Graphics::GetRGBAFormat())
  750. return 4;
  751. else if (format == Graphics::GetRGBFormat())
  752. return 3;
  753. else if (format == Graphics::GetLuminanceAlphaFormat())
  754. return 2;
  755. else
  756. return 1;
  757. }
  758. SharedPtr<FontFace> Font::Pack(FontFace* fontFace)
  759. {
  760. // Set parent font as null for the packed face so that it does not attempt to manage the font's total memory use
  761. SharedPtr<FontFace> packedFontFace(new FontFace((Font*)0));
  762. int maxTextureSize = GetSubsystem<UI>()->GetMaxFontTextureSize();
  763. // Clone properties
  764. packedFontFace->pointSize_ = fontFace->pointSize_;
  765. packedFontFace->rowHeight_ = fontFace->rowHeight_;
  766. packedFontFace->hasKerning_ = fontFace->hasKerning_;
  767. // Assume that format is the same for all textures and that bitmap font type may have more than one component
  768. unsigned components = ConvertFormatToNumComponents(fontFace->textures_[0]->GetFormat());
  769. // Save the existing textures as image resources
  770. Vector<SharedPtr<Image> > images(fontFace->textures_.Size());
  771. for (unsigned i = 0; i < fontFace->textures_.Size(); ++i)
  772. images[i] = SaveFaceTexture(fontFace->textures_[i]);
  773. // Reallocate used glyphs to new texture(s)
  774. unsigned page = 0;
  775. unsigned index = 0;
  776. unsigned startIndex = 0;
  777. HashMap<unsigned, unsigned>::ConstIterator startIter = fontFace->glyphMapping_.Begin();
  778. HashMap<unsigned, unsigned>::ConstIterator i;
  779. while (startIter != fontFace->glyphMapping_.End())
  780. {
  781. AreaAllocator allocator(FONT_TEXTURE_MIN_SIZE, FONT_TEXTURE_MIN_SIZE, maxTextureSize, maxTextureSize);
  782. for (i = startIter; i != fontFace->glyphMapping_.End(); ++i)
  783. {
  784. FontGlyph glyph = fontFace->glyphs_[i->second_];
  785. if (!glyph.used_)
  786. continue;
  787. if (glyph.width_ && glyph.height_)
  788. {
  789. int x, y;
  790. // Reserve an empty border between glyphs for filtering
  791. if (allocator.Allocate(glyph.width_ + 1, glyph.height_ + 1, x, y))
  792. {
  793. glyph.x_ = x;
  794. glyph.y_ = y;
  795. glyph.page_ = page;
  796. }
  797. else
  798. break;
  799. }
  800. packedFontFace->glyphs_.Push(glyph);
  801. packedFontFace->glyphMapping_[i->first_] = index++;
  802. }
  803. int texWidth = allocator.GetWidth();
  804. int texHeight = allocator.GetHeight();
  805. // Create the image for rendering the fonts
  806. SharedPtr<Image> image(new Image(context_));
  807. image->SetSize(texWidth, texHeight, components);
  808. // First clear the whole image
  809. unsigned char* imageData = image->GetData();
  810. for (int y = 0; y < texHeight; ++y)
  811. {
  812. unsigned char* dest = imageData + components * texWidth * y;
  813. memset(dest, 0, components * texWidth);
  814. }
  815. // Then render the glyphs into new image
  816. for (HashMap<unsigned, unsigned>::ConstIterator j = startIter; j != i; ++j)
  817. {
  818. FontGlyph glyph = fontFace->glyphs_[j->second_];
  819. if (!glyph.used_)
  820. continue;
  821. if (!glyph.width_ || !glyph.height_)
  822. {
  823. ++startIndex;
  824. continue;
  825. }
  826. FontGlyph packedGlyph = packedFontFace->glyphs_[startIndex++];
  827. Image* image = images[glyph.page_];
  828. unsigned char* source = image->GetData() + components * (image->GetWidth() * glyph.y_ + glyph.x_);
  829. unsigned char* destination = imageData + components * (texWidth * packedGlyph.y_ + packedGlyph.x_);
  830. for (int i = 0; i < glyph.height_; ++i)
  831. {
  832. memcpy(destination, source, components * glyph.width_);
  833. source += components * image->GetWidth();
  834. destination += components * texWidth;
  835. }
  836. }
  837. // Finally load image into the texture
  838. SharedPtr<Texture2D> texture = LoadFaceTexture(image);
  839. if (!texture)
  840. return SharedPtr<FontFace>();
  841. packedFontFace->textures_.Push(texture);
  842. ++page;
  843. startIter = i;
  844. assert(index == startIndex);
  845. }
  846. return packedFontFace;
  847. }
  848. SharedPtr<Image> Font::SaveFaceTexture(Texture2D* texture)
  849. {
  850. Image* image = new Image(context_);
  851. image->SetSize(texture->GetWidth(), texture->GetHeight(), ConvertFormatToNumComponents(texture->GetFormat()));
  852. if (!static_cast<Texture2D*>(texture)->GetData(0, image->GetData()))
  853. {
  854. delete image;
  855. LOGERROR("Could not save texture to image resource");
  856. return SharedPtr<Image>();
  857. }
  858. return SharedPtr<Image>(image);
  859. }
  860. bool Font::SaveFaceTexture(Texture2D* texture, const String& fileName)
  861. {
  862. SharedPtr<Image> image = SaveFaceTexture(texture);
  863. return image ? image->SavePNG(fileName) : false;
  864. }
  865. }