Font.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /**
  2. * Copyright (c) 2006-2011 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 "Font.h"
  21. #include <font/GlyphData.h>
  22. #include "Quad.h"
  23. #include <common/math.h>
  24. #include <math.h>
  25. #include <algorithm> // for max
  26. namespace love
  27. {
  28. namespace graphics
  29. {
  30. namespace opengl
  31. {
  32. Font::Font(love::font::Rasterizer * r, const Image::Filter& filter)
  33. : rasterizer(r), height(r->getHeight()), lineHeight(1), mSpacing(1), filter(filter)
  34. {
  35. love::font::GlyphData * gd = r->getGlyphData(32);
  36. type = (gd->getFormat() == love::font::GlyphData::FORMAT_LUMINANCE_ALPHA ? FONT_TRUETYPE : FONT_IMAGE);
  37. delete gd;
  38. createTexture();
  39. }
  40. Font::~Font()
  41. {
  42. unloadVolatile();
  43. }
  44. void Font::createTexture()
  45. {
  46. texture_x = texture_y = rowHeight = 0;
  47. GLuint t;
  48. glGenTextures(1, &t);
  49. textures.push_back(t);
  50. glBindTexture(GL_TEXTURE_2D, t);
  51. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
  52. (filter.mag == Image::FILTER_LINEAR) ? GL_LINEAR : GL_NEAREST);
  53. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
  54. (filter.min == Image::FILTER_LINEAR) ? GL_LINEAR : GL_NEAREST);
  55. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  56. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  57. GLint format = (type == FONT_TRUETYPE ? GL_LUMINANCE_ALPHA : GL_RGBA);
  58. glTexImage2D(GL_TEXTURE_2D,
  59. 0,
  60. GL_RGBA,
  61. (GLsizei)TEXTURE_WIDTH,
  62. (GLsizei)TEXTURE_HEIGHT,
  63. 0,
  64. format,
  65. GL_UNSIGNED_BYTE,
  66. NULL);
  67. }
  68. Font::Glyph * Font::addGlyph(int glyph)
  69. {
  70. Glyph * g = new Glyph;
  71. g->list = glGenLists(1);
  72. if (g->list == 0) { // opengl failed to generate the list
  73. delete g;
  74. return NULL;
  75. }
  76. love::font::GlyphData *gd = rasterizer->getGlyphData(glyph);
  77. g->spacing = gd->getAdvance();
  78. int w = gd->getWidth();
  79. int h = gd->getHeight();
  80. if (texture_x + w > TEXTURE_WIDTH) { // out of space - new row!
  81. texture_x = 0;
  82. texture_y += rowHeight;
  83. rowHeight = 0;
  84. }
  85. if (texture_y + h > TEXTURE_HEIGHT) { // totally out of space - new texture!
  86. createTexture();
  87. }
  88. GLuint t = textures.back();
  89. glBindTexture(GL_TEXTURE_2D, t);
  90. glTexSubImage2D(GL_TEXTURE_2D, 0, texture_x, texture_y, w, h, (type == FONT_TRUETYPE ? GL_LUMINANCE_ALPHA : GL_RGBA), GL_UNSIGNED_BYTE, gd->getData());
  91. Quad::Viewport v;
  92. v.x = texture_x;
  93. v.y = texture_y;
  94. v.w = w;
  95. v.h = h;
  96. Quad * q = new Quad(v, TEXTURE_WIDTH, TEXTURE_HEIGHT);
  97. const vertex * verts = q->getVertices();
  98. glEnableClientState(GL_VERTEX_ARRAY);
  99. glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  100. glVertexPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid *)&verts[0].x);
  101. glTexCoordPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid *)&verts[0].s);
  102. glNewList(g->list, GL_COMPILE);
  103. glBindTexture(GL_TEXTURE_2D, t);
  104. glPushMatrix();
  105. glTranslatef(static_cast<float>(gd->getBearingX()), static_cast<float>(-gd->getBearingY()), 0.0f);
  106. glDrawArrays(GL_QUADS, 0, 4);
  107. glPopMatrix();
  108. glEndList();
  109. glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  110. glDisableClientState(GL_VERTEX_ARRAY);
  111. delete q;
  112. delete gd;
  113. texture_x += w;
  114. rowHeight = std::max(rowHeight, h);
  115. glyphs[glyph] = g;
  116. return g;
  117. }
  118. float Font::getHeight() const
  119. {
  120. return static_cast<float>(height);
  121. }
  122. void Font::print(std::string text, float x, float y, float angle, float sx, float sy)
  123. {
  124. float dx = 0.0f; // spacing counter for newline handling
  125. glPushMatrix();
  126. glTranslatef(ceil(x), ceil(y), 0.0f);
  127. glRotatef(LOVE_TODEG(angle), 0, 0, 1.0f);
  128. glScalef(sx, sy, 1.0f);
  129. for (unsigned int i = 0; i < text.size(); i++) {
  130. unsigned char g = (unsigned char)text[i];
  131. if (g == '\n') { // wrap newline, but do not print it
  132. glTranslatef(-dx, floor(getHeight() * getLineHeight() + 0.5f), 0);
  133. dx = 0.0f;
  134. continue;
  135. }
  136. Glyph * glyph = glyphs[g];
  137. if (!glyph) glyph = addGlyph(g);
  138. glPushMatrix();
  139. // 1.25 is magic line height for true type fonts
  140. if (type == FONT_TRUETYPE) glTranslatef(0, floor(getHeight() / 1.25f + 0.5f), 0);
  141. glCallList(glyph->list);
  142. glPopMatrix();
  143. glTranslatef(static_cast<GLfloat>(glyph->spacing), 0, 0);
  144. dx += glyph->spacing;
  145. }
  146. glPopMatrix();
  147. }
  148. void Font::print(char character, float x, float y)
  149. {
  150. Glyph * glyph = glyphs[character];
  151. if (!glyph) glyph = addGlyph(character);
  152. glPushMatrix();
  153. glTranslatef(x, floor(y+getHeight() + 0.5f), 0.0f);
  154. glCallList(glyph->list);
  155. glPopMatrix();
  156. }
  157. int Font::getWidth(const std::string & line)
  158. {
  159. if(line.size() == 0) return 0;
  160. int temp = 0;
  161. Glyph * g;
  162. for(unsigned int i = 0; i < line.size(); i++)
  163. {
  164. g = glyphs[line[i]];
  165. if (!g) g = addGlyph(line[i]);
  166. temp += static_cast<int>(g->spacing * mSpacing);
  167. }
  168. return temp;
  169. }
  170. int Font::getWidth(const char * line)
  171. {
  172. return this->getWidth(std::string(line));
  173. }
  174. int Font::getWidth(const char character)
  175. {
  176. Glyph * g = glyphs[character];
  177. if (!g) g = addGlyph(character);
  178. return g->spacing;
  179. }
  180. int Font::getWrap(const std::string & line, float wrap, int * lines)
  181. {
  182. if(line.size() == 0) return 0;
  183. int maxw = 0;
  184. int linen = 1;
  185. int temp = 0;
  186. std::string text;
  187. Glyph * g;
  188. for(unsigned int i = 0; i < line.size(); i++)
  189. {
  190. if(temp > wrap && text.find(" ") != std::string::npos)
  191. {
  192. unsigned int space = text.find_last_of(' ');
  193. std::string tmp = text.substr(0, space);
  194. int w = getWidth(tmp);
  195. if(w > maxw) maxw = w;
  196. text = text.substr(space+1);
  197. temp = getWidth(text);
  198. linen++;
  199. }
  200. g = glyphs[line[i]];
  201. if (!g) g = addGlyph(line[i]);
  202. temp += static_cast<int>(g->spacing * mSpacing);
  203. text += line[i];
  204. }
  205. if(temp > maxw) maxw = temp;
  206. if(lines) *lines = linen;
  207. return maxw;
  208. }
  209. int Font::getWrap(const char * line, float wrap, int * lines)
  210. {
  211. return getWrap(std::string(line), wrap, lines);
  212. }
  213. void Font::setLineHeight(float height)
  214. {
  215. this->lineHeight = height;
  216. }
  217. float Font::getLineHeight() const
  218. {
  219. return lineHeight;
  220. }
  221. void Font::setSpacing(float amount)
  222. {
  223. mSpacing = amount;
  224. }
  225. float Font::getSpacing() const
  226. {
  227. return mSpacing;
  228. }
  229. bool Font::loadVolatile()
  230. {
  231. createTexture();
  232. return true;
  233. }
  234. void Font::unloadVolatile()
  235. {
  236. // nuke everything from orbit
  237. std::map<int, Glyph *>::iterator it = glyphs.begin();
  238. Glyph * g;
  239. while (it != glyphs.end()) {
  240. g = it->second;
  241. glDeleteLists(g->list, 1);
  242. delete g;
  243. glyphs.erase(it++);
  244. }
  245. std::vector<GLuint>::iterator iter = textures.begin();
  246. while (iter != textures.end()) {
  247. glDeleteTextures(1, (GLuint*)&*iter);
  248. iter++;
  249. }
  250. textures.clear();
  251. }
  252. } // opengl
  253. } // graphics
  254. } // love