GlyphCache.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. // Purpose:
  9. // - Manage and cache glyphs, retrieving them from the renderer as needed
  10. #if !defined(USE_NULLFONT_ALWAYS)
  11. #include <AtomLyIntegration/AtomFont/GlyphCache.h>
  12. #include <AtomLyIntegration/AtomFont/FontTexture.h>
  13. //-------------------------------------------------------------------------------------------------
  14. AZ::GlyphCache::GlyphCache()
  15. : m_usage(1)
  16. , m_glyphBitmapWidth(0)
  17. , m_glyphBitmapHeight(0)
  18. , m_scaleBitmap(0)
  19. {
  20. m_cacheTable.clear();
  21. m_slotList.clear();
  22. }
  23. //-------------------------------------------------------------------------------------------------
  24. AZ::GlyphCache::~GlyphCache()
  25. {
  26. }
  27. //-------------------------------------------------------------------------------------------------
  28. int AZ::GlyphCache::Create(int iCacheSize, int glyphBitmapWidth, int glyphBitmapHeight, AZ::FontSmoothMethod smoothMethod, AZ::FontSmoothAmount smoothAmount, float sizeRatio)
  29. {
  30. m_smoothMethod = smoothMethod;
  31. m_smoothAmount = smoothAmount;
  32. m_glyphBitmapWidth = glyphBitmapWidth;
  33. m_glyphBitmapHeight = glyphBitmapHeight;
  34. if (!CreateSlotList(iCacheSize))
  35. {
  36. ReleaseSlotList();
  37. return 0;
  38. }
  39. int iScaledGlyphWidth = 0;
  40. int iScaledGlyphHeight = 0;
  41. switch (m_smoothMethod)
  42. {
  43. case AZ::FontSmoothMethod::SuperSample:
  44. {
  45. switch (m_smoothAmount)
  46. {
  47. case AZ::FontSmoothAmount::x2:
  48. iScaledGlyphWidth = m_glyphBitmapWidth << 1;
  49. iScaledGlyphHeight = m_glyphBitmapHeight << 1;
  50. break;
  51. case AZ::FontSmoothAmount::x4:
  52. iScaledGlyphWidth = m_glyphBitmapWidth << 2;
  53. iScaledGlyphHeight = m_glyphBitmapHeight << 2;
  54. break;
  55. }
  56. }
  57. break;
  58. }
  59. if (iScaledGlyphWidth)
  60. {
  61. m_scaleBitmap = new GlyphBitmap;
  62. if (!m_scaleBitmap)
  63. {
  64. Release();
  65. return 0;
  66. }
  67. if (!m_scaleBitmap->Create(iScaledGlyphWidth, iScaledGlyphHeight))
  68. {
  69. Release();
  70. return 0;
  71. }
  72. m_fontRenderer.SetGlyphBitmapSize(iScaledGlyphWidth, iScaledGlyphHeight, sizeRatio);
  73. }
  74. else
  75. {
  76. m_fontRenderer.SetGlyphBitmapSize(m_glyphBitmapWidth, m_glyphBitmapHeight, sizeRatio);
  77. }
  78. return 1;
  79. }
  80. //-------------------------------------------------------------------------------------------------
  81. int AZ::GlyphCache::Release()
  82. {
  83. ReleaseSlotList();
  84. m_cacheTable.clear();
  85. if (m_scaleBitmap)
  86. {
  87. m_scaleBitmap->Release();
  88. delete m_scaleBitmap;
  89. m_scaleBitmap = 0;
  90. }
  91. m_glyphBitmapWidth = 0;
  92. m_glyphBitmapHeight = 0;
  93. return 1;
  94. }
  95. //-------------------------------------------------------------------------------------------------
  96. int AZ::GlyphCache::LoadFontFromFile(const AZStd::string & fileName)
  97. {
  98. return m_fontRenderer.LoadFromFile(fileName);
  99. }
  100. //-------------------------------------------------------------------------------------------------
  101. int AZ::GlyphCache::LoadFontFromMemory(unsigned char* fileBuffer, int dataSize)
  102. {
  103. return m_fontRenderer.LoadFromMemory(fileBuffer, dataSize);
  104. }
  105. //-------------------------------------------------------------------------------------------------
  106. int AZ::GlyphCache::ReleaseFont()
  107. {
  108. m_fontRenderer.Release();
  109. return 1;
  110. }
  111. //-------------------------------------------------------------------------------------------------
  112. int AZ::GlyphCache::GetGlyphBitmapSize(int* width, int* height)
  113. {
  114. if (width)
  115. {
  116. *width = m_glyphBitmapWidth;
  117. }
  118. if (height)
  119. {
  120. *height = m_glyphBitmapHeight;
  121. }
  122. return 1;
  123. }
  124. //-------------------------------------------------------------------------------------------------
  125. void AZ::GlyphCache::SetGlyphBitmapSize(int width, int height, float sizeRatio)
  126. {
  127. m_fontRenderer.SetGlyphBitmapSize(width, height, sizeRatio);
  128. }
  129. //-------------------------------------------------------------------------------------------------
  130. int AZ::GlyphCache::PreCacheGlyph(uint32_t character, const AtomFont::GlyphSize& glyphSize, const FFont::FontHintParams& fontHintParams)
  131. {
  132. CacheTable::iterator pItor = m_cacheTable.find(GetCacheSlotKey(character, glyphSize));
  133. if (pItor != m_cacheTable.end())
  134. {
  135. pItor->second->m_usage = m_usage;
  136. return 1;
  137. }
  138. CacheSlot* slot = GetLRUSlot();
  139. if (!slot)
  140. {
  141. return 0;
  142. }
  143. if (slot->m_usage > 0)
  144. {
  145. UnCacheGlyph(slot->m_currentCharacter, slot->m_glyphSize);
  146. }
  147. if (m_scaleBitmap)
  148. {
  149. int iOffsetMult = 1;
  150. switch (m_smoothAmount)
  151. {
  152. case AZ::FontSmoothAmount::x2:
  153. iOffsetMult = 2;
  154. break;
  155. case AZ::FontSmoothAmount::x4:
  156. iOffsetMult = 4;
  157. break;
  158. }
  159. m_scaleBitmap->Clear();
  160. if (!m_fontRenderer.GetGlyph(m_scaleBitmap, &slot->m_horizontalAdvance, &slot->m_characterWidth, &slot->m_characterHeight, slot->m_characterOffsetX, slot->m_characterOffsetY, 0, 0, character, fontHintParams))
  161. {
  162. return 0;
  163. }
  164. slot->m_characterWidth >>= iOffsetMult >> 1;
  165. slot->m_characterHeight >>= iOffsetMult >> 1;
  166. m_scaleBitmap->BlitScaledTo8(slot->m_glyphBitmap.GetBuffer(), 0, 0, m_scaleBitmap->GetWidth(), m_scaleBitmap->GetHeight(), 0, 0, slot->m_glyphBitmap.GetWidth(), slot->m_glyphBitmap.GetHeight(), slot->m_glyphBitmap.GetWidth());
  167. }
  168. else
  169. {
  170. if (!m_fontRenderer.GetGlyph(&slot->m_glyphBitmap, &slot->m_horizontalAdvance, &slot->m_characterWidth, &slot->m_characterHeight, slot->m_characterOffsetX, slot->m_characterOffsetY, 0, 0, character, fontHintParams))
  171. {
  172. return 0;
  173. }
  174. }
  175. if (m_smoothMethod == AZ::FontSmoothMethod::Blur)
  176. {
  177. slot->m_glyphBitmap.Blur(m_smoothAmount);
  178. }
  179. slot->m_usage = m_usage;
  180. slot->m_currentCharacter = character;
  181. slot->m_glyphSize = glyphSize;
  182. m_cacheTable.insert(AZStd::pair<CacheTableKey, CacheSlot*>(GetCacheSlotKey(character, glyphSize), slot));
  183. return 1;
  184. }
  185. int AZ::GlyphCache::UnCacheGlyph(uint32_t character, const AtomFont::GlyphSize& glyphSize)
  186. {
  187. CacheTable::iterator pItor = m_cacheTable.find(GetCacheSlotKey(character, glyphSize));
  188. if (pItor != m_cacheTable.end())
  189. {
  190. CacheSlot* slot = pItor->second;
  191. slot->Reset();
  192. m_cacheTable.erase(pItor);
  193. return 1;
  194. }
  195. return 0;
  196. }
  197. //-------------------------------------------------------------------------------------------------
  198. int AZ::GlyphCache::GlyphCached(uint32_t character, const AtomFont::GlyphSize& glyphSize)
  199. {
  200. return (m_cacheTable.find(GetCacheSlotKey(character, glyphSize)) != m_cacheTable.end());
  201. }
  202. //-------------------------------------------------------------------------------------------------
  203. AZ::CacheSlot* AZ::GlyphCache::GetLRUSlot()
  204. {
  205. unsigned int dwMinUsage = 0xffffffff;
  206. CacheSlot* pLRUSlot = 0;
  207. CacheSlot* slot;
  208. CacheSlotListItor pItor = m_slotList.begin();
  209. while (pItor != m_slotList.end())
  210. {
  211. slot = *pItor;
  212. if (slot->m_usage == 0)
  213. {
  214. return slot;
  215. }
  216. else
  217. {
  218. if (slot->m_usage < dwMinUsage)
  219. {
  220. pLRUSlot = slot;
  221. dwMinUsage = slot->m_usage;
  222. }
  223. }
  224. pItor++;
  225. }
  226. return pLRUSlot;
  227. }
  228. //-------------------------------------------------------------------------------------------------
  229. AZ::CacheSlot* AZ::GlyphCache::GetMRUSlot()
  230. {
  231. unsigned int dwMaxUsage = 0;
  232. CacheSlot* pMRUSlot = 0;
  233. CacheSlot* slot;
  234. CacheSlotListItor pItor = m_slotList.begin();
  235. while (pItor != m_slotList.end())
  236. {
  237. slot = *pItor;
  238. if (slot->m_usage != 0)
  239. {
  240. if (slot->m_usage > dwMaxUsage)
  241. {
  242. pMRUSlot = slot;
  243. dwMaxUsage = slot->m_usage;
  244. }
  245. }
  246. pItor++;
  247. }
  248. return pMRUSlot;
  249. }
  250. //-------------------------------------------------------------------------------------------------
  251. int AZ::GlyphCache::GetGlyph(AZ::GlyphBitmap** glyph, int* horizontalAdvance, int* width, int* height, int32_t& m_characterOffsetX, int32_t& m_characterOffsetY, uint32_t character, const AZ::AtomFont::GlyphSize& glyphSize, const AZ::FFont::FontHintParams& fontHintParams)
  252. {
  253. CacheTable::iterator pItor = m_cacheTable.find(GetCacheSlotKey(character, glyphSize));
  254. if (pItor == m_cacheTable.end())
  255. {
  256. if (!PreCacheGlyph(character, glyphSize, fontHintParams))
  257. {
  258. return 0;
  259. }
  260. }
  261. pItor = m_cacheTable.find(GetCacheSlotKey(character, glyphSize));
  262. pItor->second->m_usage = m_usage++;
  263. (*glyph) = &pItor->second->m_glyphBitmap;
  264. if (horizontalAdvance)
  265. {
  266. *horizontalAdvance = pItor->second->m_horizontalAdvance;
  267. }
  268. if (width)
  269. {
  270. *width = pItor->second->m_characterWidth;
  271. }
  272. if (height)
  273. {
  274. *height = pItor->second->m_characterHeight;
  275. }
  276. m_characterOffsetX = pItor->second->m_characterOffsetX;
  277. m_characterOffsetY = pItor->second->m_characterOffsetY;
  278. return 1;
  279. }
  280. //-------------------------------------------------------------------------------------------------
  281. Vec2 AZ::GlyphCache::GetKerning(uint32_t leftGlyph, uint32_t rightGlyph)
  282. {
  283. return m_fontRenderer.GetKerning(leftGlyph, rightGlyph);
  284. }
  285. //-------------------------------------------------------------------------------------------------
  286. float AZ::GlyphCache::GetAscenderToHeightRatio()
  287. {
  288. return m_fontRenderer.GetAscenderToHeightRatio();
  289. }
  290. //-------------------------------------------------------------------------------------------------
  291. int AZ::GlyphCache::CreateSlotList(int listSize)
  292. {
  293. for (int i = 0; i < listSize; i++)
  294. {
  295. CacheSlot* cacheSlot = new CacheSlot;
  296. if (!cacheSlot)
  297. {
  298. return 0;
  299. }
  300. if (!cacheSlot->m_glyphBitmap.Create(m_glyphBitmapWidth, m_glyphBitmapHeight))
  301. {
  302. delete cacheSlot;
  303. return 0;
  304. }
  305. cacheSlot->Reset();
  306. cacheSlot->m_slotIndex = i;
  307. m_slotList.push_back(cacheSlot);
  308. }
  309. return 1;
  310. }
  311. //-------------------------------------------------------------------------------------------------
  312. int AZ::GlyphCache::ReleaseSlotList()
  313. {
  314. CacheSlotListItor pItor = m_slotList.begin();
  315. while (pItor != m_slotList.end())
  316. {
  317. (*pItor)->m_glyphBitmap.Release();
  318. delete (*pItor);
  319. pItor = m_slotList.erase(pItor);
  320. }
  321. return 1;
  322. }
  323. //-------------------------------------------------------------------------------------------------
  324. AZ::GlyphCache::CacheTableKey AZ::GlyphCache::GetCacheSlotKey(uint32_t character, const AZ::AtomFont::GlyphSize& glyphSize) const
  325. {
  326. const AZ::AtomFont::GlyphSize clampedGlyphSize = AZ::FontTexture::ClampGlyphSize(glyphSize, m_glyphBitmapWidth, m_glyphBitmapHeight);
  327. return CacheTableKey(clampedGlyphSize, character);
  328. }
  329. #endif // #if !defined(USE_NULLFONT_ALWAYS)