Number5
Visualisierung 2 Project - Florian Schober (0828151, f.schober@live.com), Andreas Walch (0926780, walch.andreas89@gmail.com)
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Font.cpp
Go to the documentation of this file.
1 #include "Application.hpp"
2 
3 
4 Font::Font(TextRenderer* textRenderer, string const & name, const uint size)
5  : m_name(name)
6  , m_size(size)
7  , m_textRenderer(textRenderer)
8 {
9  stringstream ss; ss << "content\\fonts\\" << name << ".ttf";
10  string file = ss.str();
11 
12  FT_Error error;
13  FT_Face face;
14 
15  error = FT_New_Face( textRenderer->m_ftLib,
16  file.c_str(),
17  0,
18  &face );
19  if ( error == FT_Err_Unknown_File_Format )
20  {
21  cerr << "ERROR: Loading font '" << file << "' failed (Unknown file format)" << endl;
22  exit(EXIT_FAILURE);
23  }
24  else if ( error )
25  {
26  cerr << "ERROR: Loading font '" << file << "' failed (Could not read font-file)" << endl;
27  exit(EXIT_FAILURE);
28  }
29 
30  FT_Set_Char_Size(face,0,size*64,72,72);
31 
32  m_atlasSize = uvec2(0,0);
33 
34  map<int, uvec2> charToCoords;
35 
36  uint x = 0;
37  uint y = 0;
38  uint rowHeight = 0;
39  for(uint row = 0; row < 15; row++)
40  {
41  x = 0;
42  rowHeight = 0;
43  for(uint col = 0; col < 15; col++)
44  {
45  uint i = 32 + row*15+col;
46 
47  error = FT_Load_Char(face, i, FT_LOAD_RENDER);
48  if(error)
49  {
50  cerr << "ERROR: Loading font '" << file << "' failed (char '"<< i <<"')" << endl;
51  exit(EXIT_FAILURE);
52  }
53  auto& g = face->glyph;
54 
55  rowHeight = glm::max(rowHeight,(uint)g->bitmap.rows);
56 
57  charToCoords[i] = uvec2(x, y);
58 
59  x += g->bitmap.width + 5;
60  }
61  y += rowHeight + 5;
62  m_atlasSize.x = glm::max(m_atlasSize.x, x);
63  }
64 
65  m_atlasSize.y = y;
66 
67 
68  m_atlasSize.x = static_cast<int>(glm::pow(2.0,glm::ceil(glm::log2(static_cast<double>(m_atlasSize.x)))));
69  m_atlasSize.y = static_cast<int>(glm::pow(2.0,glm::ceil(glm::log2(static_cast<double>(m_atlasSize.y)))));
70 
72  memset(m_atlasData.data(),0,m_atlasSize.x*m_atlasSize.y*sizeof(char));
73 
74 
75  float ymin = 1000000000.0;
76  float ymax = 0;
77  x = 0;
78  for(int i = 32; i < 256; i++)
79  {
80  if(FT_Load_Char(face, i, FT_LOAD_RENDER))
81  continue;
82 
83  auto& g = face->glyph;
84  auto& pixelCoords = charToCoords[i];
85 
86  for ( int tx = 0 ; tx < g->bitmap.width ; tx ++)
87  for ( int ty = 0 ; ty < g-> bitmap.rows; ty ++)
88  {
89  m_atlasData[m_atlasSize.x * (ty+pixelCoords.y) + pixelCoords.x + tx] = g->bitmap.buffer[(g->bitmap.rows-ty-1) * g->bitmap.pitch + tx];
90  }
91 
92  auto& glyph = m_glyphs[i];
93 
94  glyph.size = vec2( g->bitmap.width, g->bitmap.rows );
95  glyph.advance = vec2( g->metrics.horiAdvance >> 6, g->metrics.vertAdvance >> 6 );
96  glyph.location = vec2( g->metrics.horiBearingX >> 6 , (g->metrics.horiBearingY - g->metrics.height) >> 6 );
97  glyph.texCoord1 = vec2(pixelCoords.x/static_cast<float>(m_atlasSize.x),pixelCoords.y/static_cast<float>(m_atlasSize.y));
98  glyph.texCoord2 = vec2((pixelCoords.x + glyph.size.x)/static_cast<float>(m_atlasSize.x),(pixelCoords.y + glyph.size.y)/static_cast<float>(m_atlasSize.y));
99 
100  ymin = static_cast<float>(glm::min(glyph.location.y,ymin));
101  ymax = static_cast<float>(glm::max(glyph.location.y + glyph.size.y, ymax));
102  }
103 
104  m_lineHeight = (ymax-ymin);
105 
106  FT_Done_Face(face);
107 
108  glGenTextures(1, &m_atlas);
109 
110  glActiveTexture(GL_TEXTURE0);
111  glBindTexture(GL_TEXTURE_2D, m_atlas);
112 
113  glPixelStorei(GL_PACK_ALIGNMENT,1);
114  glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_atlasSize.x, m_atlasSize.y, 0, GL_RED, GL_UNSIGNED_BYTE, m_atlasData.data());
115  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
116  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
117  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
118  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
119  glPixelStorei(GL_PACK_ALIGNMENT,4);
120  glBindTexture(GL_TEXTURE_2D, 0);
121 }
123 {
124  glDeleteTextures(1, &m_atlas);
125 }
126 vec2 Font::measure(string const & text)
127 {
128  vec2 size(0,0);
129 
130  auto& wndSize = m_textRenderer->m_app->getWindow().getSize();
131 
132  for(auto& c : text)
133  {
134  if (c == 0) break;
135 
136  auto& gi = m_glyphs.find(c);
137  if ( gi == m_glyphs.end() )
138  continue;
139 
140  auto& g = gi->second;
141 
142  size.x += g.advance.x / wndSize.x;
143  size.y = glm::max(size.y, g.advance.y / wndSize.y);
144  }
145 
146  return size;
147 }
148 void Font::prepare(string const & text)
149 {
150  auto& wndSize = m_textRenderer->m_app->getWindow().getSize();
151  auto vertices = &(m_textRenderer->m_vertices);
152 
153  vertices->clear();
154 
155  float x = 0;
156  for(auto& c : text)
157  {
158  if (c == 0) break;
159 
160  auto& gi = m_glyphs.find(c);
161  if ( gi == m_glyphs.end() )
162  continue;
163 
164  auto& g = gi->second;
165 
166  float localX = x + g.location.x/wndSize.x;
167  float localY = g.location.y/wndSize.y;
168 
169  float localW = g.size.x/wndSize.x;
170  float localH = g.size.y/wndSize.y;
171 
172  x += g.advance.x/wndSize.x;
173 
174  if ( g.size.x == 0 || g.size.y == 0 ) continue;
175 
176 
177  vertices->push_back(vec4( localX, localY, g.texCoord1.x, g.texCoord1.y));
178  vertices->push_back(vec4( localX + localW, localY, g.texCoord2.x, g.texCoord1.y));
179  vertices->push_back(vec4( localX, localY + localH, g.texCoord1.x, g.texCoord2.y));
180  vertices->push_back(vec4( localX, localY + localH, g.texCoord1.x, g.texCoord2.y));
181  vertices->push_back(vec4( localX + localW, localY, g.texCoord2.x, g.texCoord1.y));
182  vertices->push_back(vec4( localX + localW, localY + localH, g.texCoord2.x, g.texCoord2.y));
183  }
184 }
185 void Font::draw(string const & text, vec4 const & color, vec2 position, HAlign hAlign, VAlign vAlign, vec2 const & scale)
186 {
187  if (hAlign != HAlign::Left || vAlign != VAlign::Bottom)
188  {
189  auto size = measure(text);
190 
191  switch(hAlign)
192  {
193  case(HAlign::Center): position.x -= size.x*0.5f; break;
194  case(HAlign::Right): position.x -= size.x; break;
195  default: break;
196  }
197  switch(vAlign)
198  {
199  case(VAlign::Middle): position.y -= size.y*0.5f; break;
200  case(VAlign::Top): position.y -= size.y; break;
201  default: break;
202  }
203  }
204 
205  prepare(text);
206 
207  glBindTexture(GL_TEXTURE_2D, m_atlas);
208 
209  auto shader = m_textRenderer->m_shader;
210  shader->uniform("color", color);
211  shader->uniform("location", position);
212  shader->uniform("scale", scale);
213 
215 }
216 
217 
219  : m_app(app)
220  , m_shader(app->getShaders().get("font"))
221 {
222  auto error = FT_Init_FreeType( &m_ftLib );
223  if ( error )
224  {
225  cerr << "ERROR: Could not init freetype-lib." << endl;
226  exit(EXIT_FAILURE);
227  }
228 
229 
230  glGenBuffers(1, &m_verticesBuffer);
231  glBindBuffer(GL_ARRAY_BUFFER, m_verticesBuffer);
232  glBufferData(GL_ARRAY_BUFFER, 0, nullptr, GL_STREAM_DRAW);
233  glBindBuffer(GL_ARRAY_BUFFER, 0);
234 
235  glGenVertexArrays(1, &m_vao);
236  glBindVertexArray(m_vao);
237 
238  glBindBuffer(GL_ARRAY_BUFFER, m_verticesBuffer);
239  GLint positionIndex = Shader::position;
240  glEnableVertexAttribArray(positionIndex);
241  glVertexAttribPointer(positionIndex, 4, GL_FLOAT, GL_FALSE, 0, 0);
242 
243  glBindVertexArray(0);
244  glBindBuffer(GL_ARRAY_BUFFER, 0);
245 
246  m_shader->use();
247  m_shader->uniform("texAtlas", (int)0);
248 }
250 {
251  glDeleteBuffers(1, &m_verticesBuffer);
252  glDeleteVertexArrays(1, &m_vao);
253 
254  FT_Done_FreeType(m_ftLib);
255 }
256 Font* TextRenderer::getFont(string const & name, uint const size)
257 {
258  stringstream ss; ss << name << ":" << size;
259  string key = ss.str();
260  auto found = m_fonts.find(key);
261 
262  if (found != m_fonts.end())
263  return found->second.get();
264 
265  auto& entry = m_fonts[key];
266  entry.reset(new Font(this, name, size));
267  return entry.get();
268 }
270 {
271  m_shader->use();
272 
273  glBindVertexArray(m_vao);
274 
275  glActiveTexture(GL_TEXTURE0);
276 }
278 {
279  glBindVertexArray(0);
280 
281  glBindTexture(GL_TEXTURE_2D, 0);
282 }
284 {
285  glBindBuffer(GL_ARRAY_BUFFER, m_verticesBuffer);
286  glBufferData(GL_ARRAY_BUFFER, sizeof(vec4)*m_vertices.size(), m_vertices.data(), GL_STREAM_DRAW);
287  glBindBuffer(GL_ARRAY_BUFFER, 0);
288 
289  glDrawArrays(GL_TRIANGLES, 0, m_vertices.size());
290 }
void use()
Definition: Shader.cpp:111
void prepare(string const &text)
Definition: Font.cpp:148
VAlign
Definition: Sprite.hpp:20
Definition: Font.hpp:20
font_map m_fonts
Definition: Font.hpp:94
virtual ~TextRenderer()
Definition: Font.cpp:249
void begin()
Definition: Font.cpp:269
TextRenderer * m_textRenderer
Definition: Font.hpp:24
void draw(string const &text, vec4 const &color, vec2 position, HAlign hAlign=HAlign::Left, VAlign vAlign=VAlign::Bottom, vec2 const &scale=vec2(1, 1))
Definition: Font.cpp:185
glyph_map m_glyphs
Definition: Font.hpp:30
uint m_atlas
Definition: Font.hpp:29
GLuint m_vao
Definition: Font.hpp:100
virtual ~Font()
Definition: Font.cpp:122
Font(TextRenderer *textRenderer, string const &fontName, const uint fontSize)
Definition: Font.cpp:4
Font * getFont(string const &name, uint const size)
Definition: Font.cpp:256
static const uint position
Definition: Shader.hpp:122
TextRenderer(Application *app)
Definition: Font.cpp:218
Application * m_app
Definition: Font.hpp:92
void end()
Definition: Font.cpp:277
HAlign
Definition: Sprite.hpp:11
GLuint m_verticesBuffer
Definition: Font.hpp:99
Window & getWindow()
Definition: Application.hpp:41
Shader * m_shader
Definition: Font.hpp:95
friend class Font
Definition: Font.hpp:102
vec2 const & getSize() const
Definition: Window.hpp:45
vector< char > m_atlasData
Definition: Font.hpp:28
vec2 measure(string const &text)
Definition: Font.cpp:126
vector< vec4 > m_vertices
Definition: Font.hpp:97
uvec2 m_atlasSize
Definition: Font.hpp:27
FT_Library m_ftLib
Definition: Font.hpp:93
float m_lineHeight
Definition: Font.hpp:31
GLint uniform(string const &name)
Definition: Shader.cpp:115
void drawBuffer()
Definition: Font.cpp:283