font_manager.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. /*
  2. * Copyright 2013 Jeremie Roy. All rights reserved.
  3. * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
  4. */
  5. #include <bx/macros.h>
  6. #if BX_COMPILER_MSVC
  7. # define generic GenericFromFreeType // WinRT language extensions see "generic" as a keyword... this is stupid
  8. #endif // BX_COMPILER_MSVC
  9. BX_PRAGMA_DIAGNOSTIC_PUSH();
  10. BX_PRAGMA_DIAGNOSTIC_IGNORED_MSVC(4245) // error C4245: '=' : conversion from 'int' to 'FT_UInt', signed/unsigned mismatch
  11. BX_PRAGMA_DIAGNOSTIC_IGNORED_MSVC(4611) // warning C4611 : interaction between '_setjmp' and C++ object destruction is non - portable
  12. #if BX_COMPILER_MSVC || BX_COMPILER_GCC >= 40300
  13. #pragma push_macro("interface")
  14. #endif
  15. #undef interface
  16. #include <freetype/freetype.h>
  17. #if BX_COMPILER_MSVC || BX_COMPILER_GCC >= 40300
  18. #pragma pop_macro("interface")
  19. #endif
  20. BX_PRAGMA_DIAGNOSTIC_POP();
  21. #include "../common.h"
  22. #include <bgfx/bgfx.h>
  23. #define SDF_IMPLEMENTATION
  24. #include <sdf/sdf.h>
  25. #include <wchar.h> // wcslen
  26. #include <tinystl/allocator.h>
  27. #include <tinystl/unordered_map.h>
  28. namespace stl = tinystl;
  29. #include "font_manager.h"
  30. #include "../cube_atlas.h"
  31. struct FTHolder
  32. {
  33. FT_Library library;
  34. FT_Face face;
  35. };
  36. class TrueTypeFont
  37. {
  38. public:
  39. TrueTypeFont();
  40. ~TrueTypeFont();
  41. /// Initialize from an external buffer
  42. /// @remark The ownership of the buffer is external, and you must ensure it stays valid up to this object lifetime
  43. /// @return true if the initialization succeed
  44. bool init(const uint8_t* _buffer, uint32_t _bufferSize, int32_t _fontIndex, uint32_t _pixelHeight);
  45. /// return the font descriptor of the current font
  46. FontInfo getFontInfo();
  47. /// raster a glyph as 8bit alpha to a memory buffer
  48. /// update the GlyphInfo according to the raster strategy
  49. /// @ remark buffer min size: glyphInfo.m_width * glyphInfo * height * sizeof(char)
  50. bool bakeGlyphAlpha(CodePoint _codePoint, GlyphInfo& _outGlyphInfo, uint8_t* _outBuffer);
  51. /// raster a glyph as 32bit subpixel rgba to a memory buffer
  52. /// update the GlyphInfo according to the raster strategy
  53. /// @ remark buffer min size: glyphInfo.m_width * glyphInfo * height * sizeof(uint32_t)
  54. bool bakeGlyphSubpixel(CodePoint _codePoint, GlyphInfo& _outGlyphInfo, uint8_t* _outBuffer);
  55. /// raster a glyph as 8bit signed distance to a memory buffer
  56. /// update the GlyphInfo according to the raster strategy
  57. /// @ remark buffer min size: glyphInfo.m_width * glyphInfo * height * sizeof(char)
  58. bool bakeGlyphDistance(CodePoint _codePoint, GlyphInfo& _outGlyphInfo, uint8_t* _outBuffer);
  59. private:
  60. FTHolder* m_font;
  61. };
  62. TrueTypeFont::TrueTypeFont() : m_font(NULL)
  63. {
  64. }
  65. TrueTypeFont::~TrueTypeFont()
  66. {
  67. if (NULL != m_font)
  68. {
  69. FT_Done_Face(m_font->face);
  70. FT_Done_FreeType(m_font->library);
  71. delete m_font;
  72. m_font = NULL;
  73. }
  74. }
  75. bool TrueTypeFont::init(const uint8_t* _buffer, uint32_t _bufferSize, int32_t _fontIndex, uint32_t _pixelHeight)
  76. {
  77. BX_CHECK(m_font == NULL, "TrueTypeFont already initialized");
  78. BX_CHECK( (_bufferSize > 256 && _bufferSize < 100000000), "TrueType buffer size is suspicious");
  79. BX_CHECK( (_pixelHeight > 4 && _pixelHeight < 128), "TrueType buffer size is suspicious");
  80. FTHolder* holder = new FTHolder;
  81. FT_Error error = FT_Init_FreeType(&holder->library);
  82. BX_WARN(!error, "FT_Init_FreeType failed.");
  83. if (error)
  84. {
  85. goto err0;
  86. }
  87. error = FT_New_Memory_Face(holder->library, _buffer, _bufferSize, _fontIndex, &holder->face);
  88. BX_WARN(!error, "FT_Init_FreeType failed.");
  89. if (error)
  90. {
  91. if (FT_Err_Unknown_File_Format == error)
  92. {
  93. goto err0;
  94. }
  95. goto err1;
  96. }
  97. error = FT_Select_Charmap(holder->face, FT_ENCODING_UNICODE);
  98. BX_WARN(!error, "FT_Init_FreeType failed.");
  99. if (error)
  100. {
  101. goto err2;
  102. }
  103. error = FT_Set_Pixel_Sizes(holder->face, 0, _pixelHeight);
  104. BX_WARN(!error, "FT_Init_FreeType failed.");
  105. if (error)
  106. {
  107. goto err2;
  108. }
  109. m_font = holder;
  110. return true;
  111. err2:
  112. FT_Done_Face(holder->face);
  113. err1:
  114. FT_Done_FreeType(holder->library);
  115. err0:
  116. delete holder;
  117. return false;
  118. }
  119. FontInfo TrueTypeFont::getFontInfo()
  120. {
  121. BX_CHECK(m_font != NULL, "TrueTypeFont not initialized");
  122. BX_CHECK(FT_IS_SCALABLE(m_font->face), "Font is unscalable");
  123. FT_Size_Metrics metrics = m_font->face->size->metrics;
  124. FontInfo outFontInfo;
  125. outFontInfo.scale = 1.0f;
  126. outFontInfo.ascender = metrics.ascender / 64.0f;
  127. outFontInfo.descender = metrics.descender / 64.0f;
  128. outFontInfo.lineGap = (metrics.height - metrics.ascender + metrics.descender) / 64.0f;
  129. outFontInfo.maxAdvanceWidth = metrics.max_advance/ 64.0f;
  130. outFontInfo.underlinePosition = FT_MulFix(m_font->face->underline_position, metrics.y_scale) / 64.0f;
  131. outFontInfo.underlineThickness = FT_MulFix(m_font->face->underline_thickness, metrics.y_scale) / 64.0f;
  132. return outFontInfo;
  133. }
  134. static void glyphInfoInit(GlyphInfo& _glyphInfo, FT_BitmapGlyph _bitmap, FT_GlyphSlot _slot, uint8_t* _dst, uint32_t _bpp)
  135. {
  136. int32_t xx = _bitmap->left;
  137. int32_t yy = -_bitmap->top;
  138. int32_t ww = _bitmap->bitmap.width;
  139. int32_t hh = _bitmap->bitmap.rows;
  140. _glyphInfo.offset_x = (float)xx;
  141. _glyphInfo.offset_y = (float)yy;
  142. _glyphInfo.width = (float)ww;
  143. _glyphInfo.height = (float)hh;
  144. _glyphInfo.advance_x = (float)_slot->advance.x / 64.0f;
  145. _glyphInfo.advance_y = (float)_slot->advance.y / 64.0f;
  146. uint32_t dstPitch = ww * _bpp;
  147. uint8_t* src = _bitmap->bitmap.buffer;
  148. uint32_t srcPitch = _bitmap->bitmap.pitch;
  149. for (int32_t ii = 0; ii < hh; ++ii)
  150. {
  151. bx::memCopy(_dst, src, dstPitch);
  152. _dst += dstPitch;
  153. src += srcPitch;
  154. }
  155. }
  156. bool TrueTypeFont::bakeGlyphAlpha(CodePoint _codePoint, GlyphInfo& _glyphInfo, uint8_t* _outBuffer)
  157. {
  158. BX_CHECK(m_font != NULL, "TrueTypeFont not initialized");
  159. _glyphInfo.glyphIndex = FT_Get_Char_Index(m_font->face, _codePoint);
  160. FT_GlyphSlot slot = m_font->face->glyph;
  161. FT_Error error = FT_Load_Glyph(m_font->face, _glyphInfo.glyphIndex, FT_LOAD_DEFAULT);
  162. if (error)
  163. {
  164. return false;
  165. }
  166. FT_Glyph glyph;
  167. error = FT_Get_Glyph(slot, &glyph);
  168. if (error)
  169. {
  170. return false;
  171. }
  172. error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1);
  173. if (error)
  174. {
  175. return false;
  176. }
  177. FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph;
  178. glyphInfoInit(_glyphInfo, bitmap, slot, _outBuffer, 1);
  179. FT_Done_Glyph(glyph);
  180. return true;
  181. }
  182. bool TrueTypeFont::bakeGlyphSubpixel(CodePoint _codePoint, GlyphInfo& _glyphInfo, uint8_t* _outBuffer)
  183. {
  184. BX_CHECK(m_font != NULL, "TrueTypeFont not initialized");
  185. _glyphInfo.glyphIndex = FT_Get_Char_Index(m_font->face, _codePoint);
  186. FT_GlyphSlot slot = m_font->face->glyph;
  187. FT_Error error = FT_Load_Glyph(m_font->face, _glyphInfo.glyphIndex, FT_LOAD_DEFAULT);
  188. if (error)
  189. {
  190. return false;
  191. }
  192. FT_Glyph glyph;
  193. error = FT_Get_Glyph(slot, &glyph);
  194. if (error)
  195. {
  196. return false;
  197. }
  198. error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_LCD, 0, 1);
  199. if (error)
  200. {
  201. return false;
  202. }
  203. FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph;
  204. glyphInfoInit(_glyphInfo, bitmap, slot, _outBuffer, 3);
  205. FT_Done_Glyph(glyph);
  206. return true;
  207. }
  208. bool TrueTypeFont::bakeGlyphDistance(CodePoint _codePoint, GlyphInfo& _glyphInfo, uint8_t* _outBuffer)
  209. {
  210. BX_CHECK(m_font != NULL, "TrueTypeFont not initialized");
  211. _glyphInfo.glyphIndex = FT_Get_Char_Index(m_font->face, _codePoint);
  212. FT_Int32 loadMode = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
  213. FT_Render_Mode renderMode = FT_RENDER_MODE_NORMAL;
  214. FT_GlyphSlot slot = m_font->face->glyph;
  215. FT_Error error = FT_Load_Glyph(m_font->face, _glyphInfo.glyphIndex, loadMode);
  216. if (error)
  217. {
  218. return false;
  219. }
  220. FT_Glyph glyph;
  221. error = FT_Get_Glyph(slot, &glyph);
  222. if (error)
  223. {
  224. return false;
  225. }
  226. error = FT_Glyph_To_Bitmap(&glyph, renderMode, 0, 1);
  227. if (error)
  228. {
  229. return false;
  230. }
  231. FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph;
  232. int32_t ww = bitmap->bitmap.width;
  233. int32_t hh = bitmap->bitmap.rows;
  234. glyphInfoInit(_glyphInfo, bitmap, slot, _outBuffer, 1);
  235. FT_Done_Glyph(glyph);
  236. if (ww * hh > 0)
  237. {
  238. uint32_t dw = 6;
  239. uint32_t dh = 6;
  240. uint32_t nw = ww + dw * 2;
  241. uint32_t nh = hh + dh * 2;
  242. BX_CHECK(nw * nh < 128 * 128, "Buffer overflow (size %d)", nw * nh);
  243. uint32_t buffSize = nw * nh * sizeof(uint8_t);
  244. uint8_t* alphaImg = (uint8_t*)malloc(buffSize);
  245. bx::memSet(alphaImg, 0, nw * nh * sizeof(uint8_t) );
  246. //copy the original buffer to the temp one
  247. for (uint32_t ii = dh; ii < nh - dh; ++ii)
  248. {
  249. bx::memCopy(alphaImg + ii * nw + dw, _outBuffer + (ii - dh) * ww, ww);
  250. }
  251. sdfBuild(_outBuffer, nw, 8.0f, alphaImg, nw, nh, nw);
  252. free(alphaImg);
  253. _glyphInfo.offset_x -= (float)dw;
  254. _glyphInfo.offset_y -= (float)dh;
  255. _glyphInfo.width = (float)nw;
  256. _glyphInfo.height = (float)nh;
  257. }
  258. return true;
  259. }
  260. typedef stl::unordered_map<CodePoint, GlyphInfo> GlyphHashMap;
  261. // cache font data
  262. struct FontManager::CachedFont
  263. {
  264. CachedFont()
  265. : trueTypeFont(NULL)
  266. {
  267. masterFontHandle.idx = bx::kInvalidHandle;
  268. }
  269. FontInfo fontInfo;
  270. GlyphHashMap cachedGlyphs;
  271. TrueTypeFont* trueTypeFont;
  272. // an handle to a master font in case of sub distance field font
  273. FontHandle masterFontHandle;
  274. int16_t padding;
  275. };
  276. #define MAX_FONT_BUFFER_SIZE (512 * 512 * 4)
  277. FontManager::FontManager(Atlas* _atlas)
  278. : m_ownAtlas(false)
  279. , m_atlas(_atlas)
  280. {
  281. init();
  282. }
  283. FontManager::FontManager(uint16_t _textureSideWidth)
  284. : m_ownAtlas(true)
  285. , m_atlas(new Atlas(_textureSideWidth) )
  286. {
  287. init();
  288. }
  289. void FontManager::init()
  290. {
  291. m_cachedFiles = new CachedFile[MAX_OPENED_FILES];
  292. m_cachedFonts = new CachedFont[MAX_OPENED_FONT];
  293. m_buffer = new uint8_t[MAX_FONT_BUFFER_SIZE];
  294. const uint32_t W = 3;
  295. // Create filler rectangle
  296. uint8_t buffer[W * W * 4];
  297. bx::memSet(buffer, 255, W * W * 4);
  298. m_blackGlyph.width = W;
  299. m_blackGlyph.height = W;
  300. ///make sure the black glyph doesn't bleed by using a one pixel inner outline
  301. m_blackGlyph.regionIndex = m_atlas->addRegion(W, W, buffer, AtlasRegion::TYPE_GRAY, 1);
  302. }
  303. FontManager::~FontManager()
  304. {
  305. BX_CHECK(m_fontHandles.getNumHandles() == 0, "All the fonts must be destroyed before destroying the manager");
  306. delete [] m_cachedFonts;
  307. BX_CHECK(m_filesHandles.getNumHandles() == 0, "All the font files must be destroyed before destroying the manager");
  308. delete [] m_cachedFiles;
  309. delete [] m_buffer;
  310. if (m_ownAtlas)
  311. {
  312. delete m_atlas;
  313. }
  314. }
  315. TrueTypeHandle FontManager::createTtf(const uint8_t* _buffer, uint32_t _size)
  316. {
  317. uint16_t id = m_filesHandles.alloc();
  318. BX_CHECK(id != bx::kInvalidHandle, "Invalid handle used");
  319. m_cachedFiles[id].buffer = new uint8_t[_size];
  320. m_cachedFiles[id].bufferSize = _size;
  321. bx::memCopy(m_cachedFiles[id].buffer, _buffer, _size);
  322. TrueTypeHandle ret = { id };
  323. return ret;
  324. }
  325. void FontManager::destroyTtf(TrueTypeHandle _handle)
  326. {
  327. BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
  328. delete m_cachedFiles[_handle.idx].buffer;
  329. m_cachedFiles[_handle.idx].bufferSize = 0;
  330. m_cachedFiles[_handle.idx].buffer = NULL;
  331. m_filesHandles.free(_handle.idx);
  332. }
  333. FontHandle FontManager::createFontByPixelSize(TrueTypeHandle _ttfHandle, uint32_t _typefaceIndex, uint32_t _pixelSize, uint32_t _fontType)
  334. {
  335. BX_CHECK(bgfx::isValid(_ttfHandle), "Invalid handle used");
  336. TrueTypeFont* ttf = new TrueTypeFont();
  337. if (!ttf->init(m_cachedFiles[_ttfHandle.idx].buffer, m_cachedFiles[_ttfHandle.idx].bufferSize, _typefaceIndex, _pixelSize) )
  338. {
  339. delete ttf;
  340. FontHandle invalid = { bx::kInvalidHandle };
  341. return invalid;
  342. }
  343. uint16_t fontIdx = m_fontHandles.alloc();
  344. BX_CHECK(fontIdx != bx::kInvalidHandle, "Invalid handle used");
  345. CachedFont& font = m_cachedFonts[fontIdx];
  346. font.trueTypeFont = ttf;
  347. font.fontInfo = ttf->getFontInfo();
  348. font.fontInfo.fontType = int16_t(_fontType);
  349. font.fontInfo.pixelSize = uint16_t(_pixelSize);
  350. font.cachedGlyphs.clear();
  351. font.masterFontHandle.idx = bx::kInvalidHandle;
  352. FontHandle handle = { fontIdx };
  353. return handle;
  354. }
  355. FontHandle FontManager::createScaledFontToPixelSize(FontHandle _baseFontHandle, uint32_t _pixelSize)
  356. {
  357. BX_CHECK(bgfx::isValid(_baseFontHandle), "Invalid handle used");
  358. CachedFont& baseFont = m_cachedFonts[_baseFontHandle.idx];
  359. FontInfo& fontInfo = baseFont.fontInfo;
  360. FontInfo newFontInfo = fontInfo;
  361. newFontInfo.pixelSize = uint16_t(_pixelSize);
  362. newFontInfo.scale = (float)_pixelSize / (float) fontInfo.pixelSize;
  363. newFontInfo.ascender = (newFontInfo.ascender * newFontInfo.scale);
  364. newFontInfo.descender = (newFontInfo.descender * newFontInfo.scale);
  365. newFontInfo.lineGap = (newFontInfo.lineGap * newFontInfo.scale);
  366. newFontInfo.maxAdvanceWidth = (newFontInfo.maxAdvanceWidth * newFontInfo.scale);
  367. newFontInfo.underlineThickness = (newFontInfo.underlineThickness * newFontInfo.scale);
  368. newFontInfo.underlinePosition = (newFontInfo.underlinePosition * newFontInfo.scale);
  369. uint16_t fontIdx = m_fontHandles.alloc();
  370. BX_CHECK(fontIdx != bx::kInvalidHandle, "Invalid handle used");
  371. CachedFont& font = m_cachedFonts[fontIdx];
  372. font.cachedGlyphs.clear();
  373. font.fontInfo = newFontInfo;
  374. font.trueTypeFont = NULL;
  375. font.masterFontHandle = _baseFontHandle;
  376. FontHandle handle = { fontIdx };
  377. return handle;
  378. }
  379. void FontManager::destroyFont(FontHandle _handle)
  380. {
  381. BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
  382. CachedFont& font = m_cachedFonts[_handle.idx];
  383. if (font.trueTypeFont != NULL)
  384. {
  385. delete font.trueTypeFont;
  386. font.trueTypeFont = NULL;
  387. }
  388. font.cachedGlyphs.clear();
  389. m_fontHandles.free(_handle.idx);
  390. }
  391. bool FontManager::preloadGlyph(FontHandle _handle, const wchar_t* _string)
  392. {
  393. BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
  394. CachedFont& font = m_cachedFonts[_handle.idx];
  395. if (NULL == font.trueTypeFont)
  396. {
  397. return false;
  398. }
  399. for (uint32_t ii = 0, end = (uint32_t)wcslen(_string); ii < end; ++ii)
  400. {
  401. CodePoint codePoint = _string[ii];
  402. if (!preloadGlyph(_handle, codePoint) )
  403. {
  404. return false;
  405. }
  406. }
  407. return true;
  408. }
  409. bool FontManager::preloadGlyph(FontHandle _handle, CodePoint _codePoint)
  410. {
  411. BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
  412. CachedFont& font = m_cachedFonts[_handle.idx];
  413. FontInfo& fontInfo = font.fontInfo;
  414. GlyphHashMap::iterator iter = font.cachedGlyphs.find(_codePoint);
  415. if (iter != font.cachedGlyphs.end() )
  416. {
  417. return true;
  418. }
  419. if (NULL != font.trueTypeFont)
  420. {
  421. GlyphInfo glyphInfo;
  422. switch (font.fontInfo.fontType)
  423. {
  424. case FONT_TYPE_ALPHA:
  425. font.trueTypeFont->bakeGlyphAlpha(_codePoint, glyphInfo, m_buffer);
  426. break;
  427. case FONT_TYPE_DISTANCE:
  428. font.trueTypeFont->bakeGlyphDistance(_codePoint, glyphInfo, m_buffer);
  429. break;
  430. case FONT_TYPE_DISTANCE_SUBPIXEL:
  431. font.trueTypeFont->bakeGlyphDistance(_codePoint, glyphInfo, m_buffer);
  432. break;
  433. default:
  434. BX_CHECK(false, "TextureType not supported yet");
  435. }
  436. if (!addBitmap(glyphInfo, m_buffer) )
  437. {
  438. return false;
  439. }
  440. glyphInfo.advance_x = (glyphInfo.advance_x * fontInfo.scale);
  441. glyphInfo.advance_y = (glyphInfo.advance_y * fontInfo.scale);
  442. glyphInfo.offset_x = (glyphInfo.offset_x * fontInfo.scale);
  443. glyphInfo.offset_y = (glyphInfo.offset_y * fontInfo.scale);
  444. glyphInfo.height = (glyphInfo.height * fontInfo.scale);
  445. glyphInfo.width = (glyphInfo.width * fontInfo.scale);
  446. font.cachedGlyphs[_codePoint] = glyphInfo;
  447. return true;
  448. }
  449. if (isValid(font.masterFontHandle)
  450. && preloadGlyph(font.masterFontHandle, _codePoint) )
  451. {
  452. const GlyphInfo* glyph = getGlyphInfo(font.masterFontHandle, _codePoint);
  453. GlyphInfo glyphInfo = *glyph;
  454. glyphInfo.advance_x = (glyphInfo.advance_x * fontInfo.scale);
  455. glyphInfo.advance_y = (glyphInfo.advance_y * fontInfo.scale);
  456. glyphInfo.offset_x = (glyphInfo.offset_x * fontInfo.scale);
  457. glyphInfo.offset_y = (glyphInfo.offset_y * fontInfo.scale);
  458. glyphInfo.height = (glyphInfo.height * fontInfo.scale);
  459. glyphInfo.width = (glyphInfo.width * fontInfo.scale);
  460. font.cachedGlyphs[_codePoint] = glyphInfo;
  461. return true;
  462. }
  463. return false;
  464. }
  465. const FontInfo& FontManager::getFontInfo(FontHandle _handle) const
  466. {
  467. BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
  468. return m_cachedFonts[_handle.idx].fontInfo;
  469. }
  470. const GlyphInfo* FontManager::getGlyphInfo(FontHandle _handle, CodePoint _codePoint)
  471. {
  472. const GlyphHashMap& cachedGlyphs = m_cachedFonts[_handle.idx].cachedGlyphs;
  473. GlyphHashMap::const_iterator it = cachedGlyphs.find(_codePoint);
  474. if (it == cachedGlyphs.end() )
  475. {
  476. if (!preloadGlyph(_handle, _codePoint) )
  477. {
  478. return NULL;
  479. }
  480. it = cachedGlyphs.find(_codePoint);
  481. }
  482. BX_CHECK(it != cachedGlyphs.end(), "Failed to preload glyph.");
  483. return &it->second;
  484. }
  485. bool FontManager::addBitmap(GlyphInfo& _glyphInfo, const uint8_t* _data)
  486. {
  487. _glyphInfo.regionIndex = m_atlas->addRegion( (uint16_t)bx::fceil(_glyphInfo.width), (uint16_t)bx::fceil(_glyphInfo.height), _data, AtlasRegion::TYPE_GRAY);
  488. return true;
  489. }