font_manager.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. /*
  2. * Copyright 2013 Jeremie Roy. All rights reserved.
  3. * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
  4. */
  5. #include <bx/bx.h>
  6. #include <stb/stb_truetype.h>
  7. #include "../common.h"
  8. #include <bgfx/bgfx.h>
  9. BX_PRAGMA_DIAGNOSTIC_PUSH()
  10. BX_PRAGMA_DIAGNOSTIC_IGNORED_MSVC(4244) // warning C4244: '=': conversion from 'double' to 'float', possible loss of data
  11. BX_PRAGMA_DIAGNOSTIC_IGNORED_MSVC(4701) // warning C4701: potentially uninitialized local variable 'pt' used
  12. #define SDF_IMPLEMENTATION
  13. #include <sdf/sdf.h>
  14. BX_PRAGMA_DIAGNOSTIC_POP()
  15. #include <wchar.h> // wcslen
  16. #include <tinystl/allocator.h>
  17. #include <tinystl/unordered_map.h>
  18. namespace stl = tinystl;
  19. #include "font_manager.h"
  20. #include "../cube_atlas.h"
  21. class TrueTypeFont
  22. {
  23. public:
  24. TrueTypeFont();
  25. ~TrueTypeFont();
  26. /// Initialize from an external buffer
  27. /// @remark The ownership of the buffer is external, and you must ensure it stays valid up to this object lifetime
  28. /// @return true if the initialization succeed
  29. bool init(const uint8_t* _buffer, uint32_t _bufferSize, int32_t _fontIndex, uint32_t _pixelHeight, int16_t _widthPadding, int16_t _heightPadding);
  30. /// return the font descriptor of the current font
  31. FontInfo getFontInfo();
  32. /// raster a glyph as 8bit alpha to a memory buffer
  33. /// update the GlyphInfo according to the raster strategy
  34. /// @ remark buffer min size: glyphInfo.m_width * glyphInfo * height * sizeof(char)
  35. bool bakeGlyphAlpha(CodePoint _codePoint, GlyphInfo& _outGlyphInfo, uint8_t* _outBuffer);
  36. /// raster a glyph as 8bit signed distance to a memory buffer
  37. /// update the GlyphInfo according to the raster strategy
  38. /// @ remark buffer min size: glyphInfo.m_width * glyphInfo * height * sizeof(char)
  39. bool bakeGlyphDistance(CodePoint _codePoint, GlyphInfo& _outGlyphInfo, uint8_t* _outBuffer);
  40. private:
  41. friend class FontManager;
  42. stbtt_fontinfo m_font;
  43. float m_scale;
  44. int16_t m_widthPadding;
  45. int16_t m_heightPadding;
  46. };
  47. TrueTypeFont::TrueTypeFont() : m_font()
  48. , m_widthPadding(6)
  49. , m_heightPadding(6)
  50. {
  51. }
  52. TrueTypeFont::~TrueTypeFont()
  53. {
  54. }
  55. bool TrueTypeFont::init(const uint8_t* _buffer, uint32_t _bufferSize, int32_t _fontIndex, uint32_t _pixelHeight, int16_t _widthPadding, int16_t _heightPadding)
  56. {
  57. BX_ASSERT(m_font == NULL, "TrueTypeFont already initialized");
  58. BX_ASSERT( (_bufferSize > 256 && _bufferSize < 100000000), "TrueType buffer size is suspicious");
  59. BX_ASSERT( (_pixelHeight > 4 && _pixelHeight < 128), "TrueType buffer size is suspicious");
  60. BX_UNUSED(_bufferSize);
  61. int offset = stbtt_GetFontOffsetForIndex(_buffer, _fontIndex);
  62. stbtt_InitFont(&m_font, _buffer, offset);
  63. m_scale = stbtt_ScaleForMappingEmToPixels(&m_font, (float)_pixelHeight);
  64. m_widthPadding = _widthPadding;
  65. m_heightPadding = _heightPadding;
  66. return true;
  67. }
  68. FontInfo TrueTypeFont::getFontInfo()
  69. {
  70. BX_ASSERT(m_font != NULL, "TrueTypeFont not initialized");
  71. int ascent;
  72. int descent;
  73. int lineGap;
  74. stbtt_GetFontVMetrics(&m_font, &ascent, &descent, &lineGap);
  75. float scale = m_scale;
  76. int x0, y0, x1, y1;
  77. stbtt_GetFontBoundingBox(&m_font, &x0, &y0, &x1, &y1);
  78. FontInfo outFontInfo;
  79. outFontInfo.scale = 1.0f;
  80. outFontInfo.ascender = bx::round(ascent * scale);
  81. outFontInfo.descender = bx::round(descent * scale);
  82. outFontInfo.lineGap = bx::round(lineGap * scale);
  83. outFontInfo.maxAdvanceWidth = bx::round((y1 - y0) * scale);
  84. outFontInfo.underlinePosition = (x1 - x0) * scale - ascent;
  85. outFontInfo.underlineThickness = (x1 - x0) * scale / 24.f;
  86. return outFontInfo;
  87. }
  88. bool TrueTypeFont::bakeGlyphAlpha(CodePoint _codePoint, GlyphInfo& _glyphInfo, uint8_t* _outBuffer)
  89. {
  90. BX_ASSERT(m_font != NULL, "TrueTypeFont not initialized");
  91. int32_t ascent, descent, lineGap;
  92. stbtt_GetFontVMetrics(&m_font, &ascent, &descent, &lineGap);
  93. int32_t advance, lsb;
  94. stbtt_GetCodepointHMetrics(&m_font, _codePoint, &advance, &lsb);
  95. const float scale = m_scale;
  96. int32_t x0, y0, x1, y1;
  97. stbtt_GetCodepointBitmapBox(&m_font, _codePoint, scale, scale, &x0, &y0, &x1, &y1);
  98. const int32_t ww = x1-x0;
  99. const int32_t hh = y1-y0;
  100. _glyphInfo.offset_x = (float)x0;
  101. _glyphInfo.offset_y = (float)y0;
  102. _glyphInfo.width = (float)ww;
  103. _glyphInfo.height = (float)hh;
  104. _glyphInfo.advance_x = bx::round(((float)advance) * scale);
  105. _glyphInfo.advance_y = bx::round(((float)(ascent + descent + lineGap)) * scale);
  106. uint32_t bpp = 1;
  107. uint32_t dstPitch = ww * bpp;
  108. stbtt_MakeCodepointBitmap(&m_font, _outBuffer, ww, hh, dstPitch, scale, scale, _codePoint);
  109. return true;
  110. }
  111. bool TrueTypeFont::bakeGlyphDistance(CodePoint _codePoint, GlyphInfo& _glyphInfo, uint8_t* _outBuffer)
  112. {
  113. BX_ASSERT(m_font != NULL, "TrueTypeFont not initialized");
  114. int32_t ascent, descent, lineGap;
  115. stbtt_GetFontVMetrics(&m_font, &ascent, &descent, &lineGap);
  116. int32_t advance, lsb;
  117. stbtt_GetCodepointHMetrics(&m_font, _codePoint, &advance, &lsb);
  118. const float scale = m_scale;
  119. int32_t x0, y0, x1, y1;
  120. stbtt_GetCodepointBitmapBox(&m_font, _codePoint, scale, scale, &x0, &y0, &x1, &y1);
  121. const int32_t ww = x1-x0;
  122. const int32_t hh = y1-y0;
  123. _glyphInfo.offset_x = (float)x0;
  124. _glyphInfo.offset_y = (float)y0;
  125. _glyphInfo.width = (float)ww;
  126. _glyphInfo.height = (float)hh;
  127. _glyphInfo.advance_x = bx::round(((float)advance) * scale);
  128. _glyphInfo.advance_y = bx::round(((float)(ascent + descent + lineGap)) * scale);
  129. uint32_t bpp = 1;
  130. uint32_t dstPitch = ww * bpp;
  131. stbtt_MakeCodepointBitmap(&m_font, _outBuffer, ww, hh, dstPitch, scale, scale, _codePoint);
  132. if (ww * hh > 0)
  133. {
  134. uint32_t dw = m_widthPadding;
  135. uint32_t dh = m_heightPadding;
  136. uint32_t nw = ww + dw * 2;
  137. uint32_t nh = hh + dh * 2;
  138. BX_ASSERT(nw * nh < 128 * 128, "Buffer overflow (size %d)", nw * nh);
  139. uint32_t buffSize = nw * nh * sizeof(uint8_t);
  140. uint8_t* alphaImg = (uint8_t*)malloc(buffSize);
  141. bx::memSet(alphaImg, 0, nw * nh * sizeof(uint8_t) );
  142. //copy the original buffer to the temp one
  143. for (uint32_t ii = dh; ii < nh - dh; ++ii)
  144. {
  145. bx::memCopy(alphaImg + ii * nw + dw, _outBuffer + (ii - dh) * ww, ww);
  146. }
  147. // stb_truetype has some builtin sdf functionality, we can investigate using that too
  148. sdfBuildDistanceField(_outBuffer, nw, 8.0f, alphaImg, nw, nh, nw);
  149. free(alphaImg);
  150. _glyphInfo.offset_x -= (float)dw;
  151. _glyphInfo.offset_y -= (float)dh;
  152. _glyphInfo.width = (float)nw;
  153. _glyphInfo.height = (float)nh;
  154. }
  155. return true;
  156. }
  157. typedef stl::unordered_map<CodePoint, GlyphInfo> GlyphHashMap;
  158. // cache font data
  159. struct FontManager::CachedFont
  160. {
  161. CachedFont()
  162. : trueTypeFont(NULL)
  163. {
  164. masterFontHandle.idx = bx::kInvalidHandle;
  165. }
  166. FontInfo fontInfo;
  167. GlyphHashMap cachedGlyphs;
  168. TrueTypeFont* trueTypeFont;
  169. // an handle to a master font in case of sub distance field font
  170. FontHandle masterFontHandle;
  171. int16_t padding;
  172. };
  173. #define MAX_FONT_BUFFER_SIZE (512 * 512 * 4)
  174. FontManager::FontManager(Atlas* _atlas)
  175. : m_ownAtlas(false)
  176. , m_atlas(_atlas)
  177. {
  178. init();
  179. }
  180. FontManager::FontManager(uint16_t _textureSideWidth)
  181. : m_ownAtlas(true)
  182. , m_atlas(new Atlas(_textureSideWidth) )
  183. {
  184. init();
  185. }
  186. void FontManager::init()
  187. {
  188. m_cachedFiles = new CachedFile[MAX_OPENED_FILES];
  189. m_cachedFonts = new CachedFont[MAX_OPENED_FONT];
  190. m_buffer = new uint8_t[MAX_FONT_BUFFER_SIZE];
  191. const uint32_t W = 3;
  192. // Create filler rectangle
  193. uint8_t buffer[W * W * 4];
  194. bx::memSet(buffer, 255, W * W * 4);
  195. m_blackGlyph.width = W;
  196. m_blackGlyph.height = W;
  197. ///make sure the black glyph doesn't bleed by using a one pixel inner outline
  198. m_blackGlyph.regionIndex = m_atlas->addRegion(W, W, buffer, AtlasRegion::TYPE_GRAY, 1);
  199. }
  200. FontManager::~FontManager()
  201. {
  202. BX_ASSERT(m_fontHandles.getNumHandles() == 0, "All the fonts must be destroyed before destroying the manager");
  203. delete [] m_cachedFonts;
  204. BX_ASSERT(m_filesHandles.getNumHandles() == 0, "All the font files must be destroyed before destroying the manager");
  205. delete [] m_cachedFiles;
  206. delete [] m_buffer;
  207. if (m_ownAtlas)
  208. {
  209. delete m_atlas;
  210. }
  211. }
  212. TrueTypeHandle FontManager::createTtf(const uint8_t* _buffer, uint32_t _size)
  213. {
  214. uint16_t id = m_filesHandles.alloc();
  215. BX_ASSERT(id != bx::kInvalidHandle, "Invalid handle used");
  216. m_cachedFiles[id].buffer = new uint8_t[_size];
  217. m_cachedFiles[id].bufferSize = _size;
  218. bx::memCopy(m_cachedFiles[id].buffer, _buffer, _size);
  219. TrueTypeHandle ret = { id };
  220. return ret;
  221. }
  222. void FontManager::destroyTtf(TrueTypeHandle _handle)
  223. {
  224. BX_ASSERT(bgfx::isValid(_handle), "Invalid handle used");
  225. delete m_cachedFiles[_handle.idx].buffer;
  226. m_cachedFiles[_handle.idx].bufferSize = 0;
  227. m_cachedFiles[_handle.idx].buffer = NULL;
  228. m_filesHandles.free(_handle.idx);
  229. }
  230. FontHandle FontManager::createFontByPixelSize(TrueTypeHandle _ttfHandle, uint32_t _typefaceIndex, uint32_t _pixelSize, uint32_t _fontType,
  231. uint16_t _glyphWidthPadding, uint16_t _glyphHeightPadding)
  232. {
  233. BX_ASSERT(bgfx::isValid(_ttfHandle), "Invalid handle used");
  234. TrueTypeFont* ttf = new TrueTypeFont();
  235. if (!ttf->init(m_cachedFiles[_ttfHandle.idx].buffer, m_cachedFiles[_ttfHandle.idx].bufferSize, _typefaceIndex, _pixelSize, _glyphWidthPadding, _glyphHeightPadding) )
  236. {
  237. delete ttf;
  238. FontHandle invalid = { bx::kInvalidHandle };
  239. return invalid;
  240. }
  241. uint16_t fontIdx = m_fontHandles.alloc();
  242. BX_ASSERT(fontIdx != bx::kInvalidHandle, "Invalid handle used");
  243. CachedFont& font = m_cachedFonts[fontIdx];
  244. font.trueTypeFont = ttf;
  245. font.fontInfo = ttf->getFontInfo();
  246. font.fontInfo.fontType = int16_t(_fontType);
  247. font.fontInfo.pixelSize = uint16_t(_pixelSize);
  248. font.cachedGlyphs.clear();
  249. font.masterFontHandle.idx = bx::kInvalidHandle;
  250. FontHandle handle = { fontIdx };
  251. return handle;
  252. }
  253. FontHandle FontManager::createScaledFontToPixelSize(FontHandle _baseFontHandle, uint32_t _pixelSize)
  254. {
  255. BX_ASSERT(bgfx::isValid(_baseFontHandle), "Invalid handle used");
  256. CachedFont& baseFont = m_cachedFonts[_baseFontHandle.idx];
  257. FontInfo& fontInfo = baseFont.fontInfo;
  258. FontInfo newFontInfo = fontInfo;
  259. newFontInfo.pixelSize = uint16_t(_pixelSize);
  260. newFontInfo.scale = (float)_pixelSize / (float) fontInfo.pixelSize;
  261. newFontInfo.ascender = (newFontInfo.ascender * newFontInfo.scale);
  262. newFontInfo.descender = (newFontInfo.descender * newFontInfo.scale);
  263. newFontInfo.lineGap = (newFontInfo.lineGap * newFontInfo.scale);
  264. newFontInfo.maxAdvanceWidth = (newFontInfo.maxAdvanceWidth * newFontInfo.scale);
  265. newFontInfo.underlineThickness = (newFontInfo.underlineThickness * newFontInfo.scale);
  266. newFontInfo.underlinePosition = (newFontInfo.underlinePosition * newFontInfo.scale);
  267. uint16_t fontIdx = m_fontHandles.alloc();
  268. BX_ASSERT(fontIdx != bx::kInvalidHandle, "Invalid handle used");
  269. CachedFont& font = m_cachedFonts[fontIdx];
  270. font.cachedGlyphs.clear();
  271. font.fontInfo = newFontInfo;
  272. font.trueTypeFont = NULL;
  273. font.masterFontHandle = _baseFontHandle;
  274. FontHandle handle = { fontIdx };
  275. return handle;
  276. }
  277. void FontManager::destroyFont(FontHandle _handle)
  278. {
  279. BX_ASSERT(bgfx::isValid(_handle), "Invalid handle used");
  280. CachedFont& font = m_cachedFonts[_handle.idx];
  281. if (font.trueTypeFont != NULL)
  282. {
  283. delete font.trueTypeFont;
  284. font.trueTypeFont = NULL;
  285. }
  286. font.cachedGlyphs.clear();
  287. m_fontHandles.free(_handle.idx);
  288. }
  289. bool FontManager::preloadGlyph(FontHandle _handle, const wchar_t* _string)
  290. {
  291. BX_ASSERT(bgfx::isValid(_handle), "Invalid handle used");
  292. CachedFont& font = m_cachedFonts[_handle.idx];
  293. if (NULL == font.trueTypeFont)
  294. {
  295. return false;
  296. }
  297. for (uint32_t ii = 0, end = (uint32_t)wcslen(_string); ii < end; ++ii)
  298. {
  299. CodePoint codePoint = _string[ii];
  300. if (!preloadGlyph(_handle, codePoint) )
  301. {
  302. return false;
  303. }
  304. }
  305. return true;
  306. }
  307. bool FontManager::preloadGlyph(FontHandle _handle, CodePoint _codePoint)
  308. {
  309. BX_ASSERT(bgfx::isValid(_handle), "Invalid handle used");
  310. CachedFont& font = m_cachedFonts[_handle.idx];
  311. FontInfo& fontInfo = font.fontInfo;
  312. GlyphHashMap::iterator iter = font.cachedGlyphs.find(_codePoint);
  313. if (iter != font.cachedGlyphs.end() )
  314. {
  315. return true;
  316. }
  317. if (NULL != font.trueTypeFont)
  318. {
  319. GlyphInfo glyphInfo;
  320. switch (font.fontInfo.fontType)
  321. {
  322. case FONT_TYPE_ALPHA:
  323. font.trueTypeFont->bakeGlyphAlpha(_codePoint, glyphInfo, m_buffer);
  324. break;
  325. case FONT_TYPE_DISTANCE:
  326. font.trueTypeFont->bakeGlyphDistance(_codePoint, glyphInfo, m_buffer);
  327. break;
  328. case FONT_TYPE_DISTANCE_SUBPIXEL:
  329. font.trueTypeFont->bakeGlyphDistance(_codePoint, glyphInfo, m_buffer);
  330. break;
  331. case FONT_TYPE_DISTANCE_OUTLINE:
  332. case FONT_TYPE_DISTANCE_OUTLINE_IMAGE:
  333. case FONT_TYPE_DISTANCE_DROP_SHADOW:
  334. case FONT_TYPE_DISTANCE_DROP_SHADOW_IMAGE:
  335. case FONT_TYPE_DISTANCE_OUTLINE_DROP_SHADOW_IMAGE:
  336. font.trueTypeFont->bakeGlyphDistance(_codePoint, glyphInfo, m_buffer);
  337. break;
  338. default:
  339. BX_ASSERT(false, "TextureType not supported yet");
  340. }
  341. if (!addBitmap(glyphInfo, m_buffer) )
  342. {
  343. return false;
  344. }
  345. glyphInfo.advance_x = (glyphInfo.advance_x * fontInfo.scale);
  346. glyphInfo.advance_y = (glyphInfo.advance_y * fontInfo.scale);
  347. glyphInfo.offset_x = (glyphInfo.offset_x * fontInfo.scale);
  348. glyphInfo.offset_y = (glyphInfo.offset_y * fontInfo.scale);
  349. glyphInfo.height = (glyphInfo.height * fontInfo.scale);
  350. glyphInfo.width = (glyphInfo.width * fontInfo.scale);
  351. font.cachedGlyphs[_codePoint] = glyphInfo;
  352. return true;
  353. }
  354. if (isValid(font.masterFontHandle)
  355. && preloadGlyph(font.masterFontHandle, _codePoint) )
  356. {
  357. const GlyphInfo* glyph = getGlyphInfo(font.masterFontHandle, _codePoint);
  358. GlyphInfo glyphInfo = *glyph;
  359. glyphInfo.advance_x = (glyphInfo.advance_x * fontInfo.scale);
  360. glyphInfo.advance_y = (glyphInfo.advance_y * fontInfo.scale);
  361. glyphInfo.offset_x = (glyphInfo.offset_x * fontInfo.scale);
  362. glyphInfo.offset_y = (glyphInfo.offset_y * fontInfo.scale);
  363. glyphInfo.height = (glyphInfo.height * fontInfo.scale);
  364. glyphInfo.width = (glyphInfo.width * fontInfo.scale);
  365. font.cachedGlyphs[_codePoint] = glyphInfo;
  366. return true;
  367. }
  368. return false;
  369. }
  370. bool FontManager::addGlyphBitmap(FontHandle _handle, CodePoint _codePoint, uint16_t _width, uint16_t _height, uint16_t _pitch, float extraScale, const uint8_t* _bitmapBuffer, float glyphOffsetX, float glyphOffsetY)
  371. {
  372. BX_ASSERT(bgfx::isValid(_handle), "Invalid handle used");
  373. CachedFont& font = m_cachedFonts[_handle.idx];
  374. GlyphHashMap::iterator iter = font.cachedGlyphs.find(_codePoint);
  375. if (iter != font.cachedGlyphs.end() )
  376. {
  377. return true;
  378. }
  379. GlyphInfo glyphInfo;
  380. float glyphScale = extraScale;
  381. glyphInfo.offset_x = glyphOffsetX * glyphScale;
  382. glyphInfo.offset_y = glyphOffsetY * glyphScale;
  383. glyphInfo.width = (float)_width;
  384. glyphInfo.height = (float)_height;
  385. glyphInfo.advance_x = (float)_width * glyphScale;
  386. glyphInfo.advance_y = (float)_height * glyphScale;
  387. glyphInfo.bitmapScale = glyphScale;
  388. uint32_t dstPitch = _width * 4;
  389. uint8_t* dst = m_buffer;
  390. const uint8_t* src = _bitmapBuffer;
  391. uint32_t srcPitch = _pitch;
  392. for (int32_t ii = 0; ii < _height; ++ii)
  393. {
  394. bx::memCopy(dst, src, dstPitch);
  395. dst += dstPitch;
  396. src += srcPitch;
  397. }
  398. glyphInfo.regionIndex = m_atlas->addRegion(
  399. (uint16_t)bx::ceil(glyphInfo.width)
  400. , (uint16_t)bx::ceil(glyphInfo.height)
  401. , m_buffer
  402. , AtlasRegion::TYPE_BGRA8
  403. );
  404. font.cachedGlyphs[_codePoint] = glyphInfo;
  405. return true;
  406. }
  407. const FontInfo& FontManager::getFontInfo(FontHandle _handle) const
  408. {
  409. BX_ASSERT(bgfx::isValid(_handle), "Invalid handle used");
  410. return m_cachedFonts[_handle.idx].fontInfo;
  411. }
  412. float FontManager::getKerning(FontHandle _handle, CodePoint _prevCodePoint, CodePoint _codePoint)
  413. {
  414. const CachedFont& cachedFont = m_cachedFonts[_handle.idx];
  415. if (isValid(cachedFont.masterFontHandle))
  416. {
  417. CachedFont& baseFont = m_cachedFonts[cachedFont.masterFontHandle.idx];
  418. return baseFont.trueTypeFont->m_scale * stbtt_GetCodepointKernAdvance(&baseFont.trueTypeFont->m_font, _prevCodePoint, _codePoint);
  419. }
  420. else
  421. {
  422. return cachedFont.trueTypeFont->m_scale * stbtt_GetCodepointKernAdvance(&cachedFont.trueTypeFont->m_font, _prevCodePoint, _codePoint);
  423. }
  424. }
  425. const GlyphInfo* FontManager::getGlyphInfo(FontHandle _handle, CodePoint _codePoint)
  426. {
  427. const GlyphHashMap& cachedGlyphs = m_cachedFonts[_handle.idx].cachedGlyphs;
  428. GlyphHashMap::const_iterator it = cachedGlyphs.find(_codePoint);
  429. if (it == cachedGlyphs.end() )
  430. {
  431. if (!preloadGlyph(_handle, _codePoint) )
  432. {
  433. return NULL;
  434. }
  435. it = cachedGlyphs.find(_codePoint);
  436. }
  437. BX_ASSERT(it != cachedGlyphs.end(), "Failed to preload glyph.");
  438. return &it->second;
  439. }
  440. bool FontManager::addBitmap(GlyphInfo& _glyphInfo, const uint8_t* _data)
  441. {
  442. _glyphInfo.regionIndex = m_atlas->addRegion(
  443. (uint16_t)bx::ceil(_glyphInfo.width)
  444. , (uint16_t)bx::ceil(_glyphInfo.height)
  445. , _data
  446. , AtlasRegion::TYPE_GRAY
  447. );
  448. return true;
  449. }