tb_font_renderer_tbbf.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. // ================================================================================
  2. // == This file is a part of Turbo Badger. (C) 2011-2014, Emil Segerås ==
  3. // == See tb_core.h for more information. ==
  4. // ================================================================================
  5. #include "tb_font_renderer.h"
  6. #include "tb_renderer.h"
  7. #include "tb_tempbuffer.h"
  8. #include "tb_system.h"
  9. #include "tb_node_tree.h"
  10. #include "tb_hashtable.h"
  11. #ifdef TB_FONT_RENDERER_TBBF
  12. using namespace tb;
  13. struct GLYPH {
  14. int x, w;
  15. };
  16. /** TBBFRenderer renders a bitmap font.
  17. A font is loaded from a text file and at least one image that contains
  18. glyphs for a given size. The number of glyphs that the font contains is
  19. defined by the glyph string defined in the text file.
  20. Text file format (in tb.txt format parsed by parser/tb_parser.h):
  21. - info>glyph_str Should specify which characters the image
  22. file contains.
  23. - info>rgb Set to 1 for color fonts that should never
  24. care about the text color when drawing.
  25. Set to 0 to let drawing blend using the text
  26. color. Default 0.
  27. - size xx Specify font size xx. Should contain the
  28. following nodes:
  29. - bitmap The image file name (in the same folder).
  30. - ascent The ascent. Default 0.
  31. - descent The descent. Default 0.
  32. - x_ofs The x offset for all glyph. This can be
  33. used in combination with advance_delta to
  34. compensate for f.ex glow that extend
  35. around the glyph. Default 0.
  36. - advance_delta The advance delta for all glyphs. This can
  37. be used to compensate for f.ex shadow that
  38. should not add to each glyphs horizontal
  39. advance. Default 0.
  40. - space_advance The advance for the space character.
  41. Image file format
  42. Should contain the characters specified in the glyph_str.
  43. All characters should be placed on one long line. Each glyph will be
  44. found, measured and cropped automatically. In order for this to work,
  45. each glyph must touch pixels somewhere from the left to the right edge.
  46. So if you f.ex have a quotation mark, you will have to make sure there
  47. is pixels with alpha > 0 between the two dots, otherwise the dots will
  48. be identified as different glyphs.
  49. */
  50. class TBBFRenderer : public TBFontRenderer
  51. {
  52. public:
  53. TBBFRenderer();
  54. ~TBBFRenderer();
  55. bool Load(const char *filename, int size);
  56. bool FindGlyphs();
  57. GLYPH *FindNext(UCS4 cp, int x);
  58. virtual TBFontFace *Create(TBFontManager *font_manager, const char *filename,
  59. const TBFontDescription &font_desc);
  60. virtual TBFontMetrics GetMetrics();
  61. virtual bool RenderGlyph(TBFontGlyphData *dst_bitmap, UCS4 cp);
  62. virtual void GetGlyphMetrics(TBGlyphMetrics *metrics, UCS4 cp);
  63. private:
  64. TBNode m_node;
  65. TBFontMetrics m_metrics;
  66. TBImageLoader *m_img;
  67. int m_size;
  68. int m_x_ofs;
  69. int m_advance_delta;
  70. int m_space_advance;
  71. int m_rgb;
  72. TBHashTableAutoDeleteOf<GLYPH> m_glyph_table;
  73. };
  74. TBBFRenderer::TBBFRenderer()
  75. : m_img(nullptr)
  76. , m_size(0)
  77. , m_x_ofs(0)
  78. , m_advance_delta(0)
  79. , m_space_advance(0)
  80. , m_rgb(0)
  81. {
  82. }
  83. TBBFRenderer::~TBBFRenderer()
  84. {
  85. delete m_img;
  86. }
  87. TBFontMetrics TBBFRenderer::GetMetrics()
  88. {
  89. return m_metrics;
  90. }
  91. bool TBBFRenderer::RenderGlyph(TBFontGlyphData *data, UCS4 cp)
  92. {
  93. if (cp == ' ')
  94. return false;
  95. GLYPH *glyph;
  96. if ((glyph = m_glyph_table.Get(cp)) ||
  97. (glyph = m_glyph_table.Get('?')))
  98. {
  99. data->w = glyph->w;
  100. data->h = m_img->Height();
  101. data->stride = m_img->Width();
  102. data->data32 = m_img->Data() + glyph->x;
  103. data->rgb = m_rgb ? true : false;
  104. return true;
  105. }
  106. return false;
  107. }
  108. void TBBFRenderer::GetGlyphMetrics(TBGlyphMetrics *metrics, UCS4 cp)
  109. {
  110. metrics->x = m_x_ofs;
  111. metrics->y = -m_metrics.ascent;
  112. if (cp == ' ')
  113. metrics->advance = m_space_advance;
  114. else if (GLYPH *glyph = m_glyph_table.Get(cp))
  115. metrics->advance = glyph->w + m_advance_delta;
  116. else if (GLYPH *glyph = m_glyph_table.Get('?'))
  117. metrics->advance = glyph->w + m_advance_delta;
  118. }
  119. bool TBBFRenderer::Load(const char *filename, int size)
  120. {
  121. m_size = size;
  122. if (!m_node.ReadFile(filename))
  123. return false;
  124. // Check for size nodes and get the one closest to the size we want.
  125. TBNode *size_node = nullptr;
  126. for (TBNode *n = m_node.GetFirstChild(); n; n = n->GetNext())
  127. {
  128. if (strcmp(n->GetName(), "size") == 0)
  129. {
  130. if (!size_node || ABS(m_size - n->GetValue().GetInt()) < ABS(m_size - size_node->GetValue().GetInt()))
  131. size_node = n;
  132. }
  133. }
  134. if (!size_node)
  135. return false;
  136. // Metrics
  137. m_metrics.ascent = size_node->GetValueInt("ascent", 0);
  138. m_metrics.descent = size_node->GetValueInt("descent", 0);
  139. m_metrics.height = m_metrics.ascent + m_metrics.descent;
  140. // Other data
  141. m_advance_delta = size_node->GetValueInt("advance_delta", 0);
  142. m_space_advance = size_node->GetValueInt("space_advance", 0);
  143. m_x_ofs = size_node->GetValueInt("x_ofs", 0);
  144. // Info
  145. m_rgb = m_node.GetValueInt("info>rgb", 0);
  146. // Get the path for the bitmap file.
  147. TBTempBuffer bitmap_filename;
  148. if (!bitmap_filename.AppendPath(filename))
  149. return false;
  150. // Append the bitmap filename for the given size.
  151. bitmap_filename.AppendString(size_node->GetValueString("bitmap", ""));
  152. m_img = TBImageLoader::CreateFromFile(bitmap_filename.GetData());
  153. return FindGlyphs();
  154. }
  155. inline unsigned char GetAlpha(uint32 color)
  156. {
  157. return (color & 0xff000000) >> 24;
  158. }
  159. bool TBBFRenderer::FindGlyphs()
  160. {
  161. if (!m_img)
  162. return false;
  163. const char *glyph_str = m_node.GetValueString("info>glyph_str", nullptr);
  164. if (!glyph_str)
  165. return false;
  166. int glyph_str_len = strlen(glyph_str);
  167. int i = 0;
  168. int x = 0;
  169. while (UCS4 uc = utf8::decode_next(glyph_str, &i, glyph_str_len))
  170. {
  171. if (GLYPH *glyph = FindNext(uc, x))
  172. {
  173. m_glyph_table.Add(uc, glyph); // OOM!
  174. x = glyph->x + glyph->w + 1;
  175. }
  176. else
  177. break;
  178. }
  179. return true;
  180. }
  181. GLYPH *TBBFRenderer::FindNext(UCS4 cp, int x)
  182. {
  183. int width = m_img->Width();
  184. int height = m_img->Height();
  185. uint32 *data32 = m_img->Data();
  186. if (x >= width)
  187. return nullptr;
  188. GLYPH *glyph = new GLYPH;
  189. if (!glyph)
  190. return nullptr;
  191. glyph->x = -1;
  192. glyph->w = -1;
  193. // Find the left edge of the glyph
  194. for (int i = x; i < width && glyph->x == -1; i++)
  195. {
  196. for (int j = 0; j < height; j++)
  197. if (GetAlpha(data32[i + j * width]))
  198. {
  199. glyph->x = x = i;
  200. break;
  201. }
  202. }
  203. // Find the right edge of the glyph
  204. for (int i = x; i < width; i++)
  205. {
  206. int j;
  207. for (j = 0; j < height; j++)
  208. {
  209. if (GetAlpha(data32[i + j * width]))
  210. break;
  211. }
  212. if (j == height) // The whole col was clear, so we found the edge
  213. {
  214. glyph->w = i - glyph->x;
  215. break;
  216. }
  217. }
  218. if (glyph->x == -1 || glyph->w == -1)
  219. {
  220. delete glyph;
  221. return nullptr;
  222. }
  223. return glyph;
  224. }
  225. TBFontFace *TBBFRenderer::Create(TBFontManager *font_manager, const char *filename, const TBFontDescription &font_desc)
  226. {
  227. if (!strstr(filename, ".tb.txt"))
  228. return nullptr;
  229. if (TBBFRenderer *fr = new TBBFRenderer())
  230. {
  231. if (fr->Load(filename, (int) font_desc.GetSize()))
  232. if (TBFontFace *font = new TBFontFace(font_manager->GetGlyphCache(), fr, font_desc))
  233. return font;
  234. delete fr;
  235. }
  236. return nullptr;
  237. }
  238. void register_tbbf_font_renderer()
  239. {
  240. if (TBBFRenderer *fr = new TBBFRenderer)
  241. g_font_manager->AddRenderer(fr);
  242. }
  243. #endif // TB_FONT_RENDERER_TBBF