Font.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. /**
  2. * Copyright (c) 2006-2013 LOVE Development Team
  3. *
  4. * This software is provided 'as-is', without any express or implied
  5. * warranty. In no event will the authors be held liable for any damages
  6. * arising from the use of this software.
  7. *
  8. * Permission is granted to anyone to use this software for any purpose,
  9. * including commercial applications, and to alter it and redistribute it
  10. * freely, subject to the following restrictions:
  11. *
  12. * 1. The origin of this software must not be misrepresented; you must not
  13. * claim that you wrote the original software. If you use this software
  14. * in a product, an acknowledgment in the product documentation would be
  15. * appreciated but is not required.
  16. * 2. Altered source versions must be plainly marked as such, and must not be
  17. * misrepresented as being the original software.
  18. * 3. This notice may not be removed or altered from any source distribution.
  19. **/
  20. #include "common/config.h"
  21. #include "Font.h"
  22. #include "font/GlyphData.h"
  23. #include "modules/graphics/Geometry.h"
  24. #include "Image.h"
  25. #include "libraries/utf8/utf8.h"
  26. #include "common/math.h"
  27. #include "common/Matrix.h"
  28. #include <math.h>
  29. #include <sstream>
  30. #include <algorithm> // for max
  31. namespace love
  32. {
  33. namespace graphics
  34. {
  35. namespace opengl
  36. {
  37. const int Font::TEXTURE_WIDTHS[] = {128, 256, 256, 512, 512, 1024, 1024};
  38. const int Font::TEXTURE_HEIGHTS[] = {128, 128, 256, 256, 512, 512, 1024};
  39. Font::Font(love::font::Rasterizer *r, const Image::Filter &filter)
  40. : rasterizer(r)
  41. , height(r->getHeight())
  42. , lineHeight(1)
  43. , mSpacing(1)
  44. , filter(filter)
  45. {
  46. this->filter.mipmap = Image::FILTER_NONE;
  47. // Try to find the best texture size match for the font size. default to the
  48. // largest texture size if no rough match is found.
  49. textureSizeIndex = NUM_TEXTURE_SIZES - 1;
  50. for (int i = 0; i < NUM_TEXTURE_SIZES; i++)
  51. {
  52. // Make a rough estimate of the total used texture size, based on glyph
  53. // height. The estimated size is likely larger than the actual total
  54. // size, which is good because texture switching is expensive.
  55. if ((height * 0.8) * height * 95 <= TEXTURE_WIDTHS[i] * TEXTURE_HEIGHTS[i])
  56. {
  57. textureSizeIndex = i;
  58. break;
  59. }
  60. }
  61. textureWidth = TEXTURE_WIDTHS[textureSizeIndex];
  62. textureHeight = TEXTURE_HEIGHTS[textureSizeIndex];
  63. love::font::GlyphData *gd = 0;
  64. try
  65. {
  66. gd = r->getGlyphData(32);
  67. type = (gd->getFormat() == love::font::GlyphData::FORMAT_LUMINANCE_ALPHA) ? FONT_TRUETYPE : FONT_IMAGE;
  68. loadVolatile();
  69. }
  70. catch (love::Exception &)
  71. {
  72. delete gd;
  73. throw;
  74. }
  75. delete gd;
  76. rasterizer->retain();
  77. }
  78. Font::~Font()
  79. {
  80. rasterizer->release();
  81. unloadVolatile();
  82. }
  83. bool Font::initializeTexture(GLint format)
  84. {
  85. GLint internalformat = (format == GL_LUMINANCE_ALPHA) ? GL_LUMINANCE8_ALPHA8 : GL_RGBA8;
  86. // clear errors before initializing
  87. while (glGetError() != GL_NO_ERROR);
  88. glTexImage2D(GL_TEXTURE_2D,
  89. 0,
  90. internalformat,
  91. (GLsizei)textureWidth,
  92. (GLsizei)textureHeight,
  93. 0,
  94. format,
  95. GL_UNSIGNED_BYTE,
  96. NULL);
  97. return glGetError() == GL_NO_ERROR;
  98. }
  99. void Font::createTexture()
  100. {
  101. textureX = textureY = rowHeight = TEXTURE_PADDING;
  102. GLuint t;
  103. glGenTextures(1, &t);
  104. textures.push_back(t);
  105. gl.bindTexture(t);
  106. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  107. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  108. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  109. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  110. GLint format = (type == FONT_TRUETYPE ? GL_LUMINANCE_ALPHA : GL_RGBA);
  111. // Initialize the texture, attempting smaller sizes if initialization fails.
  112. bool initialized = false;
  113. while (textureSizeIndex >= 0)
  114. {
  115. textureWidth = TEXTURE_WIDTHS[textureSizeIndex];
  116. textureHeight = TEXTURE_HEIGHTS[textureSizeIndex];
  117. initialized = initializeTexture(format);
  118. if (initialized || textureSizeIndex <= 0)
  119. break;
  120. --textureSizeIndex;
  121. }
  122. if (!initialized)
  123. {
  124. // Clean up before throwing.
  125. gl.deleteTexture(t);
  126. gl.bindTexture(0);
  127. textures.pop_back();
  128. throw love::Exception("Could not create font texture!");
  129. }
  130. // Fill the texture with transparent black.
  131. std::vector<GLubyte> emptyData(textureWidth * textureHeight * (type == FONT_TRUETYPE ? 2 : 4), 0);
  132. glTexSubImage2D(GL_TEXTURE_2D,
  133. 0,
  134. 0, 0,
  135. (GLsizei)textureWidth,
  136. (GLsizei)textureHeight,
  137. format,
  138. GL_UNSIGNED_BYTE,
  139. &emptyData[0]);
  140. setFilter(filter);
  141. }
  142. Font::Glyph *Font::addGlyph(uint32 glyph)
  143. {
  144. love::font::GlyphData *gd = rasterizer->getGlyphData(glyph);
  145. int w = gd->getWidth();
  146. int h = gd->getHeight();
  147. if (textureX + w + TEXTURE_PADDING > textureWidth)
  148. {
  149. // out of space - new row!
  150. textureX = TEXTURE_PADDING;
  151. textureY += rowHeight;
  152. rowHeight = TEXTURE_PADDING;
  153. }
  154. if (textureY + h + TEXTURE_PADDING > textureHeight)
  155. {
  156. // totally out of space - new texture!
  157. createTexture();
  158. }
  159. Glyph *g = new Glyph;
  160. g->texture = 0;
  161. g->spacing = gd->getAdvance();
  162. memset(g->vertices, 0, sizeof(GlyphVertex) * 4);
  163. // don't waste space for empty glyphs. also fixes a division by zero bug with ati drivers
  164. if (w > 0 && h > 0)
  165. {
  166. const GLuint t = textures.back();
  167. gl.bindTexture(t);
  168. glTexSubImage2D(GL_TEXTURE_2D,
  169. 0,
  170. textureX,
  171. textureY,
  172. w, h,
  173. (type == FONT_TRUETYPE ? GL_LUMINANCE_ALPHA : GL_RGBA),
  174. GL_UNSIGNED_BYTE,
  175. gd->getData());
  176. g->texture = t;
  177. const GlyphVertex verts[4] = {
  178. { 0.0f, 0.0f, float(textureX)/float(textureWidth), float(textureY)/float(textureHeight)},
  179. {float(w), 0.0f, float(textureX+w)/float(textureWidth), float(textureY)/float(textureHeight)},
  180. {float(w), float(h), float(textureX+w)/float(textureWidth), float(textureY+h)/float(textureHeight)},
  181. { 0.0f, float(h), float(textureX)/float(textureWidth), float(textureY+h)/float(textureHeight)},
  182. };
  183. // copy vertex data to the glyph and set proper bearing
  184. for (int i = 0; i < 4; i++)
  185. {
  186. g->vertices[i] = verts[i];
  187. g->vertices[i].x += gd->getBearingX();
  188. g->vertices[i].y -= gd->getBearingY();
  189. }
  190. }
  191. if (w > 0)
  192. textureX += (w + TEXTURE_PADDING);
  193. if (h > 0)
  194. rowHeight = std::max(rowHeight, h + TEXTURE_PADDING);
  195. delete gd;
  196. glyphs[glyph] = g;
  197. return g;
  198. }
  199. Font::Glyph *Font::findGlyph(uint32 glyph)
  200. {
  201. auto it = glyphs.find(glyph);
  202. if (it != glyphs.end())
  203. return it->second;
  204. else
  205. return addGlyph(glyph);
  206. }
  207. float Font::getHeight() const
  208. {
  209. return static_cast<float>(height);
  210. }
  211. void Font::print(const std::string &text, float x, float y, float extra_spacing, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
  212. {
  213. // Spacing counter and newline handling.
  214. float dx = 0.0f;
  215. float dy = 0.0f;
  216. float lineheight = getBaseline();
  217. // Keeps track of when we need to switch textures in our vertex array.
  218. std::vector<GlyphArrayDrawInfo> glyphinfolist;
  219. // Pre-allocate space for the maximum possible number of vertices.
  220. std::vector<GlyphVertex> glyphverts;
  221. glyphverts.reserve(text.length() * 4);
  222. int vertexcount = 0;
  223. try
  224. {
  225. utf8::iterator<std::string::const_iterator> i(text.begin(), text.begin(), text.end());
  226. utf8::iterator<std::string::const_iterator> end(text.end(), text.begin(), text.end());
  227. while (i != end)
  228. {
  229. uint32 g = *i++;
  230. if (g == '\n')
  231. {
  232. // Wrap newline, but do not print it.
  233. dy += floorf(getHeight() * getLineHeight() + 0.5f);
  234. dx = 0.0f;
  235. continue;
  236. }
  237. Glyph *glyph = findGlyph(g);
  238. if (glyph->texture != 0)
  239. {
  240. // Copy the vertices and set their proper relative positions.
  241. for (int j = 0; j < 4; j++)
  242. {
  243. glyphverts.push_back(glyph->vertices[j]);
  244. glyphverts.back().x += dx;
  245. glyphverts.back().y += dy + lineheight;
  246. }
  247. // Check if glyph texture has changed since the last iteration.
  248. if (glyphinfolist.size() == 0 || glyphinfolist.back().texture != glyph->texture)
  249. {
  250. // keep track of each sub-section of the string whose glyphs use different textures than the previous section
  251. GlyphArrayDrawInfo gdrawinfo;
  252. gdrawinfo.startvertex = vertexcount;
  253. gdrawinfo.vertexcount = 0;
  254. gdrawinfo.texture = glyph->texture;
  255. glyphinfolist.push_back(gdrawinfo);
  256. }
  257. vertexcount += 4;
  258. glyphinfolist.back().vertexcount += 4;
  259. }
  260. // Advance the x position for the next glyph.
  261. dx += glyph->spacing;
  262. // Account for extra spacing given to space characters.
  263. if (g == ' ' && extra_spacing != 0.0f)
  264. dx = floorf(dx + extra_spacing);
  265. }
  266. }
  267. catch (utf8::exception &e)
  268. {
  269. throw love::Exception("Decoding error: %s", e.what());
  270. }
  271. if (vertexcount <= 0 || glyphinfolist.size() == 0)
  272. return;
  273. // Sort glyph draw info list by texture first, and quad position in memory
  274. // second (using the struct's < operator).
  275. std::sort(glyphinfolist.begin(), glyphinfolist.end());
  276. glPushMatrix();
  277. Matrix t;
  278. t.setTransformation(ceilf(x), ceilf(y), angle, sx, sy, ox, oy, kx, ky);
  279. glMultMatrixf((const GLfloat *)t.getElements());
  280. glEnableClientState(GL_VERTEX_ARRAY);
  281. glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  282. glVertexPointer(2, GL_FLOAT, sizeof(GlyphVertex), (GLvoid *)&glyphverts[0].x);
  283. glTexCoordPointer(2, GL_FLOAT, sizeof(GlyphVertex), (GLvoid *)&glyphverts[0].s);
  284. // We need to draw a new vertex array for every section of the string which
  285. // uses a different texture than the previous section.
  286. std::vector<GlyphArrayDrawInfo>::const_iterator it;
  287. for (it = glyphinfolist.begin(); it != glyphinfolist.end(); ++it)
  288. {
  289. gl.bindTexture(it->texture);
  290. glDrawArrays(GL_QUADS, it->startvertex, it->vertexcount);
  291. }
  292. glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  293. glDisableClientState(GL_VERTEX_ARRAY);
  294. glPopMatrix();
  295. }
  296. int Font::getWidth(const std::string &str)
  297. {
  298. if (str.size() == 0) return 0;
  299. std::istringstream iss(str);
  300. std::string line;
  301. Glyph *g;
  302. int max_width = 0;
  303. while (getline(iss, line, '\n'))
  304. {
  305. int width = 0;
  306. try
  307. {
  308. utf8::iterator<std::string::const_iterator> i(line.begin(), line.begin(), line.end());
  309. utf8::iterator<std::string::const_iterator> end(line.end(), line.begin(), line.end());
  310. while (i != end)
  311. {
  312. uint32 c = *i++;
  313. g = findGlyph(c);
  314. width += static_cast<int>(g->spacing * mSpacing);
  315. }
  316. }
  317. catch(utf8::exception &e)
  318. {
  319. throw love::Exception("Decoding error: %s", e.what());
  320. }
  321. if (width > max_width)
  322. max_width = width;
  323. }
  324. return max_width;
  325. }
  326. int Font::getWidth(char character)
  327. {
  328. Glyph *g = findGlyph(character);
  329. return g->spacing;
  330. }
  331. std::vector<std::string> Font::getWrap(const std::string &text, float wrap, int *max_width, std::vector<bool> *wrappedlines)
  332. {
  333. using namespace std;
  334. const float width_space = static_cast<float>(getWidth(' '));
  335. vector<string> lines_to_draw;
  336. int maxw = 0;
  337. //split text at newlines
  338. istringstream iss(text);
  339. string line;
  340. ostringstream string_builder;
  341. while (getline(iss, line, '\n'))
  342. {
  343. // split line into words
  344. vector<string> words;
  345. istringstream word_iss(line);
  346. copy(istream_iterator<string>(word_iss), istream_iterator<string>(),
  347. back_inserter< vector<string> >(words));
  348. // put words back together until a wrap occurs
  349. float width = 0.0f;
  350. float oldwidth = 0.0f;
  351. string_builder.str("");
  352. vector<string>::const_iterator word_iter, wend = words.end();
  353. for (word_iter = words.begin(); word_iter != wend; ++word_iter)
  354. {
  355. const string &word = *word_iter;
  356. width += getWidth(word);
  357. // on wordwrap, push line to line buffer and clear string builder
  358. if (width > wrap && oldwidth > 0)
  359. {
  360. int realw = (int) width;
  361. // remove trailing space
  362. string tmp = string_builder.str();
  363. lines_to_draw.push_back(tmp.substr(0,tmp.size()-1));
  364. string_builder.str("");
  365. width = static_cast<float>(getWidth(word));
  366. realw -= (int) width;
  367. if (realw > maxw)
  368. maxw = realw;
  369. // Indicate that this line was automatically wrapped.
  370. if (wrappedlines)
  371. wrappedlines->push_back(true);
  372. }
  373. string_builder << word << " ";
  374. width += width_space;
  375. oldwidth = width;
  376. }
  377. // push last line
  378. if (width > maxw)
  379. maxw = (int) width;
  380. string tmp = string_builder.str();
  381. lines_to_draw.push_back(tmp.substr(0,tmp.size()-1));
  382. // Indicate that this line was not automatically wrapped.
  383. if (wrappedlines)
  384. wrappedlines->push_back(false);
  385. }
  386. if (max_width)
  387. *max_width = maxw;
  388. return lines_to_draw;
  389. }
  390. void Font::setLineHeight(float height)
  391. {
  392. this->lineHeight = height;
  393. }
  394. float Font::getLineHeight() const
  395. {
  396. return lineHeight;
  397. }
  398. void Font::setSpacing(float amount)
  399. {
  400. mSpacing = amount;
  401. }
  402. float Font::getSpacing() const
  403. {
  404. return mSpacing;
  405. }
  406. void Font::setFilter(const Image::Filter &f)
  407. {
  408. filter = f;
  409. for (auto it = textures.begin(); it != textures.end(); ++it)
  410. {
  411. gl.bindTexture(*it);
  412. filter.anisotropy = gl.setTextureFilter(f);
  413. }
  414. }
  415. const Image::Filter &Font::getFilter()
  416. {
  417. return filter;
  418. }
  419. bool Font::loadVolatile()
  420. {
  421. createTexture();
  422. return true;
  423. }
  424. void Font::unloadVolatile()
  425. {
  426. // nuke everything from orbit
  427. std::map<uint32, Glyph *>::iterator it = glyphs.begin();
  428. Glyph *g;
  429. while (it != glyphs.end())
  430. {
  431. g = it->second;
  432. delete g;
  433. glyphs.erase(it++);
  434. }
  435. std::vector<GLuint>::iterator iter = textures.begin();
  436. while (iter != textures.end())
  437. {
  438. gl.deleteTexture(*iter);
  439. iter++;
  440. }
  441. textures.clear();
  442. }
  443. int Font::getAscent() const
  444. {
  445. return rasterizer->getAscent();
  446. }
  447. int Font::getDescent() const
  448. {
  449. return rasterizer->getDescent();
  450. }
  451. float Font::getBaseline() const
  452. {
  453. // 1.25 is magic line height for true type fonts
  454. return (type == FONT_TRUETYPE) ? floorf(getHeight() / 1.25f + 0.5f) : 0.0f;
  455. }
  456. bool Font::hasGlyph(uint32 glyph) const
  457. {
  458. return rasterizer->hasGlyph(glyph);
  459. }
  460. bool Font::hasGlyph(const std::string &text) const
  461. {
  462. return rasterizer->hasGlyph(text);
  463. }
  464. } // opengl
  465. } // graphics
  466. } // love