forked from 0ad/0ad
Unicode fonts
This was SVN commit r520.
This commit is contained in:
parent
358f43205a
commit
f149e007e1
@ -3,6 +3,7 @@
|
||||
#include "res/tex.h"
|
||||
#include "res/mem.h"
|
||||
#include "res/font.h"
|
||||
#include "res/unifont.h"
|
||||
|
||||
|
||||
extern int res_reload(const char* fn);
|
||||
|
184
source/lib/res/unifont.cpp
Executable file
184
source/lib/res/unifont.cpp
Executable file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
$Id: unifont.cpp,v 1.1 2004/06/16 15:36:28 philip Exp $
|
||||
|
||||
Unicode OpenGL texture font
|
||||
|
||||
-- Philip Taylor (philip@wildfiregames.com / philip@zaynar.demon.co.uk)
|
||||
(based on Jan Wassenberg's font.cpp/.h)
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "lib.h"
|
||||
#include "res.h"
|
||||
#include "ogl.h"
|
||||
|
||||
#include <string>
|
||||
#include <strstream>
|
||||
#include <map>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
// 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
|
||||
typedef std::map<wchar_t, unsigned short> glyphmap;
|
||||
|
||||
glyphmap* BoundGlyphs = NULL;
|
||||
|
||||
struct UniFont
|
||||
{
|
||||
Handle ht; // handle to font texture
|
||||
glyphmap* glyphs;
|
||||
uint ListBase;
|
||||
int LineSpacing;
|
||||
};
|
||||
|
||||
H_TYPE_DEFINE(UniFont);
|
||||
|
||||
static void UniFont_init(UniFont* f, va_list args)
|
||||
{
|
||||
f->glyphs = new glyphmap;
|
||||
}
|
||||
|
||||
static void UniFont_dtor(UniFont* f)
|
||||
{
|
||||
tex_free(f->ht);
|
||||
glDeleteLists(f->ListBase, (GLsizei)f->glyphs->size());
|
||||
f->glyphs->clear();
|
||||
delete f->glyphs;
|
||||
}
|
||||
|
||||
|
||||
static int UniFont_reload(UniFont* f, const char* fn)
|
||||
{
|
||||
// fn is the base filename, like "fonts/console"
|
||||
// The font definition file is fn+".fnt" and the texture is fn+".tga"
|
||||
|
||||
std::string FilenameBase = fn;
|
||||
|
||||
void* RawFNT;
|
||||
size_t FNTSize;
|
||||
Handle err = vfs_load((FilenameBase+".fnt").c_str(), RawFNT, FNTSize);
|
||||
|
||||
if (err <= 0)
|
||||
return (int)err;
|
||||
|
||||
// Get the data in a nicer object
|
||||
std::istrstream FNTStream ((char*)RawFNT, (int)FNTSize);
|
||||
|
||||
int Version;
|
||||
FNTStream >> Version;
|
||||
assert (Version == 100); // Make sure this is from a recent version of the font builder
|
||||
|
||||
int TextureWidth, TextureHeight;
|
||||
FNTStream >> TextureWidth >> TextureHeight;
|
||||
|
||||
int NumGlyphs;
|
||||
FNTStream >> NumGlyphs;
|
||||
|
||||
FNTStream >> f->LineSpacing;
|
||||
|
||||
f->ListBase = glGenLists(NumGlyphs);
|
||||
assert(f->ListBase != 0); // My Voodoo2 drivers didn't support display lists
|
||||
|
||||
for (int i = 0; i < NumGlyphs; ++i)
|
||||
{
|
||||
int Codepoint, TextureX, TextureY, Width, Height, OffsetX, OffsetY, Advance;
|
||||
FNTStream >> Codepoint >> TextureX >> TextureY >> Width >> Height >> OffsetX >> OffsetY >> Advance;
|
||||
|
||||
GLfloat u = (GLfloat)TextureX / (GLfloat)TextureWidth;
|
||||
GLfloat v = (GLfloat)TextureY / (GLfloat)TextureHeight;
|
||||
GLfloat w = (GLfloat)Width / (GLfloat)TextureWidth;
|
||||
GLfloat h = (GLfloat)Height / (GLfloat)TextureHeight;
|
||||
|
||||
glNewList(f->ListBase+i, GL_COMPILE);
|
||||
glBegin(GL_QUADS);
|
||||
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);
|
||||
glEnd();
|
||||
glTranslatef((GLfloat)Advance, 0, 0);
|
||||
glEndList();
|
||||
|
||||
(*f->glyphs)[(wchar_t)Codepoint] = i;
|
||||
}
|
||||
|
||||
// Load glyph texture
|
||||
const Handle ht = tex_load((FilenameBase+".tga").c_str());
|
||||
if (ht <= 0)
|
||||
return (int)ht;
|
||||
|
||||
tex_upload(ht, GL_NEAREST, GL_ALPHA8, GL_ALPHA);
|
||||
|
||||
f->ht = ht;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Handle unifont_load(const char* fn, int scope)
|
||||
{
|
||||
return h_alloc(H_UniFont, fn, scope);
|
||||
}
|
||||
|
||||
|
||||
int unifont_bind(const Handle h)
|
||||
{
|
||||
H_DEREF(h, UniFont, f);
|
||||
|
||||
tex_bind(f->ht);
|
||||
glListBase(f->ListBase);
|
||||
BoundGlyphs = f->glyphs;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int unifont_linespacing(const Handle h)
|
||||
{
|
||||
H_DEREF(h, UniFont, f);
|
||||
return f->LineSpacing;
|
||||
}
|
||||
|
||||
|
||||
void glwprintf(const wchar_t* fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
const int buf_size = 1024;
|
||||
wchar_t buf[buf_size];
|
||||
|
||||
va_start(args, fmt);
|
||||
if (vsnwprintf(buf, buf_size-1, fmt, args) < 0)
|
||||
debug_out("glwprintf failed (buffer size exceeded?)");
|
||||
va_end(args);
|
||||
|
||||
// Make sure there's always NULL termination
|
||||
buf[buf_size-1] = 0;
|
||||
|
||||
assert(BoundGlyphs != NULL); // You always need to bind something first
|
||||
|
||||
// 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)
|
||||
{
|
||||
glyphmap::iterator it = BoundGlyphs->find(buf[i]);
|
||||
|
||||
if (it == BoundGlyphs->end())
|
||||
it = BoundGlyphs->find(0xFFFD); // Use the missing glyph symbol
|
||||
|
||||
if (it == BoundGlyphs->end()) // Missing the missing glyph symbol - give up
|
||||
{
|
||||
debug_out("Missing the missing glyph in a unifont!");
|
||||
return;
|
||||
}
|
||||
|
||||
buf[i] = (*it).second; // Replace with the display list offset
|
||||
}
|
||||
|
||||
// Execute all the display lists
|
||||
glCallLists((GLsizei)len, GL_UNSIGNED_SHORT, buf);
|
||||
}
|
37
source/lib/res/unifont.h
Executable file
37
source/lib/res/unifont.h
Executable file
@ -0,0 +1,37 @@
|
||||
// $Id: unifont.h,v 1.1 2004/06/16 15:36:28 philip Exp $
|
||||
|
||||
#ifndef __UNIFONT_H__
|
||||
#define __UNIFONT_H__
|
||||
|
||||
//#include "types.h"
|
||||
#include "h_mgr.h"
|
||||
|
||||
|
||||
// Load and return a handle to the font defined
|
||||
// in fn+".fnt" with texture fn+".tga"
|
||||
extern Handle unifont_load(const char* fn, int scope = RES_STATIC);
|
||||
|
||||
// Use the font referenced by h for all subsequent glwprintf() calls.
|
||||
// Must be called before any glwprintf().
|
||||
extern int unifont_bind(Handle h);
|
||||
|
||||
// Output text at current OpenGL modelview pos.
|
||||
extern void glwprintf(const wchar_t* fmt, ...);
|
||||
|
||||
/*
|
||||
glwprintf assumes an environment rougly like:
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_BLEND);
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
*/
|
||||
|
||||
// Return spacing in pixels from one line of text to the next
|
||||
int unifont_linespacing(const Handle h);
|
||||
|
||||
#endif // __UNIFONT_H__
|
Loading…
Reference in New Issue
Block a user