Open Source Tomb Raider Engine
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

FontTTF.cpp 7.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. /*!
  2. * \file src/system/FontTTF.cpp
  3. * \brief TrueType Font Implementation
  4. *
  5. * \author xythobuz
  6. */
  7. #include <fstream>
  8. #include "global.h"
  9. #include "Log.h"
  10. #include "TextureManager.h"
  11. #include "utils/pixel.h"
  12. #include "system/FontTTF.h"
  13. #define MAP_WIDTH 512
  14. #define MAP_HEIGHT 512
  15. #define FONT_SIZE 33
  16. #define MAP_NUM_CHARS 100
  17. FontMapTTF::FontMapTTF() : begin(-1), texture(-1), charInfo(nullptr) { }
  18. FontMapTTF::FontMapTTF(FontMapTTF&& other) {
  19. begin = other.begin;
  20. texture = other.texture;
  21. other.begin = other.texture = -1;
  22. charInfo = other.charInfo;
  23. other.charInfo = nullptr;
  24. }
  25. FontMapTTF::~FontMapTTF() {
  26. if (charInfo != nullptr) {
  27. delete [] charInfo;
  28. }
  29. if (texture > -1) {
  30. //! \fixme Free the TextureManager buffer slot
  31. }
  32. }
  33. int FontMapTTF::initialize(unsigned char* fontData, int firstChar) {
  34. stbtt_pack_context context;
  35. unsigned char* pixels = new unsigned char[MAP_WIDTH * MAP_HEIGHT];
  36. if (!stbtt_PackBegin(&context, pixels, MAP_WIDTH, MAP_HEIGHT, 0, 1, nullptr)) {
  37. delete [] pixels;
  38. Log::get(LOG_ERROR) << "Error initializing font map in stbtt_PackBegin!" << Log::endl;
  39. return -1;
  40. }
  41. stbtt_PackSetOversampling(&context, 2, 2);
  42. if (charInfo != nullptr)
  43. delete [] charInfo;
  44. charInfo = new stbtt_packedchar[MAP_NUM_CHARS];
  45. if (!stbtt_PackFontRange(&context, fontData, 0, FONT_SIZE, firstChar, MAP_NUM_CHARS, charInfo)) {
  46. stbtt_PackEnd(&context);
  47. delete [] pixels;
  48. delete [] charInfo;
  49. charInfo = nullptr;
  50. Log::get(LOG_ERROR) << "Error packing font map!" << Log::endl;
  51. return -2;
  52. }
  53. stbtt_PackEnd(&context);
  54. unsigned char* rgb = grayscale2rgba(pixels, MAP_WIDTH, MAP_HEIGHT);
  55. delete [] pixels;
  56. texture = TextureManager::loadBufferSlot(rgb, MAP_WIDTH, MAP_HEIGHT, ColorMode::RGBA,
  57. 32, TextureStorage::SYSTEM, texture);
  58. delete [] rgb;
  59. if (texture < 0) {
  60. delete [] charInfo;
  61. charInfo = nullptr;
  62. Log::get(LOG_ERROR) << "Error loading new font map texture!" << Log::endl;
  63. return -3;
  64. }
  65. begin = firstChar;
  66. return 0;
  67. }
  68. bool FontMapTTF::contains(int c) {
  69. orAssert(begin >= 0);
  70. return (begin >= 0) && (c >= begin) && (c < (begin + MAP_NUM_CHARS));
  71. }
  72. void FontMapTTF::getQuad(int c, float* xpos, float* ypos, stbtt_aligned_quad* quad) {
  73. orAssert(contains(c));
  74. stbtt_GetPackedQuad(charInfo, MAP_WIDTH, MAP_HEIGHT, c - begin, xpos, ypos, quad, 0);
  75. }
  76. // ----------------------------------------------------------------------------
  77. unsigned char* FontTTF::fontData = nullptr;
  78. std::vector<FontMapTTF> FontTTF::maps;
  79. ShaderBuffer FontTTF::vertexBuffer;
  80. ShaderBuffer FontTTF::uvBuffer;
  81. int FontTTF::initialize(std::string f) {
  82. orAssert(f.length() > 0);
  83. std::ifstream file(f, std::ios::binary);
  84. if (!file) {
  85. Log::get(LOG_ERROR) << "Couldn't open file \"" << f << "\"!" << Log::endl;
  86. return -1;
  87. }
  88. file.seekg(0, std::ios::end);
  89. auto size = file.tellg();
  90. orAssert(size > 0);
  91. file.seekg(0);
  92. maps.clear();
  93. if (fontData != nullptr) {
  94. delete [] fontData;
  95. fontData = nullptr;
  96. }
  97. fontData = new unsigned char[size];
  98. if (!file.read(reinterpret_cast<char*>(fontData), size)) {
  99. Log::get(LOG_ERROR) << "Couldn't read data in \"" << f << "\"" << Log::endl;
  100. delete [] fontData;
  101. fontData = nullptr;
  102. return -2;
  103. }
  104. maps.emplace_back();
  105. if (maps.at(0).initialize(fontData, ' ') < 0) {
  106. delete [] fontData;
  107. fontData = nullptr;
  108. return -3;
  109. }
  110. return 0;
  111. }
  112. void FontTTF::shutdown() {
  113. if (fontData != nullptr) {
  114. delete [] fontData;
  115. fontData = nullptr;
  116. }
  117. maps.clear();
  118. }
  119. unsigned int FontTTF::widthText(float scale, std::string s) {
  120. float x = 0.0f, y = 0.0f;
  121. stbtt_aligned_quad q;
  122. for (int i = 0; i < s.length(); i++) {
  123. if ((s[i] < 0x20) || (s[i] == 0x7F)) {
  124. continue;
  125. }
  126. getQuad(s[i], &x, &y, &q);
  127. }
  128. return x * scale;
  129. }
  130. void FontTTF::drawText(unsigned int x, unsigned int y, float scale,
  131. glm::vec4 color, std::string s) {
  132. drawTextInternal(x, y, scale, color, 0, s, false);
  133. }
  134. unsigned int FontTTF::heightText(float scale, unsigned int maxWidth, std::string s) {
  135. float x = 0.0f, y = FONT_SIZE;
  136. stbtt_aligned_quad q;
  137. for (int i = 0; i < s.length(); i++) {
  138. if ((s[i] < 0x20) || (s[i] == 0x7F)) {
  139. continue;
  140. }
  141. getQuad(s[i], &x, &y, &q);
  142. if (x > maxWidth) {
  143. x = 0.0f;
  144. y += FONT_SIZE;
  145. }
  146. }
  147. return y * scale;
  148. }
  149. void FontTTF::drawTextWrapped(unsigned int x, unsigned int y, float scale,
  150. glm::vec4 color, unsigned int maxWidth, std::string s) {
  151. drawTextInternal(x, y, scale, color, maxWidth, s, true);
  152. }
  153. void FontTTF::drawTextInternal(unsigned int x, unsigned int y, float scale,
  154. glm::vec4 color, unsigned int maxWidth, std::string s,
  155. bool drawWrapped) {
  156. std::vector<glm::vec2> vertices;
  157. std::vector<glm::vec2> uvs;
  158. int texture = -1;
  159. float xpos = x, ypos = y + (FONT_SIZE * scale);
  160. for (int i = 0; i < s.length(); i++) {
  161. if ((s[i] < 0x20) || (s[i] == 0x7F)) {
  162. continue;
  163. }
  164. stbtt_aligned_quad quad;
  165. int tex = getQuad(s[i], &xpos, &ypos, &quad);
  166. if (drawWrapped && (xpos > (x + maxWidth))) {
  167. xpos = x;
  168. ypos += FONT_SIZE * scale;
  169. if (s[i] != ' ')
  170. i--;
  171. continue;
  172. }
  173. if ((texture != tex) && (texture != -1)) {
  174. vertexBuffer.bufferData(vertices);
  175. uvBuffer.bufferData(uvs);
  176. Shader::drawGL(vertexBuffer, uvBuffer, color, texture);
  177. vertices.clear();
  178. uvs.clear();
  179. }
  180. texture = tex;
  181. float xmin = quad.x0;
  182. float xmax = quad.x0 + ((quad.x1 - quad.x0) * scale);
  183. float ymin = quad.y1;
  184. float ymax = quad.y1 + ((quad.y0 - quad.y1) * scale);
  185. vertices.emplace_back(xmin, ymin);
  186. vertices.emplace_back(xmin, ymax);
  187. vertices.emplace_back(xmax, ymax);
  188. vertices.emplace_back(xmax, ymin);
  189. vertices.emplace_back(xmin, ymin);
  190. vertices.emplace_back(xmax, ymax);
  191. uvs.emplace_back(quad.s0, quad.t1);
  192. uvs.emplace_back(quad.s0, quad.t0);
  193. uvs.emplace_back(quad.s1, quad.t0);
  194. uvs.emplace_back(quad.s1, quad.t1);
  195. uvs.emplace_back(quad.s0, quad.t1);
  196. uvs.emplace_back(quad.s1, quad.t0);
  197. }
  198. vertexBuffer.bufferData(vertices);
  199. uvBuffer.bufferData(uvs);
  200. Shader::drawGL(vertexBuffer, uvBuffer, color, texture);
  201. }
  202. int FontTTF::charIsMapped(int c) {
  203. for (int i = 0; i < maps.size(); i++) {
  204. if (maps.at(i).contains(c)) {
  205. return i;
  206. }
  207. }
  208. int begin = c;
  209. if (c >= (MAP_NUM_CHARS / 2))
  210. begin -= (MAP_NUM_CHARS / 2);
  211. Log::get(LOG_INFO) << "Unmapped character '" << char(c) << "', new map from " << begin << " to "
  212. << begin + MAP_NUM_CHARS - 1 << "..." << Log::endl;
  213. int p = maps.size();
  214. maps.emplace_back();
  215. if (maps.at(p).initialize(fontData, begin) < 0) {
  216. return -1;
  217. }
  218. return p;
  219. }
  220. int FontTTF::getQuad(int c, float* xpos, float* ypos, stbtt_aligned_quad* quad) {
  221. if (c < 0) {
  222. //! \fixme This has nothing to do with proper UTF8 support...
  223. c += 128;
  224. }
  225. int map = charIsMapped(c);
  226. orAssert(map >= 0);
  227. maps.at(map).getQuad(c, xpos, ypos, quad);
  228. return maps.at(map).getTexture();
  229. }