zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
Font.cpp
Go to the documentation of this file.
1 /* This file is part of the Zenipex Library (zenilib).
2  * Copyright (C) 2011 Mitchell Keith Bloch (bazald).
3  *
4  * zenilib is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * zenilib is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with zenilib. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include <zeni_graphics.h>
19 
20 #include <algorithm>
21 #include <ft2build.h>
22 #include FT_FREETYPE_H
23 #include FT_GLYPH_H
24 #include <Zeni/Image.h>
25 
26 #include <Zeni/Define.h>
27 
28 #if defined(_DEBUG) && defined(_WINDOWS)
29 #define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
30 #define new DEBUG_NEW
31 #endif
32 
33 namespace Zeni {
34 
36  : m_glyph_height(0),
37  m_virtual_screen_height(0.0f)
38  {
39  }
40 
41  Font::Font(const float &glyph_height,
42  const float &virtual_screen_height,
43  const String &font_name)
44  : m_glyph_height(glyph_height),
45  m_virtual_screen_height(virtual_screen_height),
46  m_font_name(font_name)
47  {
48  }
49 
50  Font_FT::Glyph::Glyph()
51  : m_glyph_width(0.0f)
52  {
53  }
54 
55  Font_FT::Glyph::Glyph(FT_Face &face,
56  const char &c,
57  const int &ascent,
58  const float &vratio,
59  const Point2i &position,
60  const Point2i &total_size)
61  : m_glyph_width(0.0f)
62  {
63  // Reload the Glyph for our character.
64  if(FT_Load_Char(face, c, FT_LOAD_RENDER))
65  throw Error("FT_Load_Char(...) failed.");
66 
67  // Move the face's glyph into a Glyph object.
68  FT_Glyph glyph;
69  if(FT_Get_Glyph(face->glyph, &glyph))
70  throw Error("FT_Get_Glyph(...) failed.");
71 
72  FT_BitmapGlyph bglyph = reinterpret_cast<FT_BitmapGlyph>(glyph);
73 
74  m_glyph_width = int(glyph->advance.x) / (65536.0f * vratio);
75  m_upper_left_point.x = bglyph->left / vratio;
76  m_upper_left_point.y = (ascent - bglyph->top) / vratio;
77  m_lower_right_point.x = (bglyph->left + bglyph->bitmap.width) / vratio;
78  m_lower_right_point.y = (ascent - bglyph->top + bglyph->bitmap.rows) / vratio;
79 
80  m_upper_left_texel.x = float(position.x) / total_size.x;
81  m_upper_left_texel.y = float(position.y) / total_size.y;
82  m_lower_right_texel.x = float(position.x + bglyph->bitmap.width) / total_size.x;
83  m_lower_right_texel.y = float(position.y + bglyph->bitmap.rows) / total_size.y;
84 
85 // ZENI_LOGD(("Generating Glyph " + itoa(glyph->advance.x) + "|" + ftoa(m_glyph_width) + " (" + itoa(bglyph->left) + "," + itoa(bglyph->top) + ") [" + itoa(bglyph->bitmap.width) + "," + itoa(bglyph->bitmap.rows) + "]").c_str());
86 
87  // Destroy the glyph object
88  FT_Done_Glyph(glyph);
89  }
90 
91  void Font_FT::Glyph::render(Video &vr, const Point2f &position, const float &vratio) const {
92  const float x = int(position.x * vratio + 0.5f) / vratio;
93  const float y = int(position.y * vratio + 0.5f) / vratio;
94 
95  Quadrilateral<Vertex2f_Texture> rect(
96  (Vertex2f_Texture(Point2f(m_upper_left_point.x + x, m_upper_left_point.y + y), m_upper_left_texel)) ,
97  (Vertex2f_Texture(Point2f(m_upper_left_point.x + x, m_lower_right_point.y + y), Point2f(m_upper_left_texel.x, m_lower_right_texel.y))) ,
98  (Vertex2f_Texture(Point2f(m_lower_right_point.x + x, m_lower_right_point.y + y), m_lower_right_texel)) ,
99  (Vertex2f_Texture(Point2f(m_lower_right_point.x + x, m_upper_left_point.y + y), Point2f(m_lower_right_texel.x, m_upper_left_texel.y))) );
100 
101 // ZENI_LOGD(("Rendering Glyph " + ftoa(m_glyph_width) + " (" + ftoa(m_upper_left_point.x + x) + "," + ftoa(m_upper_left_point.y + y) + "), " + ftoa(m_lower_right_point.x + x) + "x" + ftoa(m_lower_right_point.y + y) + ", texture (" + ftoa(m_upper_left_texel.x) + "," + ftoa(m_upper_left_texel.y) + "), " + ftoa(m_lower_right_texel.x) + "x" + ftoa(m_lower_right_texel.y)).c_str());
102 
103  vr.render(rect);
104  }
105 
106  void Font_FT::Glyph::render(Video &vr, const Point3f &position, const Vector3f &right, const Vector3f &down) const {
107  const Vector3f scaled_right = (m_lower_right_point.x - m_upper_left_point.x) * right;
108  const Vector3f scaled_down = (m_lower_right_point.y - m_upper_left_point.y) * down;
109 
110  const Point3f &ul = position + m_upper_left_point.x * right + m_upper_left_point.y * down;
111  const Point3f ll = ul + scaled_down;
112  const Point3f lr = ll + scaled_right;
113  const Point3f ur = ul + scaled_right;
114 
115  Quadrilateral<Vertex3f_Texture> rect(
116  (Vertex3f_Texture(ul, m_upper_left_texel)) ,
117  (Vertex3f_Texture(ll, Point2f(m_upper_left_texel.x, m_lower_right_texel.y))) ,
118  (Vertex3f_Texture(lr, m_lower_right_texel)) ,
119  (Vertex3f_Texture(ur, Point2f(m_lower_right_texel.x, m_upper_left_texel.y))) );
120 
121  vr.render(rect);
122  }
123 
125  : m_ascent(0),
126  m_font_height(0.0f),
127  m_vratio(0.0f)
128  {
129  }
130 
131  Font_FT::Font_FT(const String &filepath,
132  const float &glyph_height,
133  const float &virtual_screen_height)
134  : Font(glyph_height,
135  (virtual_screen_height < MINIMUM_VIRTUAL_SCREEN_HEIGHT ||
136  virtual_screen_height > MAXIMUM_VIRTUAL_SCREEN_HEIGHT) ?
137  float(get_Window().get_height()) : virtual_screen_height,
138  filepath),
139  m_ascent(0),
140  m_font_height(glyph_height),
141 #ifdef TEMP_DISABLE
142  m_vratio(1.0f)
143 #else
144  m_vratio(get_Window().get_height() / get_virtual_screen_height())
145 #endif
146  {
147  ZENI_LOGD(("Generating font '" + filepath + "', size " + ftoa(m_font_height) + ", ratio " + ftoa(m_vratio)).c_str());
148  init(filepath);
149  }
150 
151  float Font_FT::get_text_width(const String &text) const {
152  float max_width = 0.0f, width = 0.0f;
153  unsigned int pos = 0;
154  const unsigned int size = static_cast<unsigned int>(text.size());
155 
156  for(; pos < size; ++pos)
157  if(text[pos] != '\r' && text[pos] != '\n')
158  width += m_glyph[int(text[pos])].get_glyph_width();
159  else {
160  max_width = std::max(max_width, width);
161  width = 0.0f;
162  }
163 
164  return std::max(max_width, width);
165  }
166 
167  void Font_FT::render_text(const String &text, const Point2f &position, const Color &color, const JUSTIFY &justify) const {
168  Video &vr = get_Video();
169  const float &x = position.x;
170  const float &y = position.y;
171 
172  const Color previous_color = vr.get_Color();
173 
174  vr.set_Color(color);
175  vr.apply_Texture(*m_texture);
176 
177  float cx, x_diff, cy = y;
178  unsigned int i = 0u;
179 
180 NEXT_LINE:
181 
182  cx = x;
183  x_diff = 0.0f;
184 
185  if(justify != ZENI_LEFT) {
186  for(unsigned int j = i; j < text.size(); ++j) {
187  if(text[j] == '\r' || text[j] == '\n')
188  break;
189 
190  x_diff -= m_glyph[int(text[j])].get_glyph_width();
191  }
192 
193  if(justify == ZENI_CENTER)
194  cx += x_diff / 2u;
195  else if(justify == ZENI_RIGHT)
196  cx += x_diff;
197  }
198 
199  for(; i < text.size(); ++i) {
200  if(text[i] == '\r' && i+1 < text.size() && text[i+1] == '\n')
201  ++i;
202 
203  if(text[i] == '\r' || text[i] == '\n') {
204  ++i;
205  cy += m_font_height;
206  goto NEXT_LINE;
207  }
208  else {
209  m_glyph[int(text[i])].render(vr, Point2f(cx, cy), m_vratio);
210  cx += m_glyph[int(text[i])].get_glyph_width();
211  }
212  }
213 
214  vr.unapply_Texture();
215 
216  vr.set_Color(previous_color);
217  }
218 
219  void Font_FT::render_text(const String &text, const Point3f &position, const Vector3f &right, const Vector3f &down, const Color &color, const JUSTIFY &justify) const {
220  Video &vr = get_Video();
221 
222  const Color previous_color = vr.get_Color();
223 
224  vr.set_Color(color);
225  vr.apply_Texture(*m_texture);
226 
227  Point3f pos, vertical_pos = position;
228  float x_diff;
229  unsigned int i = 0u;
230 
231 NEXT_LINE_2:
232 
233  pos = vertical_pos;
234  x_diff = 0.0f;
235 
236  if(justify != ZENI_LEFT) {
237  for(unsigned int j = i; j < text.size(); ++j) {
238  if(text[j] == '\r' || text[j] == '\n')
239  break;
240 
241  x_diff -= m_glyph[int(text[j])].get_glyph_width();
242  }
243 
244  if(justify == ZENI_CENTER)
245  pos += x_diff / 2.0f * right;
246  else if(justify == ZENI_RIGHT)
247  pos += x_diff * right;
248  }
249 
250  for(; i < text.size(); ++i) {
251  if(text[i] == '\r' && i+1 < text.size() && text[i+1] == '\n')
252  ++i;
253 
254  if(text[i] == '\r' || text[i] == '\n') {
255  ++i;
256  vertical_pos += m_font_height * down;
257  goto NEXT_LINE_2;
258  }
259  else {
260  m_glyph[int(text[i])].render(vr, pos, right, down);
261  pos += m_glyph[int(text[i])].get_glyph_width() * right;
262  }
263  }
264 
265  vr.unapply_Texture();
266 
267  vr.set_Color(previous_color);
268  }
269 
270  void Font_FT::init(const String &filepath) {
271  String filename(filepath.c_str());
272  String file;
274 
275  FT_Open_Args foargs;
276  memset(&foargs, 0, sizeof(FT_Open_Args));
277  foargs.flags = FT_OPEN_MEMORY;
278  foargs.memory_base = reinterpret_cast<const FT_Byte *>(file.c_str());
279  foargs.memory_size = FT_Long(file.size());
280 
281  const int height = int(get_text_height() * m_vratio + 0.5f);
282 
283  //Create and initilize a freetype font library.
285  if(FT_Init_FreeType(&library)) {
286  ZENI_LOGE("FT_Init_FreeType(...) failed.");
287  throw Error("FT_Init_FreeType(...) failed.");
288  }
289  ZENI_LOGD("FT_Init_FreeType(...) success.");
290 
291  //The object in which Freetype holds information on a given
292  //font is called a "face".
293  FT_Face face;
294 
295  //This is where we load in the font information from the file.
296  //Of all the places where the code might die, this is the most likely,
297  //as FT_New_Face will die if the font file does not exist or is somehow broken.
298  if(FT_Open_Face(library, &foargs, 0, &face)) {
299  ZENI_LOGE("FT_Open_Face(...) failed.");
300  throw Error("FT_Open_Face(...) failed.");
301  }
302  ZENI_LOGD("FT_Open_Face(...) success.");
303 
304  if(FT_Set_Pixel_Sizes(face, 0, height)) {
305  ZENI_LOGE("FT_Set_Pixel_Sizes(...) failed.");
306  throw Error("FT_Set_Pixel_Sizes(...) failed.");
307  }
308  ZENI_LOGD("FT_Set_Pixel_Sizes(...) success.");
309 
310  //This is where we actually create each of the fonts display lists.
311  std::vector<Image> glyph(96);
312  Point2i maxsz;
313  for(int i = 32; i != 128; ++i) {
314  Image &img = glyph[i - 32];
315  img = gen_glyph(face, char(i));
316  if(img.width() >= maxsz.x)
317  maxsz.x = img.width() + 1;
318  if(img.height() >= maxsz.y)
319  maxsz.y = img.height() + 1;
320  }
321 
322  Image glyphs(Point2i(next_power_of_two(10 * maxsz.x), next_power_of_two(10 * maxsz.y)), Image::Luminance_Alpha, false);
323  m_glyph.reserve(256);
324  m_glyph.resize(32);
325  for(int i = 0; i != 96; ++i) {
326  const Point2i pos((i % 10) * maxsz.x, (i / 10) * maxsz.y);
327  glyphs.blit(pos, glyph[i]);
328  m_glyph.push_back(Glyph(face, char(i + 32), m_ascent, m_vratio, pos, glyphs.size()));
329  }
330  glyph.clear();
331  m_glyph.resize(256);
332 
333  ZENI_LOGD("Generating Texture from glyphs.");
334  m_texture = std::auto_ptr<Texture>(get_Video().create_Texture(glyphs));
335 
336  //We don't need the face information now that the display
337  //lists have been created, so we free the assosiated resources.
338  ZENI_LOGD("Calling FT_Done_Face(...).");
339  FT_Done_Face(face);
340 
341  //Ditto for the library.
342  ZENI_LOGD("Calling FT_Done_FreeType(...).");
343  FT_Done_FreeType(library);
344  }
345 
346  int Font_FT::next_power_of_two(const int &a) {
347  int rval=1;
348  while(rval<a) rval<<=1;
349  return rval;
350  }
351 
352  Image Font_FT::gen_glyph(FT_Face &face, const char &ch) {
353  //Load the Glyph for our character.
354  if(FT_Load_Char(face, ch, FT_LOAD_RENDER)) {
355  ZENI_LOGE("FT_Load_Char(...) failed.");
356  throw Error("FT_Load_Char(...) failed.");
357  }
358 // ZENI_LOGD("FT_Load_Char(...) success.");
359 
360  //Move the face's glyph into a Glyph object.
361  FT_Glyph glyph;
362  if(FT_Get_Glyph(face->glyph, &glyph)) {
363  ZENI_LOGE("FT_Get_Glyph(...) failed.");
364  throw Error("FT_Get_Glyph(...) failed.");
365  }
366 // ZENI_LOGD("FT_Get_Glyph(...) success.");
367 
368  FT_BitmapGlyph bglyph = reinterpret_cast<FT_BitmapGlyph>(glyph);
369 
370  //Update the maximum Glyph ascent
371  if(bglyph->top > m_ascent)
372  m_ascent = bglyph->top;
373 
374  //Here we fill in the data for the expanded bitmap.
375  //Notice that we are using two channel bitmap (one for
376  //luminocity and one for alpha), but we assign
377  //both luminocity and alpha to the value that we
378  //find in the FreeType bitmap.
379  //We use the ?: operator so that value which we use
380  //will be 0 if we are in the padding zone, and whatever
381  //is the the Freetype bitmap otherwise.
382  Image image(Point2i(bglyph->bitmap.width, bglyph->bitmap.rows), Image::Luminance_Alpha, false);
383  Uint8 * image_data = image.get_data();
384 // ZENI_LOGD("Copying glyph into Image.");
385  for(int pixel = 0, pend = bglyph->bitmap.width * bglyph->bitmap.rows; pixel != pend; ++pixel) {
386  image_data[2 * pixel] = 0xFF;
387  image_data[2 * pixel + 1] = bglyph->bitmap.buffer[pixel];
388  }
389 // ZENI_LOGD("Glyph copied into Image.");
390 
391  //Destroy the glyph object
392  FT_Done_Glyph(glyph);
393 
394  return image;
395  }
396 
397 }
398 
399 #include <Zeni/Undefine.h>
const FT_Byte * memory_base
Definition: freetype.h:1832
static String & load_asset(String &memory, const String &filename)
Load a file into memory.
Definition: File_Ops.cpp:190
signed long FT_Long
Definition: fttypes.h:238
GLuint color
Definition: glew.h:7185
FT_UInt flags
Definition: freetype.h:1831
FT_Bitmap bitmap
Definition: ftglyph.h:165
The Video Rendering Singleton.
Definition: Video.h:71
GLclampf f
Definition: glew.h:3390
int rows
Definition: ftimage.h:312
EGLSurface EGLint x
Definition: eglext.h:293
unsigned char * buffer
Definition: ftimage.h:315
static void render(const Vertex_Buffer_Macrorenderer &macrorenderer, std::vector< Vertex_Buffer::Vertex_Buffer_Range * > &descriptors)
int32_t j
Definition: e_log.c:102
#define memset
Definition: SDL_malloc.c:633
FILE * file
Definition: visualinfo.c:88
EGLSurface EGLint EGLint EGLint EGLint height
Definition: eglext.h:293
#define FT_OPEN_MEMORY
Definition: freetype.h:1732
GLboolean GLboolean GLboolean GLboolean a
Definition: glew.h:8736
const char * c_str() const
Definition: String.cpp:467
FT_Library library
Definition: cffdrivr.c:409
else
Font_FT()
Instantiate a new Font with a call to get_Video().create_Font()
Definition: Font.cpp:124
FT_Done_FreeType(FT_Library library)
Definition: ftinit.c:264
virtual float get_text_width(const String &text) const
Get the width of text rendering using this font. Approximately text_height * text.length() / 2.0f.
Definition: Font.cpp:151
JUSTIFY
Definition: Font.h:68
FT_Init_FreeType(FT_Library *alibrary)
Definition: ftinit.c:232
FT_Set_Pixel_Sizes(FT_Face face, FT_UInt pixel_width, FT_UInt pixel_height)
Definition: ftobjs.c:2927
EGLImageKHR image
Definition: eglext.h:88
unsigned char FT_Byte
Definition: fttypes.h:150
#define FT_LOAD_RENDER
Definition: freetype.h:2514
A 3D Point represented with floats.
Definition: Coordinate.h:133
void apply_Texture(const String &name)
Apply a texture by name.
Definition: Video.hxx:118
A Featureful 3-Space Vector Class.
Definition: Vector3f.h:58
ALuint u
Definition: alMain.h:58
String ftoa(const float &number)
int
Definition: SDL_systhread.c:37
virtual Texture * create_Texture(const Image &image)=0
Function for creating a Texture from an Image.
EGLSurface EGLint EGLint EGLint width
Definition: eglext.h:293
FT_Pos x
Definition: ftimage.h:77
GLenum face
Definition: gl2ext.h:1490
const GLfloat * c
Definition: glew.h:14913
virtual void unapply_Texture()=0
Unapply a texture.
void ZENI_LOGD(const Zeni::String &str)
Definition: Android.h:50
FT_Load_Char(FT_Face face, FT_ULong char_code, FT_Int32 load_flags)
Definition: ftobjs.c:809
Font Abstraction.
Definition: Font.h:70
virtual void set_Color(const Color &color)=0
Set the current color.
Definition: Video.cpp:210
void ZENI_LOGE(const Zeni::String &str)
Definition: Android.h:59
FT_Size size
Definition: freetype.h:950
#define MAXIMUM_VIRTUAL_SCREEN_HEIGHT
Definition: Define.h:86
int width
Definition: ftimage.h:313
Window & get_Window()
Get access to the singleton.
Definition: Window.cpp:392
FT_Get_Glyph(FT_GlyphSlot slot, FT_Glyph *aglyph)
Definition: ftglyph.c:353
GLint GLvoid * img
Definition: glew.h:1371
EGLSurface EGLint EGLint y
Definition: eglext.h:293
Font()
Instantiate a new Font with a call to get_Video().create_Font()
Definition: Font.cpp:35
FT_GlyphSlot glyph
Definition: freetype.h:949
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:129
FT_Open_Face(FT_Library library, const FT_Open_Args *args, FT_Long face_index, FT_Face *aface)
Definition: ftobjs.c:1994
size_t size() const
Definition: String.cpp:310
const Color & get_Color() const
Get the current color.
Definition: Video.hxx:110
Video & get_Video()
Get access to the singleton.
Definition: Video.cpp:149
float get_text_height() const
Get the height of the font. The width is usually half the height, by default.
Definition: Font.hxx:29
#define MINIMUM_VIRTUAL_SCREEN_HEIGHT
Definition: Define.h:85
FT_Done_Face(FT_Face face)
Definition: ftobjs.c:2329
The Error Class.
Definition: Error.h:52
int i
Definition: pngrutil.c:1377
GLfloat right
Definition: glew.h:13816
#define max(x, y)
Definition: os.h:79
A 2D Point represented with floats.
Definition: Coordinate.h:98
FT_Done_Glyph(FT_Glyph glyph)
Definition: ftglyph.c:611
Color.
Definition: Color.h:41
virtual void render_text(const String &text, const Point2f &position, const Color &color, const JUSTIFY &justify=ZENI_LEFT) const
Render text at screen position (x, y), with justification JUSTIFY.
Definition: Font.cpp:167
FT_Long memory_size
Definition: freetype.h:1833
FT_Vector advance
Definition: ftglyph.h:113
GLsizei size
Definition: gl2ext.h:1467