Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
unifont.cpp
Go to the documentation of this file.
1 /* Copyright (c) 2012 Wildfire Games
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining
4  * a copy of this software and associated documentation files (the
5  * "Software"), to deal in the Software without restriction, including
6  * without limitation the rights to use, copy, modify, merge, publish,
7  * distribute, sublicense, and/or sell copies of the Software, and to
8  * permit persons to whom the Software is furnished to do so, subject to
9  * the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 /*
24  * Unicode OpenGL texture font.
25  */
26 
27 #include "precompiled.h"
28 #include "unifont.h"
29 
30 #include <stdio.h>
31 #include <string>
32 #include <sstream>
33 #include <map>
34 
35 #include "ogl_tex.h"
36 #include "lib/res/h_mgr.h"
37 
38 typedef std::map<u16, UnifontGlyphData> glyphmap;
39 
40 struct UniFont
41 {
42  Handle ht; // Handle to font texture
43 
44  bool HasRGB; // true if RGBA, false if ALPHA
45 
47 
49  int Height; // of a capital letter, roughly
50 };
51 
53 
54 static void UniFont_init(UniFont* UNUSED(f), va_list UNUSED(args))
55 {
56 }
57 
58 static void UniFont_dtor(UniFont* f)
59 {
60  // these are all safe, no is_valid flags needed
61  (void)ogl_tex_free(f->ht);
62 
63  SAFE_DELETE(f->glyphs);
64 }
65 
66 // basename is e.g. "console"; the files are "fonts/console.fnt" and "fonts/console.png"
67 // [10..70ms]
68 static Status UniFont_reload(UniFont* f, const PIVFS& vfs, const VfsPath& basename, Handle UNUSED(h))
69 {
70  // already loaded
71  if(f->ht > 0)
72  return INFO::OK;
73 
74  f->glyphs = new glyphmap();
75 
76  const VfsPath path(L"fonts/");
77 
78  // Read font definition file into a stringstream
79  shared_ptr<u8> buf; size_t size;
80  const VfsPath fntName(basename.ChangeExtension(L".fnt"));
81  RETURN_STATUS_IF_ERR(vfs->LoadFile(path / fntName, buf, size)); // [cumulative for 12: 36ms]
82  std::istringstream FNTStream(std::string((const char*)buf.get(), size));
83 
84  int Version;
85  FNTStream >> Version;
86  if (Version < 100 || Version > 101) // Make sure this is from a recent version of the font builder
88 
89  int TextureWidth, TextureHeight;
90  FNTStream >> TextureWidth >> TextureHeight;
91 
92  if (Version >= 101)
93  {
94  std::string Format;
95  FNTStream >> Format;
96  if (Format == "rgba")
97  f->HasRGB = true;
98  else if (Format == "a")
99  f->HasRGB = false;
100  else
101  debug_warn(L"Invalid .fnt format string");
102  }
103 
104  int NumGlyphs;
105  FNTStream >> NumGlyphs;
106 
107  FNTStream >> f->LineSpacing;
108 
109  if (Version >= 101)
110  FNTStream >> f->Height;
111  else
112  f->Height = 0;
113 
114  // [cumulative for 12: 256ms]
115  for (int i = 0; i < NumGlyphs; ++i)
116  {
117  int Codepoint, TextureX, TextureY, Width, Height, OffsetX, OffsetY, Advance;
118  FNTStream >> Codepoint>>TextureX>>TextureY>>Width>>Height>>OffsetX>>OffsetY>>Advance;
119 
120  if (Codepoint < 0 || Codepoint > 0xFFFF)
121  {
122  DEBUG_WARN_ERR(ERR::LOGIC); // Invalid codepoint
123  continue;
124  }
125 
126  if (Version < 101 && Codepoint == 'I')
127  {
128  f->Height = Height;
129  }
130 
131  GLfloat u = (GLfloat)TextureX / (GLfloat)TextureWidth;
132  GLfloat v = (GLfloat)TextureY / (GLfloat)TextureHeight;
133  GLfloat w = (GLfloat)Width / (GLfloat)TextureWidth;
134  GLfloat h = (GLfloat)Height / (GLfloat)TextureHeight;
135 
136  UnifontGlyphData g = { u, -v, u+w, -v+h, (i16)OffsetX, (i16)-OffsetY, (i16)(OffsetX+Width), (i16)(-OffsetY+Height), (i16)Advance };
137  (*f->glyphs)[(u16)Codepoint] = g;
138  }
139 
140  ENSURE(f->Height); // Ensure the height has been found (which should always happen if the font includes an 'I')
141 
142  // Load glyph texture
143  // [cumulative for 12: 20ms]
144  const VfsPath imgName(basename.ChangeExtension(L".png"));
145  Handle ht = ogl_tex_load(vfs, path / imgName);
147  (void)ogl_tex_set_filter(ht, GL_NEAREST);
148 
149  Status err;
150  if (f->HasRGB)
151  {
152  // use format auto-detection
153  err = ogl_tex_upload(ht);
154  }
155  else
156  {
157  // override is necessary because the GL format is chosen as LUMINANCE,
158  // but we want ALPHA. there is no way of knowing what format
159  // 8bpp textures are in - we could adopt a naming convention and
160  // add some TEX_ flags, but that's overkill.
161  err = ogl_tex_upload(ht, GL_ALPHA);
162  }
163 
164  if(err < 0)
165  {
166  (void)ogl_tex_free(ht);
167  return err;
168  }
169 
170  f->ht = ht;
171 
172  return INFO::OK;
173 }
174 
176 {
177  if(f->ht < 0)
181  // <LineSpacing> and <Height> are read directly from font file.
182  // negative values don't make sense, but that's all we can check.
183  if(f->LineSpacing < 0 || f->Height < 0)
185  return INFO::OK;
186 }
187 
188 static Status UniFont_to_string(const UniFont* f, wchar_t* buf)
189 {
190  if (f->ht) // not true if this is called after dtor (which it is)
191  {
192  const VfsPath& path = h_filename(f->ht);
193  swprintf_s(buf, H_STRING_LEN, L"Font %ls", path.string().c_str());
194  }
195  else
196  swprintf_s(buf, H_STRING_LEN, L"Font");
197  return INFO::OK;
198 }
199 
200 
201 Handle unifont_load(const PIVFS& vfs, const VfsPath& pathname, size_t flags)
202 {
203  return h_alloc(H_UniFont, vfs, pathname, flags);
204 }
205 
206 
208 {
209  H_DEREF(h, UniFont, f);
210  return h_free(h, H_UniFont);
211 }
212 
213 
215 {
216  H_DEREF(h, UniFont, f);
217  return f->LineSpacing;
218 }
219 
220 
221 int unifont_height(const Handle h)
222 {
223  H_DEREF(h, UniFont, f);
224  return f->Height;
225 }
226 
227 
228 bool unifont_has_rgb(const Handle h)
229 {
230  UniFont* const f = H_USER_DATA(h, UniFont);
231  if(!f)
232  return false;
233  return f->HasRGB;
234 }
235 
236 
237 int unifont_character_width(const Handle h, wchar_t c)
238 {
239  H_DEREF(h, UniFont, f);
240  glyphmap::iterator it = f->glyphs->find(c);
241 
242  if (it == f->glyphs->end())
243  it = f->glyphs->find(0xFFFD); // Use the missing glyph symbol
244 
245  return it->second.xadvance;
246 }
247 
248 Status unifont_stringsize(const Handle h, const wchar_t* text, int& width, int& height)
249 {
250  H_DEREF(h, UniFont, f);
251 
252  width = 0;
253  height = f->Height;
254 
255  size_t len = wcslen(text);
256 
257  for (size_t i = 0; i < len; ++i)
258  {
259  glyphmap::iterator it = f->glyphs->find(text[i]);
260 
261  if (it == f->glyphs->end())
262  it = f->glyphs->find(0xFFFD); // Use the missing glyph symbol
263 
264  if (it == f->glyphs->end()) // Missing the missing glyph symbol - give up
265  {
266  DEBUG_WARN_ERR(ERR::LOGIC); // Missing the missing glyph in a unifont!
267  return INFO::OK;
268  }
269 
270  width += it->second.xadvance; // Add the character's advance distance
271  }
272 
273  return INFO::OK;
274 }
275 
277 {
278  UniFont* const f = H_USER_DATA(h, UniFont);
279  if(!f)
280  {
282  static glyphmap dummy;
283  return dummy;
284  }
285 
286  return *f->glyphs;
287 }
288 
290 {
291  UniFont* const f = H_USER_DATA(h, UniFont);
292  if(!f)
293  {
295  return 0;
296  }
297 
298  return f->ht;
299 }
Status h_free(Handle &h, H_Type type)
Definition: h_mgr.cpp:583
const Status LOGIC
Definition: status.h:409
bool unifont_has_rgb(const Handle h)
Definition: unifont.cpp:228
const Status _1
Definition: status.h:441
#define UNUSED(param)
mark a function parameter as unused and avoid the corresponding compiler warning. ...
const glyphmap & unifont_get_glyphs(const Handle h)
Definition: unifont.cpp:276
const Status OK
Definition: status.h:386
static Status UniFont_reload(UniFont *f, const PIVFS &vfs, const VfsPath &basename, Handle h)
Definition: unifont.cpp:68
int unifont_linespacing(const Handle h)
Definition: unifont.cpp:214
Status ogl_tex_free(Handle &ht)
Release this texture reference.
Definition: ogl_tex.cpp:586
bool HasRGB
Definition: unifont.cpp:44
shared_ptr< IVFS > PIVFS
Definition: vfs.h:226
const Status _3
Definition: status.h:443
Handle ht
Definition: unifont.cpp:42
int LineSpacing
Definition: unifont.cpp:48
int swprintf_s(wchar_t *buf, size_t max_chars, const wchar_t *fmt,...) WPRINTF_ARGS(3)
VfsPath h_filename(const Handle h)
Definition: h_mgr.cpp:625
const Status INVALID_HANDLE
Definition: status.h:419
int unifont_character_width(const Handle h, wchar_t c)
Definition: unifont.cpp:237
Handle h_alloc(H_Type type, const PIVFS &vfs, const VfsPath &pathname, size_t flags,...)
Definition: h_mgr.cpp:519
#define i16
Definition: types.h:35
Status unifont_stringsize(const Handle h, const wchar_t *text, int &width, int &height)
Determine pixel extents of a string.
Definition: unifont.cpp:248
static void UniFont_init(UniFont *f, va_list args)
Definition: unifont.cpp:54
#define H_DEREF(h, type, var)
Definition: h_mgr.h:341
#define H_TYPE_DEFINE(type)
Definition: h_mgr.h:307
#define ENSURE(expr)
ensure the expression &lt;expr&gt; evaluates to non-zero.
Definition: debug.h:282
LIB_API int debug_IsPointerBogus(const void *p)
check if a pointer appears to be totally invalid.
Definition: udbg.cpp:114
Definition: path.h:75
const String & string() const
Definition: path.h:123
glyphmap * glyphs
Definition: unifont.cpp:46
static Status UniFont_to_string(const UniFont *f, wchar_t *buf)
Definition: unifont.cpp:188
#define SAFE_DELETE(p)
delete memory ensuing from new and set the pointer to zero (thus making double-frees safe / a no-op) ...
i64 Status
Error handling system.
Definition: status.h:171
i64 Handle
`handle&#39; representing a reference to a resource (sound, texture, etc.)
Definition: handle.h:41
Handle ogl_tex_load(const PIVFS &vfs, const VfsPath &pathname, size_t flags)
Load and return a handle to the texture.
Definition: ogl_tex.cpp:542
#define DEBUG_WARN_ERR(status)
display the error dialog with text corresponding to the given error code.
Definition: debug.h:331
#define u16
Definition: types.h:40
Handle unifont_load(const PIVFS &vfs, const VfsPath &pathname, size_t flags)
Load a font.
Definition: unifont.cpp:201
static void UniFont_dtor(UniFont *f)
Definition: unifont.cpp:58
Path ChangeExtension(Path extension) const
Definition: path.h:185
int unifont_height(const Handle h)
Definition: unifont.cpp:221
Status ogl_tex_set_filter(Handle ht, GLint filter)
Override default filter (see ogl_tex_set_defaults) for this texture.
Definition: ogl_tex.cpp:638
std::map< u16, UnifontGlyphData > glyphmap
Definition: unifont.cpp:38
int Height
Definition: unifont.cpp:49
#define WARN_RETURN(status)
Definition: status.h:255
const Status FAIL
Definition: status.h:406
#define debug_warn(expr)
display the error dialog with the given text.
Definition: debug.h:324
const Status _2
Definition: status.h:442
const size_t H_STRING_LEN
Definition: h_mgr.h:371
Status unifont_unload(Handle &h)
Release a handle to a previously loaded font (subject to reference counting).
Definition: unifont.cpp:207
static Status UniFont_validate(const UniFont *f)
Definition: unifont.cpp:175
#define H_USER_DATA(h, type)
Definition: h_mgr.h:334
Handle unifont_get_texture(const Handle h)
Definition: unifont.cpp:289
Status ogl_tex_upload(const Handle ht, GLenum fmt_ovr, int q_flags_ovr, GLint int_fmt_ovr)
Upload texture to OpenGL.
Definition: ogl_tex.cpp:912
#define RETURN_STATUS_IF_ERR(expression)
Definition: status.h:276