2006-04-11 16:59:08 -07:00
|
|
|
/**
|
|
|
|
|
* =========================================================================
|
|
|
|
|
* File : unifont.cpp
|
|
|
|
|
* Project : 0 A.D.
|
|
|
|
|
* Description : Unicode OpenGL texture font.
|
|
|
|
|
* =========================================================================
|
|
|
|
|
*/
|
2004-06-16 08:36:49 -07:00
|
|
|
|
|
|
|
|
#include "precompiled.h"
|
2007-01-01 13:25:47 -08:00
|
|
|
#include "unifont.h"
|
2004-06-16 08:36:49 -07:00
|
|
|
|
2007-01-01 13:25:47 -08:00
|
|
|
#include <stdio.h>
|
2004-06-16 08:36:49 -07:00
|
|
|
#include <string>
|
2004-06-18 11:34:04 -07:00
|
|
|
#include <sstream>
|
2004-06-16 08:36:49 -07:00
|
|
|
#include <map>
|
|
|
|
|
|
2006-06-29 15:52:50 -07:00
|
|
|
#include "ogl_tex.h"
|
2007-12-20 12:14:21 -08:00
|
|
|
#include "../h_mgr.h"
|
|
|
|
|
#include "lib/file/vfs/vfs.h"
|
|
|
|
|
extern PIVFS g_VFS;
|
2006-06-29 15:52:50 -07:00
|
|
|
|
2004-06-16 08:36:49 -07:00
|
|
|
// This isn't particularly efficient - it can be improved if we
|
|
|
|
|
// (a) care enough, and (b) know about fixed ranges of characters
|
|
|
|
|
// that the fonts usually contain
|
2004-07-13 15:48:53 -07:00
|
|
|
typedef std::map<wchar_t, unsigned short> glyphmap_id;
|
|
|
|
|
// Store the size separately, because it's used separately
|
|
|
|
|
typedef std::map<wchar_t, int> glyphmap_size;
|
2004-06-16 08:36:49 -07:00
|
|
|
|
2005-12-12 11:19:30 -08:00
|
|
|
static glyphmap_id* BoundGlyphs = NULL;
|
2004-06-16 08:36:49 -07:00
|
|
|
|
|
|
|
|
struct UniFont
|
|
|
|
|
{
|
2004-09-04 13:35:12 -07:00
|
|
|
Handle ht; // Handle to font texture
|
|
|
|
|
|
|
|
|
|
glyphmap_id* glyphs_id; // Stored as pointers to keep the struct's size down. (sizeof(std::map)==12, though that's probably not enough to matter)
|
2004-07-13 15:48:53 -07:00
|
|
|
glyphmap_size* glyphs_size;
|
2004-09-04 13:35:12 -07:00
|
|
|
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 11:48:32 -07:00
|
|
|
GLuint ListBase;
|
2004-06-16 08:36:49 -07:00
|
|
|
int LineSpacing;
|
2004-09-04 13:35:12 -07:00
|
|
|
int Height; // of a capital letter, roughly
|
2004-06-16 08:36:49 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
H_TYPE_DEFINE(UniFont);
|
|
|
|
|
|
2005-10-11 21:35:01 -07:00
|
|
|
static void UniFont_init(UniFont* UNUSED(f), va_list UNUSED(args))
|
2004-06-16 08:36:49 -07:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void UniFont_dtor(UniFont* f)
|
|
|
|
|
{
|
2005-10-11 21:35:01 -07:00
|
|
|
// these are all safe, no is_valid flags needed
|
|
|
|
|
(void)ogl_tex_free(f->ht);
|
|
|
|
|
|
2004-07-13 15:48:53 -07:00
|
|
|
glDeleteLists(f->ListBase, (GLsizei)f->glyphs_id->size());
|
2005-10-11 21:35:01 -07:00
|
|
|
f->ListBase = 0;
|
2004-06-16 08:36:49 -07:00
|
|
|
|
2005-10-11 21:35:01 -07:00
|
|
|
SAFE_DELETE(f->glyphs_id);
|
|
|
|
|
SAFE_DELETE(f->glyphs_size);
|
|
|
|
|
}
|
2004-06-16 08:36:49 -07:00
|
|
|
|
2007-12-22 10:15:52 -08:00
|
|
|
// basename is e.g. "console"; the files are "fonts/console.fnt" and "fonts/console.tga"
|
2006-06-29 15:52:50 -07:00
|
|
|
// [10..70ms]
|
2007-12-22 10:15:52 -08:00
|
|
|
static LibError UniFont_reload(UniFont* f, const VfsPath& basename, Handle UNUSED(h))
|
2004-06-16 08:36:49 -07:00
|
|
|
{
|
2005-10-11 21:35:01 -07:00
|
|
|
// already loaded
|
|
|
|
|
if(f->ht > 0)
|
2006-09-22 06:19:40 -07:00
|
|
|
return INFO::OK;
|
2005-10-11 21:35:01 -07:00
|
|
|
|
2006-12-19 19:22:24 -08:00
|
|
|
f->glyphs_id = new glyphmap_id();
|
|
|
|
|
f->glyphs_size = new glyphmap_size();
|
2005-10-11 21:35:01 -07:00
|
|
|
|
2007-12-22 10:15:52 -08:00
|
|
|
const VfsPath path("fonts/");
|
2004-06-16 08:36:49 -07:00
|
|
|
|
2005-09-29 10:33:30 -07:00
|
|
|
// Read font definition file into a stringstream
|
2007-12-20 12:14:21 -08:00
|
|
|
shared_ptr<u8> buf; size_t size;
|
2007-12-22 10:15:52 -08:00
|
|
|
const VfsPath fntName(basename.string() + ".fnt");
|
|
|
|
|
RETURN_ERR(g_VFS->LoadFile(path/fntName, buf, size)); // [cumulative for 12: 36ms]
|
|
|
|
|
std::istringstream FNTStream (std::string((const char*)buf.get(), size));
|
2004-07-29 09:12:27 -07:00
|
|
|
|
2004-06-16 08:36:49 -07:00
|
|
|
int Version;
|
|
|
|
|
FNTStream >> Version;
|
2004-08-24 14:07:20 -07:00
|
|
|
if (Version != 100) // Make sure this is from a recent version of the font builder
|
2007-12-20 12:14:21 -08:00
|
|
|
WARN_RETURN(ERR::FAIL);
|
2004-06-16 08:36:49 -07:00
|
|
|
|
|
|
|
|
int TextureWidth, TextureHeight;
|
|
|
|
|
FNTStream >> TextureWidth >> TextureHeight;
|
|
|
|
|
|
|
|
|
|
int NumGlyphs;
|
|
|
|
|
FNTStream >> NumGlyphs;
|
|
|
|
|
|
|
|
|
|
FNTStream >> f->LineSpacing;
|
|
|
|
|
|
2004-09-04 13:35:12 -07:00
|
|
|
if (Version >= 101)
|
|
|
|
|
FNTStream >> f->Height;
|
|
|
|
|
else
|
|
|
|
|
f->Height = 0;
|
|
|
|
|
|
2004-06-16 08:36:49 -07:00
|
|
|
f->ListBase = glGenLists(NumGlyphs);
|
2004-08-24 14:07:20 -07:00
|
|
|
if (f->ListBase == 0) // My Voodoo2 drivers didn't support display lists (although I'd be surprised if they got this far)
|
2006-09-22 06:19:40 -07:00
|
|
|
WARN_RETURN(ERR::FAIL);
|
2004-06-16 08:36:49 -07:00
|
|
|
|
2006-06-29 15:52:50 -07:00
|
|
|
// [cumulative for 12: 256ms]
|
2004-06-16 08:36:49 -07:00
|
|
|
for (int i = 0; i < NumGlyphs; ++i)
|
|
|
|
|
{
|
2004-09-04 13:35:12 -07:00
|
|
|
int Codepoint, TextureX, TextureY, Width, Height, OffsetX, OffsetY, Advance;
|
|
|
|
|
FNTStream >> Codepoint>>TextureX>>TextureY>>Width>>Height>>OffsetX>>OffsetY>>Advance;
|
2004-06-16 08:36:49 -07:00
|
|
|
|
2007-01-01 13:25:47 -08:00
|
|
|
if (Codepoint > 0xFFFF)
|
2004-08-24 14:07:20 -07:00
|
|
|
{
|
2007-12-20 12:14:21 -08:00
|
|
|
debug_assert(0); // Invalid codepoint
|
2004-08-24 14:07:20 -07:00
|
|
|
continue;
|
|
|
|
|
}
|
2004-07-24 07:04:40 -07:00
|
|
|
|
2004-09-04 13:35:12 -07:00
|
|
|
if (Version < 101 && Codepoint == 'I')
|
|
|
|
|
{
|
|
|
|
|
f->Height = Height;
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-16 08:36:49 -07:00
|
|
|
GLfloat u = (GLfloat)TextureX / (GLfloat)TextureWidth;
|
|
|
|
|
GLfloat v = (GLfloat)TextureY / (GLfloat)TextureHeight;
|
|
|
|
|
GLfloat w = (GLfloat)Width / (GLfloat)TextureWidth;
|
|
|
|
|
GLfloat h = (GLfloat)Height / (GLfloat)TextureHeight;
|
|
|
|
|
|
2005-01-23 10:23:29 -08:00
|
|
|
// It might be better to use vertex arrays instead of display lists,
|
|
|
|
|
// but this works well enough for now.
|
2006-06-29 15:52:50 -07:00
|
|
|
// [cumulative for 12: 180ms]
|
2004-06-16 08:36:49 -07:00
|
|
|
glNewList(f->ListBase+i, GL_COMPILE);
|
|
|
|
|
glBegin(GL_QUADS);
|
2005-01-07 06:10:14 -08:00
|
|
|
glTexCoord2f(u, -v); glVertex2i(OffsetX, -OffsetY);
|
|
|
|
|
glTexCoord2f(u+w, -v); glVertex2i(OffsetX+Width, -OffsetY);
|
|
|
|
|
glTexCoord2f(u+w, -v+h); glVertex2i(OffsetX+Width, -OffsetY+Height);
|
|
|
|
|
glTexCoord2f(u, -v+h); glVertex2i(OffsetX, -OffsetY+Height);
|
2004-06-16 08:36:49 -07:00
|
|
|
glEnd();
|
|
|
|
|
glTranslatef((GLfloat)Advance, 0, 0);
|
|
|
|
|
glEndList();
|
|
|
|
|
|
2006-06-29 15:52:50 -07:00
|
|
|
// [cumulative for 12: 20ms]
|
2004-07-24 07:04:40 -07:00
|
|
|
(*f->glyphs_id)[(wchar_t)Codepoint] = (unsigned short)i;
|
2004-07-13 15:48:53 -07:00
|
|
|
(*f->glyphs_size)[(wchar_t)Codepoint] = Advance;
|
2004-06-16 08:36:49 -07:00
|
|
|
}
|
|
|
|
|
|
2005-06-27 21:06:25 -07:00
|
|
|
debug_assert(f->Height); // Ensure the height has been found (which should always happen if the font includes an 'I')
|
2004-09-04 13:35:12 -07:00
|
|
|
|
2004-06-16 08:36:49 -07:00
|
|
|
// Load glyph texture
|
2006-06-29 15:52:50 -07:00
|
|
|
// [cumulative for 12: 20ms]
|
2007-12-22 10:15:52 -08:00
|
|
|
const VfsPath tgaName(basename.string() + ".tga");
|
|
|
|
|
Handle ht = ogl_tex_load(path/tgaName);
|
2005-09-29 10:33:30 -07:00
|
|
|
RETURN_ERR(ht);
|
2005-09-28 22:00:20 -07:00
|
|
|
(void)ogl_tex_set_filter(ht, GL_NEAREST);
|
2005-09-29 10:33:30 -07:00
|
|
|
// override is necessary because the GL format is chosen as LUMINANCE,
|
|
|
|
|
// but we want ALPHA. there is no way of knowing what format
|
|
|
|
|
// 8bpp textures are in - we could adopt a naming convention and
|
|
|
|
|
// add some TEX_ flags, but that's overkill.
|
2005-12-11 14:23:55 -08:00
|
|
|
LibError err = ogl_tex_upload(ht, GL_ALPHA);
|
2005-09-29 10:33:30 -07:00
|
|
|
if(err < 0)
|
|
|
|
|
{
|
|
|
|
|
(void)ogl_tex_free(ht);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
2004-06-16 08:36:49 -07:00
|
|
|
|
2005-09-29 10:33:30 -07:00
|
|
|
f->ht = ht;
|
2006-06-29 15:52:50 -07:00
|
|
|
|
2006-09-22 06:19:40 -07:00
|
|
|
return INFO::OK;
|
2004-06-16 08:36:49 -07:00
|
|
|
}
|
|
|
|
|
|
2005-12-11 14:23:55 -08:00
|
|
|
static LibError UniFont_validate(const UniFont* f)
|
2005-10-11 21:35:01 -07:00
|
|
|
{
|
|
|
|
|
if(f->ht < 0)
|
2006-09-22 06:19:40 -07:00
|
|
|
WARN_RETURN(ERR::_1);
|
2005-10-11 21:35:01 -07:00
|
|
|
if(debug_is_pointer_bogus(f->glyphs_id) || debug_is_pointer_bogus(f->glyphs_size))
|
2006-09-22 06:19:40 -07:00
|
|
|
WARN_RETURN(ERR::_2);
|
2005-10-11 21:35:01 -07:00
|
|
|
// <LineSpacing> and <Height> are read directly from font file.
|
|
|
|
|
// negative values don't make sense, but that's all we can check.
|
|
|
|
|
if(f->LineSpacing < 0 || f->Height < 0)
|
2006-09-22 06:19:40 -07:00
|
|
|
WARN_RETURN(ERR::_3);
|
2005-10-11 21:35:01 -07:00
|
|
|
if(f->ListBase == 0 || f->ListBase > 1000000) // suspicious
|
2006-09-22 06:19:40 -07:00
|
|
|
WARN_RETURN(ERR::_4);
|
|
|
|
|
return INFO::OK;
|
2005-10-11 21:35:01 -07:00
|
|
|
}
|
|
|
|
|
|
2006-12-16 16:49:09 -08:00
|
|
|
static LibError UniFont_to_string(const UniFont* f, char* buf)
|
2005-10-21 00:47:38 -07:00
|
|
|
{
|
2006-12-19 19:22:24 -08:00
|
|
|
if (f->ht) // not true if this is called after dtor (which it is)
|
2008-07-17 10:00:00 -07:00
|
|
|
{
|
|
|
|
|
const VfsPath& path = h_filename(f->ht);
|
|
|
|
|
snprintf(buf, H_STRING_LEN, "Font %s", path.string().c_str());
|
|
|
|
|
}
|
2006-12-19 19:22:24 -08:00
|
|
|
else
|
|
|
|
|
snprintf(buf, H_STRING_LEN, "Font");
|
2006-09-22 06:19:40 -07:00
|
|
|
return INFO::OK;
|
2005-10-21 00:47:38 -07:00
|
|
|
}
|
|
|
|
|
|
2004-06-16 08:36:49 -07:00
|
|
|
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 11:48:32 -07:00
|
|
|
Handle unifont_load(const VfsPath& pathname, int flags)
|
2004-06-16 08:36:49 -07:00
|
|
|
{
|
2007-12-22 10:15:52 -08:00
|
|
|
return h_alloc(H_UniFont, pathname, flags);
|
2004-06-16 08:36:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2005-12-11 14:23:55 -08:00
|
|
|
LibError unifont_unload(Handle& h)
|
2004-07-12 13:08:34 -07:00
|
|
|
{
|
|
|
|
|
return h_free(h, H_UniFont);
|
|
|
|
|
}
|
|
|
|
|
|
2005-01-23 10:23:29 -08:00
|
|
|
|
2005-12-11 14:23:55 -08:00
|
|
|
LibError unifont_bind(const Handle h)
|
2004-06-16 08:36:49 -07:00
|
|
|
{
|
|
|
|
|
H_DEREF(h, UniFont, f);
|
|
|
|
|
|
2005-09-01 19:58:40 -07:00
|
|
|
ogl_tex_bind(f->ht);
|
2004-06-16 08:36:49 -07:00
|
|
|
glListBase(f->ListBase);
|
2004-07-13 15:48:53 -07:00
|
|
|
BoundGlyphs = f->glyphs_id;
|
2004-06-16 08:36:49 -07:00
|
|
|
|
2006-09-22 06:19:40 -07:00
|
|
|
return INFO::OK;
|
2004-06-16 08:36:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int unifont_linespacing(const Handle h)
|
|
|
|
|
{
|
|
|
|
|
H_DEREF(h, UniFont, f);
|
|
|
|
|
return f->LineSpacing;
|
|
|
|
|
}
|
|
|
|
|
|
2005-01-23 10:23:29 -08:00
|
|
|
|
2004-10-14 03:09:51 -07:00
|
|
|
int unifont_height(const Handle h)
|
|
|
|
|
{
|
|
|
|
|
H_DEREF(h, UniFont, f);
|
|
|
|
|
return f->Height;
|
|
|
|
|
}
|
2004-06-16 08:36:49 -07:00
|
|
|
|
2005-01-23 10:23:29 -08:00
|
|
|
|
2005-12-11 14:23:55 -08:00
|
|
|
int unifont_character_width(const Handle h, wchar_t c)
|
2004-11-24 15:47:48 -08:00
|
|
|
{
|
|
|
|
|
H_DEREF(h, UniFont, f);
|
|
|
|
|
glyphmap_size::iterator it = f->glyphs_size->find(c);
|
|
|
|
|
|
|
|
|
|
if (it == f->glyphs_size->end())
|
|
|
|
|
it = f->glyphs_size->find(0xFFFD); // Use the missing glyph symbol
|
|
|
|
|
|
|
|
|
|
return it->second;
|
|
|
|
|
}
|
|
|
|
|
|
2005-01-23 10:23:29 -08:00
|
|
|
|
|
|
|
|
void glvwprintf(const wchar_t* fmt, va_list args)
|
2004-06-16 08:36:49 -07:00
|
|
|
{
|
|
|
|
|
const int buf_size = 1024;
|
|
|
|
|
wchar_t buf[buf_size];
|
|
|
|
|
|
2007-10-13 11:22:20 -07:00
|
|
|
int ret = vswprintf(buf, buf_size-1, fmt, args);
|
|
|
|
|
if(ret < 0) {
|
|
|
|
|
debug_printf("glwprintf failed (buffer size exceeded?) - return value %d, errno %d\n", ret, errno);
|
|
|
|
|
}
|
2004-06-16 08:36:49 -07:00
|
|
|
|
2004-09-04 13:35:12 -07:00
|
|
|
// Make sure there's always null termination
|
2004-06-16 08:36:49 -07:00
|
|
|
buf[buf_size-1] = 0;
|
|
|
|
|
|
2005-06-27 21:06:25 -07:00
|
|
|
debug_assert(BoundGlyphs != NULL); // You always need to bind something first
|
2004-06-16 08:36:49 -07:00
|
|
|
|
|
|
|
|
// Count the number of characters
|
|
|
|
|
size_t len = wcslen(buf);
|
|
|
|
|
|
|
|
|
|
// Replace every wchar_t with the display list offset for the appropriate glyph
|
|
|
|
|
for (size_t i = 0; i < len; ++i)
|
|
|
|
|
{
|
2004-07-13 15:48:53 -07:00
|
|
|
glyphmap_id::iterator it = BoundGlyphs->find(buf[i]);
|
2004-06-16 08:36:49 -07:00
|
|
|
|
|
|
|
|
if (it == BoundGlyphs->end())
|
|
|
|
|
it = BoundGlyphs->find(0xFFFD); // Use the missing glyph symbol
|
|
|
|
|
|
|
|
|
|
if (it == BoundGlyphs->end()) // Missing the missing glyph symbol - give up
|
|
|
|
|
{
|
2007-12-20 12:14:21 -08:00
|
|
|
debug_assert(0); // Missing the missing glyph in a unifont!
|
2004-06-16 08:36:49 -07:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-04 13:35:12 -07:00
|
|
|
buf[i] = it->second; // Replace with the display list offset
|
2004-06-16 08:36:49 -07:00
|
|
|
}
|
2004-06-21 05:49:37 -07:00
|
|
|
|
2004-08-24 14:07:20 -07:00
|
|
|
// 0 glyphs -> nothing to do (avoid BoundsChecker warning)
|
|
|
|
|
if (!len)
|
2004-06-21 05:49:37 -07:00
|
|
|
return;
|
|
|
|
|
|
2004-06-16 08:36:49 -07:00
|
|
|
// Execute all the display lists
|
2004-08-24 14:07:20 -07:00
|
|
|
glCallLists((GLsizei)len, sizeof(wchar_t)==4 ? GL_INT : GL_UNSIGNED_SHORT, buf);
|
2004-06-16 08:36:49 -07:00
|
|
|
}
|
2004-07-13 15:48:53 -07:00
|
|
|
|
2005-01-23 10:23:29 -08:00
|
|
|
|
|
|
|
|
void glwprintf(const wchar_t* fmt, ...)
|
|
|
|
|
{
|
|
|
|
|
va_list args;
|
|
|
|
|
va_start(args, fmt);
|
|
|
|
|
glvwprintf(fmt, args);
|
|
|
|
|
va_end(args);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2005-12-11 14:23:55 -08:00
|
|
|
LibError unifont_stringsize(const Handle h, const wchar_t* text, int& width, int& height)
|
2004-09-05 19:24:34 -07:00
|
|
|
{
|
|
|
|
|
H_DEREF(h, UniFont, f);
|
|
|
|
|
|
|
|
|
|
width = 0;
|
|
|
|
|
height = f->Height;
|
|
|
|
|
|
|
|
|
|
size_t len = wcslen(text);
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < len; ++i)
|
|
|
|
|
{
|
|
|
|
|
glyphmap_size::iterator it = f->glyphs_size->find(text[i]);
|
|
|
|
|
|
|
|
|
|
if (it == f->glyphs_size->end())
|
|
|
|
|
it = f->glyphs_size->find(0xFFFD); // Use the missing glyph symbol
|
|
|
|
|
|
|
|
|
|
if (it == f->glyphs_size->end()) // Missing the missing glyph symbol - give up
|
|
|
|
|
{
|
2007-12-20 12:14:21 -08:00
|
|
|
debug_assert(0); // Missing the missing glyph in a unifont!
|
2006-09-22 06:19:40 -07:00
|
|
|
return INFO::OK;
|
2004-09-05 19:24:34 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
width += it->second; // Add the character's advance distance
|
|
|
|
|
}
|
|
|
|
|
|
2006-09-22 06:19:40 -07:00
|
|
|
return INFO::OK;
|
2004-09-19 04:57:51 -07:00
|
|
|
}
|