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 9.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  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 30
  16. #define MAP_NUM_CHARS 50
  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. //! \todo _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. getLog() << "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. getLog() << "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. getLog() << "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. assert(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. assert(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. assert(f.length() > 0);
  83. std::ifstream file(f, std::ios::binary);
  84. if (!file) {
  85. getLog() << "Couldn't open file \"" << f << "\"!" << Log::endl;
  86. return -1;
  87. }
  88. file.seekg(0, std::ios::end);
  89. auto size = file.tellg();
  90. assert(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. getLog() << "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. const unsigned char color[4], std::string s) {
  132. glm::vec4 col(color[0] / 256.0f, color[1] / 256.0f, color[2] / 256.0f, color[3] / 256.0f);
  133. std::vector<glm::vec2> vertices;
  134. std::vector<glm::vec2> uvs;
  135. int texture = -1;
  136. float xpos = x, ypos = y + (FONT_SIZE * scale);
  137. for (int i = 0; i < s.length(); i++) {
  138. if ((s[i] < 0x20) || (s[i] == 0x7F)) {
  139. continue;
  140. }
  141. stbtt_aligned_quad quad;
  142. int tex = getQuad(s[i], &xpos, &ypos, &quad);
  143. if ((texture != tex) && (texture != -1)) {
  144. vertexBuffer.bufferData(vertices);
  145. uvBuffer.bufferData(uvs);
  146. Shader::drawGL(vertexBuffer, uvBuffer, col, texture);
  147. vertices.clear();
  148. uvs.clear();
  149. }
  150. texture = tex;
  151. glm::vec2 v1(quad.x0, quad.y0);
  152. glm::vec2 v2(quad.x0, quad.y0 + ((quad.y1 - quad.y0) * scale));
  153. glm::vec2 v3(quad.x0 + ((quad.x1 - quad.x0) * scale), quad.y0 + ((quad.y1 - quad.y0) * scale));
  154. glm::vec2 v4(quad.x0 + ((quad.x1 - quad.x0) * scale), quad.y0);
  155. glm::vec2 u1(quad.s0, quad.t0);
  156. glm::vec2 u2(quad.s0, quad.t1);
  157. glm::vec2 u3(quad.s1, quad.t1);
  158. glm::vec2 u4(quad.s1, quad.t0);
  159. vertices.push_back(v1);
  160. vertices.push_back(v2);
  161. vertices.push_back(v3);
  162. vertices.push_back(v4);
  163. vertices.push_back(v1);
  164. vertices.push_back(v3);
  165. uvs.push_back(u1);
  166. uvs.push_back(u2);
  167. uvs.push_back(u3);
  168. uvs.push_back(u4);
  169. uvs.push_back(u1);
  170. uvs.push_back(u3);
  171. }
  172. vertexBuffer.bufferData(vertices);
  173. uvBuffer.bufferData(uvs);
  174. Shader::drawGL(vertexBuffer, uvBuffer, col, texture);
  175. }
  176. unsigned int FontTTF::heightText(float scale, unsigned int maxWidth, std::string s) {
  177. float x = 0.0f, y = FONT_SIZE;
  178. stbtt_aligned_quad q;
  179. for (int i = 0; i < s.length(); i++) {
  180. if ((s[i] < 0x20) || (s[i] == 0x7F)) {
  181. continue;
  182. }
  183. getQuad(s[i], &x, &y, &q);
  184. if (x > maxWidth) {
  185. x = 0.0f;
  186. y += FONT_SIZE;
  187. }
  188. }
  189. return y * scale;
  190. }
  191. void FontTTF::drawTextWrapped(unsigned int x, unsigned int y, float scale,
  192. const unsigned char color[4], unsigned int maxWidth, std::string s) {
  193. glm::vec4 col(color[0] / 256.0f, color[1] / 256.0f, color[2] / 256.0f, color[3] / 256.0f);
  194. std::vector<glm::vec2> vertices;
  195. std::vector<glm::vec2> uvs;
  196. int texture = -1;
  197. float xpos = x, ypos = y + (FONT_SIZE * scale);
  198. for (int i = 0; i < s.length(); i++) {
  199. if ((s[i] < 0x20) || (s[i] == 0x7F)) {
  200. continue;
  201. }
  202. stbtt_aligned_quad quad;
  203. int tex = getQuad(s[i], &xpos, &ypos, &quad);
  204. if (xpos > (x + maxWidth)) {
  205. xpos = x;
  206. ypos += FONT_SIZE * scale;
  207. if (s[i] != ' ')
  208. i--;
  209. continue;
  210. }
  211. if ((texture != tex) && (texture != -1)) {
  212. vertexBuffer.bufferData(vertices);
  213. uvBuffer.bufferData(uvs);
  214. Shader::drawGL(vertexBuffer, uvBuffer, col, texture);
  215. vertices.clear();
  216. uvs.clear();
  217. }
  218. texture = tex;
  219. glm::vec2 v1(quad.x0, quad.y0);
  220. glm::vec2 v2(quad.x0, quad.y0 + ((quad.y1 - quad.y0) * scale));
  221. glm::vec2 v3(quad.x0 + ((quad.x1 - quad.x0) * scale), quad.y0 + ((quad.y1 - quad.y0) * scale));
  222. glm::vec2 v4(quad.x0 + ((quad.x1 - quad.x0) * scale), quad.y0);
  223. glm::vec2 u1(quad.s0, quad.t0);
  224. glm::vec2 u2(quad.s0, quad.t1);
  225. glm::vec2 u3(quad.s1, quad.t1);
  226. glm::vec2 u4(quad.s1, quad.t0);
  227. vertices.push_back(v1);
  228. vertices.push_back(v2);
  229. vertices.push_back(v3);
  230. vertices.push_back(v4);
  231. vertices.push_back(v1);
  232. vertices.push_back(v3);
  233. uvs.push_back(u1);
  234. uvs.push_back(u2);
  235. uvs.push_back(u3);
  236. uvs.push_back(u4);
  237. uvs.push_back(u1);
  238. uvs.push_back(u3);
  239. }
  240. vertexBuffer.bufferData(vertices);
  241. uvBuffer.bufferData(uvs);
  242. Shader::drawGL(vertexBuffer, uvBuffer, col, texture);
  243. }
  244. int FontTTF::charIsMapped(int c) {
  245. for (int i = 0; i < maps.size(); i++) {
  246. if (maps.at(i).contains(c)) {
  247. return i;
  248. }
  249. }
  250. int begin = c;
  251. if (c >= (MAP_NUM_CHARS / 2))
  252. begin -= (MAP_NUM_CHARS / 2);
  253. getLog() << "Unmapped character " << c << ", new map from " << begin << " to "
  254. << begin + MAP_NUM_CHARS - 1 << "..." << Log::endl;
  255. int p = maps.size();
  256. maps.emplace_back();
  257. if (maps.at(p).initialize(fontData, begin) < 0) {
  258. return -1;
  259. }
  260. return p;
  261. }
  262. int FontTTF::getQuad(int c, float* xpos, float* ypos, stbtt_aligned_quad *quad) {
  263. if (c < 0) {
  264. //! \todo This has nothing to do with proper UTF8 support...
  265. c += 128;
  266. }
  267. int map = charIsMapped(c);
  268. assert(map >= 0);
  269. maps.at(map).getQuad(c, xpos, ypos, quad);
  270. return maps.at(map).getTexture();
  271. }