font_manager.cpp 13 KB

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