jubilant-funicular
SpriteFont.cpp
1 #include "nta/SpriteFont.h"
2 #include "nta/Logger.h"
3 
4 namespace nta {
5  void SpriteFont::init(TTF_Font* font) {
6  /*
7  static auto toPower2 = [](int i) {
8  i--;
9  i |= i >> 1;
10  i |= i >> 2;
11  i |= i >> 4;
12  i |= i >> 8;
13  i |= i >> 16;
14  return ++i;
15  };
16  */
17  m_fontHeight = TTF_FontHeight(font);
18  Logger::writeToLog("Creating SpriteFont...");
19  FontMap* seed = new FontMap;
20  SDL_Surface* glyphSurface = nullptr;
21  for (char c = FIRST_PRINTABLE_CHAR; c <= LAST_PRINTABLE_CHAR; c++) {
22  glyphSurface = TTF_RenderGlyph_Blended(font, c, {255, 255, 255, 255});
23  seed->addRect(c, glm::vec2(glyphSurface->w, glyphSurface->h));
24  SDL_FreeSurface(glyphSurface);
25  }
26  seed->position();
27  /* Why did I want these to be powers of 2 before?
28  glm::ivec2 dimensions = glm::ivec2(toPower2(seed->getBoundingDimensions().x),
29  toPower2(seed->getBoundingDimensions().y));
30  */
31  glm::ivec2 dimensions(ceil(seed->getBoundingDimensions().x),
32  ceil(seed->getBoundingDimensions().y));
33  // create initial gray texture
34  glGenTextures(1, &m_texId);
35  glBindTexture(GL_TEXTURE_2D, m_texId);
36  GLubyte* graySquare = new GLubyte[dimensions.x*dimensions.y*4];
37  memset(graySquare, 0x50, dimensions.x*dimensions.y*4);
38  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dimensions.x, dimensions.y, 0, GL_RGBA,
39  GL_UNSIGNED_BYTE, graySquare);
40  delete[] graySquare;
41  // add glyphs to texture
42  m_charGlyphs = new CharGlyph[NUM_PRINTABLE_CHARS];
43  for (char c = FIRST_PRINTABLE_CHAR; c <= LAST_PRINTABLE_CHAR; c++) {
44  CharGlyph& cg = m_charGlyphs[c - FIRST_PRINTABLE_CHAR];
45  FontMap::CharRect cr = seed->m_rects[c - FIRST_PRINTABLE_CHAR];
46  cg.size = cr.dimensions;
47  cg.uvRect = glm::vec4(cr.topLeft/glm::vec2(dimensions),
48  cr.dimensions/glm::vec2(dimensions));
49  cg.uvRect.y *= -1;
50  glyphSurface = TTF_RenderGlyph_Blended(font, c, {255, 255, 255, 255});
51  glTexSubImage2D(GL_TEXTURE_2D, 0, cr.topLeft.x, -cr.topLeft.y, cr.dimensions.x,
52  cr.dimensions.y, GL_RGBA, GL_UNSIGNED_BYTE, glyphSurface->pixels);
53  SDL_FreeSurface(glyphSurface);
54  }
55  glyphSurface = nullptr;
56  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
57  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
58  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
59  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
60  glBindTexture(GL_TEXTURE_2D, 0);
61  Logger::writeToLog("Created SpriteFont");
62  Logger::writeToLog("Generated font has dimensions: " + utils::to_string(dimensions.x) + " x " +
63  utils::to_string(dimensions.y));
64  }
66  if (m_texId != 0) {
67  glDeleteTextures(1, &m_texId);
68  }
69  m_texId = 0;
70  if (m_charGlyphs) {
71  delete[] m_charGlyphs;
72  }
73  m_charGlyphs = nullptr;
74  }
75  glm::vec2 SpriteFont::measure(crstring text) const {
76  if (text == "") {
77  return glm::vec2(0);
78  }
79  glm::vec2 dim(0, m_fontHeight);
80  float xOffset = 0;
81  for (char c : text) {
82  if (c == '\n') {
83  dim.y += m_fontHeight;
84  xOffset = 0;
85  } else if (c == '\t') {
86  // not the best way to implement tabs, but meh
87  xOffset += SPRITE_FONT_TAB_SIZE * m_charGlyphs[' '-FIRST_PRINTABLE_CHAR].size.x;
88  } else {
89  xOffset += m_charGlyphs[c-FIRST_PRINTABLE_CHAR].size.x;
90  if (xOffset > dim.x) {
91  dim.x = xOffset;
92  }
93  }
94  }
95  return dim;
96  }
97  void SpriteFont::drawText(SpriteBatch& batch, crstring text, crvec2 topLeft, crvec2 scale,
98  crvec4 color, float depth) const {
99  glm::vec2 offset(0);
100  for (char c : text) {
101  if (c == '\n') {
102  offset.y -= m_fontHeight*scale.y;
103  offset.x = 0;
104  } else if (c == '\t') {
105  CharGlyph cg = m_charGlyphs[' '-FIRST_PRINTABLE_CHAR];
106  offset.x += SPRITE_FONT_TAB_SIZE*cg.size.x*scale.x;
107  } else {
108  CharGlyph cg = m_charGlyphs[c-FIRST_PRINTABLE_CHAR];
109  batch.addGlyph(glm::vec4(topLeft+offset, cg.size*scale), cg.uvRect, m_texId,
110  depth, color);
111  offset.x += cg.size.x*scale.x;
112  }
113  }
114  }
115  void SpriteFont::drawText(SpriteBatch& batch, crstring text, crvec4 posRect, crvec4 color,
116  float depth) const {
117  glm::vec2 scale = glm::vec2(posRect[2], posRect[3])/measure(text);
118  drawText(batch, text, glm::vec2(posRect.x, posRect.y), scale, color, depth);
119  }
120  void SpriteFont::drawText(SpriteBatch& batch, crvec2 corner1, crvec2 corner2, crstring text,
121  crvec4 color, float depth) const {
122  glm::vec4 posRect(glm::min(corner1.x, corner2.x), glm::max(corner1.y, corner2.y),
123  glm::abs(corner1-corner2));
124  drawText(batch, text, posRect, color, depth);
125  }
126  void SpriteFont::drawTexture(SpriteBatch& batch, crvec4 posRect) const {
127  batch.addGlyph(posRect, glm::vec4(0,0,1,1), m_texId, 1);
128  }
129 }
nta::FontMap::CharRect
a rectangle representing the location of a char in the FontMap
Definition: SpriteFont.h:29
nta::CharGlyph::size
glm::vec2 size
the size of the rendered glyph
Definition: SpriteFont.h:23
nta::SpriteFont::m_texId
GLuint m_texId
the idea of the generated texture
Definition: SpriteFont.h:64
nta::FontMap::position
void position()
positions map so that the topleft is at (0,0)
Definition: FontMap.cpp:64
nta::Logger::writeToLog
static void writeToLog(crstring entry)
writes an entry in the log
Definition: Logger.cpp:17
nta::CharGlyph::uvRect
glm::vec4 uvRect
the rectangle containing this glyph in the texture
Definition: SpriteFont.h:21
nta::SpriteFont::m_charGlyphs
CharGlyph * m_charGlyphs
a collection of glyphs for each char
Definition: SpriteFont.h:62
nta::SpriteBatch
Definition: SpriteBatch.h:87
nta::SpriteFont::destroy
void destroy()
Destroys this SpriteFont.
Definition: SpriteFont.cpp:65
nta::SpriteBatch::addGlyph
void addGlyph(crvec4 posRect, GLuint texture=0, crvec4 uvRect=glm::vec4(0, 0, 1, 1), crvec4 color=glm::vec4(1), float depth=0.5)
Definition: SpriteBatch.cpp:100
nta::FontMap::addRect
void addRect(char c, crvec2 dimensions)
adds a rectangle and associates it with c (replacing any preexisting rectangle)
Definition: FontMap.cpp:39
nta
Definition: Animation2D.h:6
nta::SpriteFont::m_fontHeight
int m_fontHeight
the height of the font
Definition: SpriteFont.h:66
nta::SpriteFont::measure
glm::vec2 measure(crstring text) const
returns the dimensions of the rectangle containing the text
Definition: SpriteFont.cpp:75
nta::FontMap::m_rects
CharRect * m_rects
the rectangles making up the FontMap
Definition: SpriteFont.h:40
nta::SpriteFont::drawText
void drawText(SpriteBatch &batch, crstring text, crvec2 topLeft, crvec2 scale, crvec4 color=glm::vec4(1), float depth=NTA_DEFAULT_DEPTH) const
renders text with specified location, color, scale, etc.
Definition: SpriteFont.cpp:97
nta::CharGlyph
represents a single char in the texture
Definition: SpriteFont.h:19
nta::FontMap
represents the organization of a texture containing the characters
Definition: SpriteFont.h:26
nta::utils::to_string
std::string to_string(const T &input, std::size_t precision=0)
converts input to a std::string
Definition: utils.h:36
nta::SpriteFont::init
void init(TTF_Font *font)
Definition: SpriteFont.cpp:5
nta::FontMap::getBoundingDimensions
glm::vec2 getBoundingDimensions() const
returns the dimensions of the rectangle that contains the FontMap
Definition: FontMap.cpp:16
nta::SpriteFont::drawTexture
void drawTexture(SpriteBatch &batch, crvec4 posRect=glm::vec4(-100, 100, 200, 200)) const
renders texture
Definition: SpriteFont.cpp:126