glut-font.cpp

Go to the documentation of this file.
00001 /*
00002  * glut-font.cpp
00003  *
00004  * Copyright (C) 2008,2010  Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *     * Redistributions of source code must retain the above copyright
00011  *       notice, this list of conditions and the following disclaimer.
00012  *     * Redistributions in binary form must reproduce the above copyright
00013  *       notice, this list of conditions and the following disclaimer in the
00014  *       documentation and/or other materials provided with the distribution.
00015  *     * Neither the name of the <organization> nor the
00016  *       names of its contributors may be used to endorse or promote products
00017  *       derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  * Basic font support.  See glut-font.h
00031  */
00032 
00033 // includes --------------------------------------------------------------------
00034 #include "glut-font.h"          // always include our own header first
00035 
00036 #include "ftgl/ftgl.h"
00037 #include "glut/glut.h"
00038 #include "perf/perf.h"
00039 
00040 
00041 namespace glut {
00042 
00043 
00044 // interface destructors
00045 Font::~Font(void) throw() { }
00046 FontManager::~FontManager(void) throw() { }
00047 
00048 
00049 ////////////////////////////////////////////////////////////////////////////////
00050 //
00051 //      static helper methods
00052 //
00053 ////////////////////////////////////////////////////////////////////////////////
00054 
00055 
00056 // used when path=NULL
00057 class DefaultFont : public Font {
00058 public:
00059         ~DefaultFont(void) throw() { }
00060 
00061         // glut::Font class interface methods ----------------------------------
00062         const char * getName(void) const throw() { return "(default font)"; }
00063         font_rect_t getBoundingRect(IN const char * text) {
00064                         ASSERT(text, "null");
00065 
00066                         int lh = this->getLineHeight();
00067 
00068                         int drop = 3;   // letters hang 3 pixels below baseline
00069 
00070                         font_rect_t box;
00071                         box.lead = 0;
00072                         box.drop = drop;
00073                         box.rise = lh - drop;
00074                         box.trail = glutBitmapLength(GLUT_BITMAP_9_BY_15,
00075                             (const byte_t *) text);
00076 
00077                         return box;
00078                 }
00079 
00080         void display(IN float x, IN float y, IN float z, IN const char * text) {
00081                         ASSERT(text, "null");
00082 
00083                         glRasterPos3f(x, y, z);
00084                         for (; *text; ++text) {
00085                                 glutBitmapCharacter(GLUT_BITMAP_9_BY_15, *text);
00086                         }
00087                 }
00088 
00089         bool canScale(void) const throw() { return false; }
00090         bool setFaceSize(IN float size) { return false; }
00091         float getFaceSize(void) const throw() { return -1; }
00092         int getLineHeight(void) const throw() { return 15; }
00093 
00094 private:
00095 };
00096 
00097 
00098 
00099 class FtglFont : public Font {
00100 public:
00101         ~FtglFont(void) throw() { }
00102 
00103         // glut::Font class interface methods ----------------------------------
00104         const char * getName(void) const throw() { return m_name.c_str(); }
00105         font_rect_t getBoundingRect(IN const char * text) {
00106                         ASSERT(text, "null");
00107 
00108                         FTBBox box = m_font->BBox(text);
00109                         font_rect_t fr;
00110                         FTPoint u = box.Upper();
00111                         FTPoint l = box.Lower();
00112                         //DPRINTF("l: (%f, %f, %f)", l.X(), l.Y(), l.Z());
00113                         //DPRINTF("u: (%f, %f, %f)", u.X(), u.Y(), u.Z());
00114 
00115                         fr.lead = -l.X();
00116                         fr.drop = -l.Y() + 1;
00117 
00118                         fr.trail = u.X();
00119                         fr.rise = u.Y();
00120 
00121                         return fr;
00122                 }
00123         void display(IN float x, IN float y, IN float z, IN const char * text) {
00124                         ASSERT(text, "null");
00125 
00126                         glMatrixMode(GL_MODELVIEW);
00127                         glPushMatrix();
00128                         glTranslatef(x, y, z);
00129                         glScalef(1, -1, 1);
00130                         m_font->Render(text);
00131                         glPopMatrix();
00132                 }
00133 
00134         bool canScale(void) const throw() { return true; }
00135         bool setFaceSize(IN float pointSize) {
00136                         if (pointSize < 0.5) {
00137                                 return false;
00138                         }
00139                         m_font->FaceSize(pointSize);
00140                         return true;
00141                 }
00142         float getFaceSize(void) const throw() {
00143                         return m_font->FaceSize();
00144                 }
00145         int getLineHeight(void) const throw() { return m_font->LineHeight(); }
00146 
00147         // static factory methods ----------------------------------------------
00148         static smart_ptr<FtglFont> create(IN const char * name,
00149                                         IN smart_ptr<FTFont>& font) {
00150                         ASSERT(name, "null");
00151                         ASSERT(font, "null");
00152 
00153                         smart_ptr<FtglFont> local = new FtglFont;
00154                         ASSERT(local, "out of memory");
00155 
00156                         local->m_name = name;
00157                         local->m_font = font;
00158 
00159                         return local;
00160                 }
00161 
00162 private:
00163         // private constructor -------------------------------------------------
00164         FtglFont(void) throw() { }
00165 
00166         // private helper methods ----------------------------------------------
00167         // private member data -------------------------------------------------
00168         std::string             m_name;
00169         smart_ptr<FTFont>       m_font;
00170 };
00171 
00172 
00173 
00174 class Mgr : public FontManager {
00175 public:
00176         ~Mgr(void) throw() { }
00177 
00178         // public class methods ------------------------------------------------
00179         void initialize(void);
00180 
00181         // glut::FontManager class interface methods ---------------------------
00182         smart_ptr<Font> getFont(IN const char * path);
00183 
00184 private:
00185         // private typedefs ----------------------------------------------------
00186         typedef std::map<std::string, smart_ptr<FtglFont> > font_map_t;
00187 
00188         // private helper methods ----------------------------------------------
00189         // private member data -------------------------------------------------
00190         font_map_t                      m_fonts;
00191 };
00192 
00193 
00194 void
00195 Mgr::initialize
00196 (
00197 void
00198 )
00199 {
00200 }
00201 
00202 
00203 
00204 smart_ptr<Font>
00205 Mgr::getFont
00206 (
00207 IN const char * path
00208 )
00209 {
00210         // ASSERT(path) -- can be null!
00211         if (!path) {
00212                 return getDefaultFont();
00213         }
00214 
00215         // already have this font?
00216         font_map_t::iterator i = m_fonts.find(path);
00217         if (m_fonts.end() != i) {
00218                 smart_ptr<Font> font = i->second;
00219                 ASSERT(font, "null font in map?");
00220                 return font;
00221         }
00222 
00223         // don't have this loaded yet
00224         perf::Timer timer("loadFont");
00225         DPRINTF("Need to load font: %s", path);
00226         smart_ptr<FTGLTextureFont> texFont = new FTGLTextureFont(path);
00227         ASSERT_THROW(texFont, "failed to create texture font: " << path);
00228         texFont->FaceSize(40);
00229         smart_ptr<FTFont> ftglFont = texFont;   // downcast
00230         ASSERT(ftglFont, "can't downcast to FTFont from FTGLTextureFont?");
00231         smart_ptr<FtglFont> font = FtglFont::create(path, ftglFont);
00232         ASSERT_THROW(font, "failed to create glut::Font: " << path);
00233         m_fonts[path] = font;
00234 
00235         return font;
00236 }
00237 
00238 
00239 
00240 ////////////////////////////////////////////////////////////////////////////////
00241 //
00242 //      public API
00243 //
00244 ////////////////////////////////////////////////////////////////////////////////
00245 
00246 smart_ptr<FontManager>
00247 FontManager::create
00248 (
00249 void
00250 )
00251 {
00252         smart_ptr<Mgr> local = new Mgr;
00253         ASSERT(local, "out of memory");
00254 
00255         local->initialize();
00256 
00257         return local;
00258 }
00259 
00260 
00261 
00262 smart_ptr<Font>
00263 getDefaultFont
00264 (
00265 void
00266 )
00267 {
00268         static smart_ptr<Font> g_defaultFont = NULL;
00269         if (!g_defaultFont) {
00270                 g_defaultFont = new DefaultFont;
00271                 ASSERT(g_defaultFont, "out of memory");
00272         }
00273         return g_defaultFont;
00274 }
00275 
00276 
00277 
00278 bool
00279 scaleFontToPixelHeight
00280 (
00281 IO Font * font,
00282 IN const char * text,
00283 IN int H
00284 )
00285 {
00286         perf::Timer timer("scaleFont");
00287         ASSERT(font, "null");
00288         ASSERT(text, "null");
00289         ASSERT(H > 0, "Bad desired pixel height: %d", H);
00290 
00291         if (!font->canScale()) {
00292                 return false;
00293         }
00294 
00295         float startScale = font->getFaceSize();
00296 
00297         float leftSize = 0.0;
00298         float rightSize = 72.0;
00299         while (true) {
00300                 ASSERT_THROW(font->setFaceSize(rightSize),
00301                     "Font is supposed to be scalable");
00302                 font_rect_t fr = font->getBoundingRect(text);
00303                 int y = fr.rise + fr.drop;
00304 //              DPRINTF("Point size %f --> line height %d", rightSize, y);
00305                 if (rightSize > 200 && y < 2) {
00306                         // font isn't scaling!
00307                         font->setFaceSize(startScale);
00308                         return false;
00309                 }
00310                 if (y > H) {
00311                         break;
00312                 }
00313                 rightSize *= 2;
00314         }
00315 
00316         // okay, binary search between left and right
00317         while (true) {
00318                 float midSize = 0.5 * (leftSize + rightSize);
00319                 ASSERT_THROW(font->setFaceSize(midSize),
00320                     "font is supposed to be scalable");
00321                 font_rect_t fr = font->getBoundingRect(text);
00322                 int y = fr.rise + fr.drop;
00323         //      DPRINTF("Point size %f --> line height %d", midSize, y);
00324                 if (rightSize - leftSize < 0.25)
00325                         return true;
00326                 if (y == H)
00327                         return true;
00328                 if (y < H) {
00329                         // mid is too small --> go right
00330                         leftSize = midSize;
00331                 } else {
00332                         // mid is too big --> go left
00333                         rightSize = midSize;
00334                 }
00335         }
00336 
00337         return false;
00338 }
00339 
00340 
00341 
00342 };      // glut namespace
00343