00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include "glut-font.h"
00035
00036
00037 #define FREETYPE2_STATIC
00038 #define FTGL_LIBRARY_STATIC
00039
00040
00041 #include "ftgl.h"
00042
00043 #include "perf/perf.h"
00044 #include "wave-glut/wave-glut.h"
00045
00046
00047 namespace glut {
00048
00049
00050
00051 Font::~Font(void) throw() { }
00052 FontManager::~FontManager(void) throw() { }
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063 class DefaultFont : public Font {
00064 public:
00065 ~DefaultFont(void) throw() { }
00066
00067
00068 const char * getName(void) const throw() { return "(default font)"; }
00069 font_rect_t getBoundingRect(IN const char * text) {
00070 ASSERT(text, "null");
00071
00072 int lh = this->getLineHeight();
00073
00074 int drop = 3;
00075
00076 font_rect_t box;
00077 box.lead = 0;
00078 box.drop = drop;
00079 box.rise = lh - drop;
00080 box.trail = glutBitmapLength(GLUT_BITMAP_9_BY_15,
00081 (const byte_t *) text);
00082
00083 return box;
00084 }
00085
00086 void display(IN float x, IN float y, IN float z, IN const char * text) {
00087 ASSERT(text, "null");
00088
00089 glRasterPos3f(x, y, z);
00090 for (; *text; ++text) {
00091 glutBitmapCharacter(GLUT_BITMAP_9_BY_15, *text);
00092 }
00093 }
00094
00095 bool canScale(void) const throw() { return false; }
00096 bool setFaceSize(IN float size) { return false; }
00097 float getFaceSize(void) const throw() { return -1; }
00098 int getLineHeight(void) const throw() { return 15; }
00099
00100 private:
00101 };
00102
00103
00104
00105 class FtglFont : public Font {
00106 public:
00107 ~FtglFont(void) throw() {
00108 if (m_data) {
00109 delete[] m_data;
00110 }
00111 }
00112
00113
00114 const char * getName(void) const throw() { return m_name.c_str(); }
00115 font_rect_t getBoundingRect(IN const char * text) {
00116 ASSERT(text, "null");
00117
00118
00119 FTBBox box = m_font->BBox(text);
00120 font_rect_t fr;
00121 FTPoint u = box.Upper();
00122 FTPoint l = box.Lower();
00123
00124
00125
00126 fr.lead = -l.X();
00127 fr.drop = -l.Y() + 1;
00128
00129 fr.trail = u.X();
00130 fr.rise = u.Y();
00131
00132
00133
00134
00135 return fr;
00136 }
00137 void display(IN float x, IN float y, IN float z, IN const char * text) {
00138 ASSERT(text, "null");
00139
00140 glMatrixMode(GL_MODELVIEW);
00141 glPushMatrix();
00142 glTranslatef(x, y, z);
00143 glScalef(1, -1, 1);
00144 m_font->Render(text);
00145 glPopMatrix();
00146 }
00147
00148 bool canScale(void) const throw() { return true; }
00149 bool setFaceSize(IN float pointSize) {
00150 if (pointSize < 0.5) {
00151 return false;
00152 }
00153 m_font->FaceSize(pointSize);
00154 return true;
00155 }
00156 float getFaceSize(void) const throw() {
00157 return m_font->FaceSize();
00158 }
00159 int getLineHeight(void) const throw() { return m_font->LineHeight(); }
00160
00161
00162 static smart_ptr<FtglFont> create(IN const char * name,
00163 IN byte_t * data,
00164 IN smart_ptr<FTFont>& font) {
00165 ASSERT(name, "null");
00166 ASSERT(font, "null");
00167
00168
00169 smart_ptr<FtglFont> local = new FtglFont;
00170 ASSERT(local, "out of memory");
00171
00172 local->m_name = name;
00173 local->m_font = font;
00174 local->m_data = data;
00175
00176 return local;
00177 }
00178
00179 private:
00180
00181 FtglFont(void) throw() { m_data = NULL; }
00182
00183
00184
00185 byte_t * m_data;
00186 std::string m_name;
00187 smart_ptr<FTFont> m_font;
00188 };
00189
00190
00191
00192 class Mgr : public FontManager {
00193 public:
00194 ~Mgr(void) throw() { }
00195
00196
00197 void initialize(void);
00198
00199
00200 smart_ptr<Font> getFont(IN nstream::Stream * stream);
00201
00202 private:
00203
00204 typedef std::map<std::string, smart_ptr<FtglFont> > font_map_t;
00205
00206
00207
00208 font_map_t m_fonts;
00209 };
00210
00211
00212 void
00213 Mgr::initialize
00214 (
00215 void
00216 )
00217 {
00218 }
00219
00220
00221
00222 smart_ptr<Font>
00223 Mgr::getFont
00224 (
00225 IN nstream::Stream * stream
00226 )
00227 {
00228
00229 if (!stream) {
00230 return getDefaultFont();
00231 }
00232
00233
00234 smart_ptr<nstream::File> file = stream->getFile();
00235 ASSERT(file, "null");
00236 const char * path = file->getName();
00237 ASSERT(path, "null");
00238 smart_ptr<nstream::Manager> mgr = file->getManager();
00239 ASSERT(mgr, "null");
00240 std::string name = mgr->getFullName(path);
00241
00242
00243
00244 font_map_t::iterator i = m_fonts.find(name);
00245 if (m_fonts.end() != i) {
00246 smart_ptr<Font> font = i->second;
00247 ASSERT(font, "null font in map?");
00248 return font;
00249 }
00250
00251
00252 perf::Timer timer("loadFont");
00253 DPRINTF("Need to load font: %s", name.c_str());
00254
00255
00256 std::istream& in = stream->getStream();
00257 ASSERT_THROW(in.good(), "bad font stream? " << name);
00258 std::streampos currPos = in.tellg();
00259 in.seekg(0, std::ios::end);
00260 std::streampos endPos = in.tellg();
00261 long bytes = (long) (endPos - currPos);
00262
00263 in.seekg(currPos, std::ios::beg);
00264
00265
00266 byte_t * data = new byte_t[bytes];
00267 ASSERT(data, "out of memory");
00268 in.read((char *) data, bytes);
00269 ASSERT_THROW(!in.fail(), "failed to read all bytes: " << bytes);
00270
00271 smart_ptr<FTGLTextureFont> texFont = new FTGLTextureFont(data, bytes);
00272 ASSERT_THROW(texFont, "failed to create texture font: " << name);
00273 texFont->FaceSize(40);
00274 smart_ptr<FTFont> ftglFont = texFont;
00275 ASSERT(ftglFont, "can't downcast to FTFont from FTGLTextureFont?");
00276 smart_ptr<FtglFont> font = FtglFont::create(path, data, ftglFont);
00277 ASSERT_THROW(font, "failed to create glut::Font: " << path);
00278
00279
00280 m_fonts[name] = font;
00281 return font;
00282 }
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292 smart_ptr<FontManager>
00293 FontManager::create
00294 (
00295 void
00296 )
00297 {
00298 smart_ptr<Mgr> local = new Mgr;
00299 ASSERT(local, "out of memory");
00300
00301 local->initialize();
00302
00303 return local;
00304 }
00305
00306
00307
00308 smart_ptr<Font>
00309 getDefaultFont
00310 (
00311 void
00312 )
00313 {
00314 static smart_ptr<Font> g_defaultFont = NULL;
00315 if (!g_defaultFont) {
00316 g_defaultFont = new DefaultFont;
00317 ASSERT(g_defaultFont, "out of memory");
00318 }
00319 return g_defaultFont;
00320 }
00321
00322
00323
00324 bool
00325 scaleFontToPixelHeight
00326 (
00327 IO Font * font,
00328 IN const char * text,
00329 IN int H
00330 )
00331 {
00332 perf::Timer timer("scaleFont");
00333 ASSERT(font, "null");
00334 ASSERT(text, "null");
00335 ASSERT(H > 0, "Bad desired pixel height: %d", H);
00336
00337 if (!font->canScale()) {
00338 return false;
00339 }
00340
00341 float startScale = font->getFaceSize();
00342
00343 float leftSize = 0.0;
00344 float rightSize = 72.0;
00345 while (true) {
00346 ASSERT_THROW(font->setFaceSize(rightSize),
00347 "Font is supposed to be scalable");
00348 font_rect_t fr = font->getBoundingRect(text);
00349 int y = fr.rise + fr.drop;
00350
00351 if (rightSize > 200 && y < 2) {
00352
00353 font->setFaceSize(startScale);
00354 return false;
00355 }
00356 if (y > H) {
00357 break;
00358 }
00359 rightSize *= 2;
00360 }
00361
00362
00363 while (true) {
00364 float midSize = 0.5 * (leftSize + rightSize);
00365 ASSERT_THROW(font->setFaceSize(midSize),
00366 "font is supposed to be scalable");
00367 font_rect_t fr = font->getBoundingRect(text);
00368 int y = fr.rise + fr.drop;
00369
00370 if (rightSize - leftSize < 0.25)
00371 return true;
00372 if (y == H)
00373 return true;
00374 if (y < H) {
00375
00376 leftSize = midSize;
00377 } else {
00378
00379 rightSize = midSize;
00380 }
00381 }
00382
00383 return false;
00384 }
00385
00386
00387
00388 };
00389