ResFontFT.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. #include "ResFontFT.h"
  2. #include "oxygine/res/Resources.h"
  3. #include "oxygine/Font.h"
  4. #include "oxygine/res/CreateResourceContext.h"
  5. #include "oxygine/core/NativeTexture.h"
  6. #include "oxygine/Image.h"
  7. #include "oxygine/core/ImageDataOperations.h"
  8. #include "oxygine/core/VideoDriver.h"
  9. #include "ft2build.h"
  10. #include FT_FREETYPE_H
  11. #ifdef _MSC_VER
  12. typedef unsigned __int8 uint8_t;
  13. typedef unsigned __int32 uint32_t;
  14. #else
  15. #include <stdint.h>
  16. #endif
  17. #define ASCII_IN_TABLE 1
  18. static const uint8_t utf8d[] =
  19. {
  20. #if ASCII_IN_TABLE
  21. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  22. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  23. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  24. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  25. #endif
  26. 070, 070, 070, 070, 070, 070, 070, 070, 070, 070, 070, 070, 070, 070, 070, 070,
  27. 050, 050, 050, 050, 050, 050, 050, 050, 050, 050, 050, 050, 050, 050, 050, 050,
  28. 030, 030, 030, 030, 030, 030, 030, 030, 030, 030, 030, 030, 030, 030, 030, 030,
  29. 030, 030, 030, 030, 030, 030, 030, 030, 030, 030, 030, 030, 030, 030, 030, 030,
  30. 204, 204, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188,
  31. 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188,
  32. 174, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 142, 126, 126,
  33. 111, 95, 95, 95, 79, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207,
  34. 0, 1, 1, 1, 8, 7, 6, 4, 5, 4, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  35. 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  36. 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  37. 1, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  38. 1, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 8, 7, 6, 4, 5, 4, 3, 2, 1, 1, 1, 1,
  39. };
  40. uint32_t decodeSymbol(int sym)
  41. {
  42. int symArr[] = { sym, 0 };
  43. uint8_t* s = (uint8_t*)symArr;
  44. uint8_t data, byte, stat = 9;
  45. uint32_t unic = 0;
  46. while ((byte = *s++))
  47. {
  48. // Each byte is associated with a character class and a mask;
  49. // The character class is used to advance a finite automaton;
  50. // The mask is used to strip off leading bits from the byte;
  51. // The remaining bits are combined into a Unicode code point;
  52. // A code point is complete if the DFA enters the final state.
  53. #if ASCII_IN_TABLE
  54. data = utf8d[byte];
  55. stat = utf8d[256 + (stat << 4) + (data >> 4)];
  56. byte = (byte ^ (uint8_t)(data << 4));
  57. #else
  58. if (byte < 0x80)
  59. {
  60. stat = utf8d[128 + (stat << 4)];
  61. }
  62. else
  63. {
  64. data = utf8d[byte - 0x80];
  65. stat = utf8d[128 + (stat << 4) + (data >> 4)];
  66. byte = (byte ^ (uint8_t)(data << 4));
  67. }
  68. #endif
  69. unic = (unic << 6) | byte;
  70. if (!stat)
  71. {
  72. // unic is now a proper code point, we just print it out.
  73. //printf("U+%04X\n", unic);
  74. return unic;
  75. }
  76. if (stat == 1)
  77. {
  78. // the byte is not allowed here; the state would have to
  79. // be reset to continue meaningful reading of the string
  80. }
  81. }
  82. return 0;
  83. }
  84. namespace oxygine
  85. {
  86. FT_Library _library = 0;
  87. static int FT_SNAP_SIZE = 1000;
  88. static int FT_MAX_SNAP_SIZE = 200;
  89. static float FT_GLOBAL_WORLD_SCALE = 0.0f;
  90. static oxygine::Point FT_ATLAS_SIZE(512, 512);
  91. void ftGenDefault(ResFontFT::postProcessData& data)
  92. {
  93. Image& dest = *data.dest;
  94. const ImageData& src = *data.src;
  95. dest.init(src.w, src.h, TF_R8G8B8A8);
  96. ImageData rc = dest.lock();
  97. operations::blitPremultiply(src, rc);
  98. }
  99. static ResFontFT::postProcessHook _ftGen = ftGenDefault;
  100. void ResFontFT::setGlyphPostProcessor(postProcessHook f)
  101. {
  102. _ftGen = f;
  103. }
  104. Image tempImage;
  105. class FontFT : public Font
  106. {
  107. public:
  108. FontFT(ResFontFT* rs, int size) : _rs(rs), _size(size)
  109. {
  110. OX_ASSERT(size > 0);
  111. if (size <= 0)
  112. size = 10;
  113. _ignoreOptions = false;
  114. FT_Face face = _rs->_face;
  115. FT_Set_Pixel_Sizes(_rs->_face, 0, size);
  116. int dist = (int)(face->size->metrics.height / 64);
  117. int mxadv = dist;// face->size->metrics.max_advance / 64;
  118. init("abc", size, dist, mxadv);
  119. #if !defined(_MSC_VER) || (_MSC_VER >= 1900)
  120. _glyphs.reserve(100);
  121. #endif
  122. }
  123. protected:
  124. ResFontFT* _rs;
  125. int _size;
  126. bool loadGlyph(int code, glyph& g, const glyphOptions& opt) override
  127. {
  128. FT_Face face = _rs->_face;
  129. FT_Set_Pixel_Sizes(_rs->_face, 0, _size);
  130. /* load glyph image into the slot (erase previous one) */
  131. int sm = decodeSymbol(code);
  132. int error = FT_Load_Char(face, sm, FT_LOAD_RENDER);
  133. if (error)
  134. return false;
  135. FT_GlyphSlot slot = face->glyph;
  136. FT_Bitmap bitmap = slot->bitmap;
  137. ImageData src(bitmap.width, bitmap.rows, bitmap.pitch, TF_A8, bitmap.buffer);
  138. Rect srcRect;
  139. spTexture t;
  140. g.advance_x = static_cast<short>(slot->advance.x >> 6);
  141. g.advance_y = static_cast<short>(slot->advance.y >> 6);
  142. g.offset_x = slot->bitmap_left;
  143. g.offset_y = -slot->bitmap_top;
  144. g.ch = code;
  145. g.opt = opt;
  146. //if (src.w && src.h)
  147. {
  148. ResFontFT::postProcessData gd;
  149. gd.src = &src;
  150. gd.dest = &tempImage;
  151. gd.gl = &g;
  152. gd.opt = opt;
  153. gd.font = this;
  154. if (src.w && src.h)
  155. _ftGen(gd);
  156. else
  157. {
  158. tempImage.init(0, 0, TF_R8G8B8A8);
  159. }
  160. _rs->_atlas.add(tempImage.lock(), srcRect, t);
  161. OX_ASSERT(t);
  162. g.src = srcRect.cast<RectF>();
  163. Vector2 sz((float)t->getWidth(), (float)t->getHeight());
  164. g.src.pos = g.src.pos.div(sz);
  165. g.src.size = g.src.size.div(sz);
  166. g.texture = safeSpCast<NativeTexture>(t);
  167. }
  168. g.sw = tempImage.getWidth();
  169. g.sh = tempImage.getHeight();
  170. return true;
  171. }
  172. };
  173. Resource* ResFontFT::createResource(CreateResourceContext& context)
  174. {
  175. ResFontFT* res = new ResFontFT;
  176. pugi::xml_node node = context.walker.getNode();
  177. setNode(res, node);
  178. std::string file = context.walker.getPath("file");
  179. res->setName(Resource::extractID(node, file, ""));
  180. res->init(file);
  181. context.resources->add(res);
  182. return res;
  183. }
  184. void ResFontFT::initLibrary()
  185. {
  186. Resources::registerResourceType(&ResFontFT::createResource, "ftfont");
  187. FT_Init_FreeType(&_library);
  188. }
  189. void ResFontFT::freeLibrary()
  190. {
  191. FT_Done_FreeType(_library);
  192. Resources::unregisterResourceType("ftfont");
  193. }
  194. int ResFontFT::getSnapSize()
  195. {
  196. return FT_SNAP_SIZE;
  197. }
  198. void ResFontFT::setSnapSize(int size)
  199. {
  200. FT_SNAP_SIZE = size;
  201. }
  202. void ResFontFT::setMaxSnapSize(int size)
  203. {
  204. FT_MAX_SNAP_SIZE = size;
  205. }
  206. void ResFontFT::setAtlasSize(int w, int h)
  207. {
  208. FT_ATLAS_SIZE = Point(w, h);
  209. }
  210. void ResFontFT::setGlobalWorldScale(float s)
  211. {
  212. FT_GLOBAL_WORLD_SCALE = s;
  213. }
  214. ResFontFT::ResFontFT() : _atlas(CLOSURE(this, &ResFontFT::createTexture)), _face(0)
  215. {
  216. _atlas.init();
  217. }
  218. ResFontFT::~ResFontFT()
  219. {
  220. }
  221. spTexture ResFontFT::createTexture(int w, int h)
  222. {
  223. Image mt;
  224. mt.init(FT_ATLAS_SIZE.x, FT_ATLAS_SIZE.y, TF_R8G8B8A8);
  225. mt.fillZero();
  226. spNativeTexture texture = IVideoDriver::instance->createTexture();
  227. texture->init(mt.lock());
  228. return texture;
  229. }
  230. void ResFontFT::init(const std::string& fnt)
  231. {
  232. file::read(fnt.c_str(), _fdata);
  233. int error = FT_New_Memory_Face(_library,
  234. reinterpret_cast<const unsigned char*>(_fdata.getData()), _fdata.getSize(), 0, &_face);
  235. OX_ASSERT(!error);
  236. //_fonts.push_back(FontFT(this, 32));
  237. }
  238. Font* ResFontFT::getFont(int size)
  239. {
  240. OX_ASSERT(size >= 0);
  241. if (size <= 0)
  242. size = 10;
  243. for (fonts::iterator i = _fonts.begin(); i != _fonts.end(); ++i)
  244. {
  245. FontFT& f = *i;
  246. if (f.getSize() == size)
  247. return &f;
  248. }
  249. _fonts.push_back(FontFT(this, size));
  250. return &_fonts.back();
  251. }
  252. const Font* ResFontFT::getFont(const char* name, int size) const
  253. {
  254. //OX_ASSERT(size > 0);
  255. ResFontFT* r = const_cast<ResFontFT*>(this);
  256. return r->getFont(size);
  257. }
  258. const oxygine::Font* ResFontFT::getClosestFont(float worldScale, int styleFontSize, float& resScale) const
  259. {
  260. if (FT_GLOBAL_WORLD_SCALE != 0.0f)
  261. worldScale = FT_GLOBAL_WORLD_SCALE;
  262. int fontSize = (int)(styleFontSize * worldScale);
  263. if (!fontSize)
  264. return 0;
  265. if (fontSize > FT_SNAP_SIZE)
  266. {
  267. int x = fontSize + FT_SNAP_SIZE - 1;
  268. fontSize = x - (x % FT_SNAP_SIZE);
  269. fontSize = std::min(fontSize, FT_MAX_SNAP_SIZE);
  270. }
  271. resScale = (float)fontSize / styleFontSize;
  272. return getFont(0, fontSize);
  273. }
  274. void ResFontFT::_load(LoadResourcesContext* context)
  275. {
  276. }
  277. void ResFontFT::_unload()
  278. {
  279. }
  280. }