aglrasterfont.h

Go to the documentation of this file.
00001 
00003 
00004 //
00005 // Copyright (c) 2004-2004 California Institute of Technology
00006 // Copyright (c) 2004-2007 University of Southern California
00007 // Rob Peters <rjpeters at usc dot edu>
00008 //
00009 // created: Tue Jul 20 20:21:35 2004
00010 // commit: $Id: aglrasterfont.h 10065 2007-04-12 05:54:56Z rjpeters $
00011 // $HeadURL: file:///lab/rjpeters/svnrepo/code/trunk/groovx/src/gfx/aglrasterfont.h $
00012 //
00013 // --------------------------------------------------------------------
00014 //
00015 // This file is part of GroovX.
00016 //   [http://ilab.usc.edu/rjpeters/groovx/]
00017 //
00018 // GroovX is free software; you can redistribute it and/or modify it
00019 // under the terms of the GNU General Public License as published by
00020 // the Free Software Foundation; either version 2 of the License, or
00021 // (at your option) any later version.
00022 //
00023 // GroovX is distributed in the hope that it will be useful, but
00024 // WITHOUT ANY WARRANTY; without even the implied warranty of
00025 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00026 // General Public License for more details.
00027 //
00028 // You should have received a copy of the GNU General Public License
00029 // along with GroovX; if not, write to the Free Software Foundation,
00030 // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00031 //
00033 
00034 #ifndef GROOVX_GFX_AGLRASTERFONT_H_UTC20050626084024_DEFINED
00035 #define GROOVX_GFX_AGLRASTERFONT_H_UTC20050626084024_DEFINED
00036 
00037 #include "geom/rect.h"
00038 #include "geom/vec3.h"
00039 
00040 #include "gfx/bbox.h"
00041 #include "gfx/fontspec.h"
00042 #include "gfx/glcanvas.h"
00043 #include "gfx/gxrasterfont.h"
00044 
00045 #include "rutz/cstrstream.h"
00046 #include "rutz/error.h"
00047 #include "rutz/fstring.h"
00048 #include "rutz/sfmt.h"
00049 
00050 #include <cctype>
00051 #include <cstdio>
00052 #include <cstdlib> // for atoi()
00053 #include <cstring>
00054 #include <AGL/agl.h>
00055 #include <AGL/gl.h>
00056 
00057 #include "rutz/trace.h"
00058 #include "rutz/debug.h"
00059 GVX_DBG_REGISTER
00060 
00061 class AglRasterFont : public GxRasterFont
00062 {
00063 public:
00064   AglRasterFont(const char* n);
00065   virtual ~AglRasterFont() throw();
00066 
00067   struct AppleFontSpec
00068   {
00069     GLint fontID;
00070     Style face;
00071     GLint size;
00072   };
00073 
00074   static GLint getFontId(const char* name);
00075 
00076   static GLint getFontId(ConstStr255Param name);
00077 
00078   static AppleFontSpec pickAppleFont(const char* spec);
00079 
00080   virtual const char* fontName() const;
00081 
00082   virtual unsigned int listBase() const;
00083 
00084   virtual void bboxOf(const char* text, Gfx::Bbox& bbox) const;
00085 
00086   virtual void drawText(const char* text, Gfx::Canvas& canvas) const;
00087 
00089   virtual int rasterHeight() const;
00090 
00091 private:
00092   rutz::fstring itsFontName;
00093   FontInfo itsFontInfo;
00094   AppleFontSpec itsFontSpec;
00095   unsigned int itsListBase;
00096   unsigned int itsListCount;
00097 };
00098 
00099 AglRasterFont::AglRasterFont(const char* fontname) :
00100   itsFontName(fontname ? fontname : "fixed"),
00101   itsListBase(0),
00102   itsListCount(0)
00103 {
00104 GVX_TRACE("AglRasterFont::AglRasterFont");
00105 
00106   // This seems to do nothing (but it should make the Font Manager pick
00107   // nice outline fonts instead of uglier scaled-bitmap fonts):
00108 
00109   // SetOutlinePreferred(TRUE);
00110 
00111   itsFontSpec = pickAppleFont(fontname);
00112 
00113   itsListCount = 256;
00114   itsListBase = GLCanvas::genLists( 256 );
00115 
00116   if (itsListBase==0)
00117     {
00118       throw rutz::error(rutz::fstring("couldn't allocate GL display lists"),
00119                         SRC_POS);
00120     }
00121 
00122   GLboolean status = aglUseFont(aglGetCurrentContext(),
00123                                 itsFontSpec.fontID,
00124                                 itsFontSpec.face,
00125                                 itsFontSpec.size,
00126                                 0,
00127                                 256,
00128                                 itsListBase);
00129 
00130   if (status == GL_FALSE)
00131     {
00132       throw rutz::error("aglUseFont failed", SRC_POS);
00133     }
00134 
00135   /*
00136     struct FontInfo {
00137       short ascent;
00138       short descent;
00139       short widMax;
00140       short leading;
00141     };
00142   */
00143 
00144   OSErr err = FetchFontInfo(itsFontSpec.fontID, itsFontSpec.size,
00145                             itsFontSpec.face, &itsFontInfo);
00146 
00147   if (err != noErr)
00148     {
00149       throw rutz::error("FetchFontInfo failed", SRC_POS);
00150     }
00151 
00152 #if 0
00153   // for debugging
00154   for (int l = first; l < first+itsListCount; ++l)
00155     {
00156       double p = 4*double((l-first-1)-48)/42.0 - 2.0;
00157       glRasterPos2d(-1.0, p);
00158       glCallList(l);
00159     }
00160   glFlush();
00161 #endif
00162 }
00163 
00164 AglRasterFont::~AglRasterFont() throw()
00165 {
00166 GVX_TRACE("AglRasterFont::~AglRasterFont");
00167 
00168   if (aglGetCurrentContext() != 0)
00169     {
00170       GLCanvas::deleteLists(itsListBase, itsListCount);
00171     }
00172 }
00173 
00174 GLint AglRasterFont::getFontId(const char* name)
00175 {
00176 GVX_TRACE("AglRasterFont::getFontId");
00177 
00178   unsigned char pstring[256];
00179 
00180   c2pstrcpy(pstring, name);
00181 
00182   short fnum = 0;
00183   GetFNum(pstring, &fnum);
00184 
00185   if (fnum == 0)
00186     throw rutz::error(rutz::sfmt("couldn't get Apple Font ID "
00187                                  "for font '%s'", name),
00188                       SRC_POS);
00189 
00190   return GLint(fnum);
00191 }
00192 
00193 AglRasterFont::AppleFontSpec AglRasterFont::pickAppleFont(const char* spec)
00194 {
00195 GVX_TRACE("AglRasterFont::pickAppleFont");
00196 
00197   AppleFontSpec result;
00198 
00199   result.fontID = getFontId("Geneva");
00200   result.face = bold;
00201   result.size = 18;
00202 
00203   if (isdigit(spec[0]))
00204     {
00205       int w, h;
00206       // e.g. 8x13, 9x15
00207       int n = sscanf(spec, "%dx%d", &w, &h);
00208 
00209       if (n != 2)
00210         throw rutz::error(rutz::sfmt("couldn't parse fontspec '%s' as "
00211                                      "'[width]x[height]", spec),
00212                           SRC_POS);
00213 
00214       result.fontID = getFontId("Courier");
00215       result.face = bold;
00216       result.size = h;
00217     }
00218   else if (spec[0] == '-')
00219     {
00220       char family[64] = { '\0' };
00221       char weight[64] = { '\0' };
00222       char slant[64] = { '\0' };
00223       char pxlsize[64] = { '\0' };
00224 
00225       int n = sscanf(spec, "-%*[^-]-%40[^-]-%40[^-]-%40[^-]-%*[^-]-%*[^-]-%40[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]",
00226                      family, weight, slant, pxlsize);
00227 
00228       if (n != 4)
00229         throw rutz::error(rutz::sfmt("couldn't parse fontspec '%s' "
00230                                      "(expected 4 conversions, got %d)",
00231                                      spec, n),
00232                           SRC_POS);
00233 
00234       result.fontID = getFontId(family);
00235 
00236       result.face = 0;
00237 
00238       if (strcmp(weight, "bold") == 0)
00239         result.face |= bold;
00240 
00241       if (*slant == 'i' || *slant == 'o')
00242         result.face |= italic;
00243 
00244       int ipxlsize = result.size;
00245 
00246       if (*pxlsize != '*')
00247         {
00248           int n2 = sscanf(pxlsize, "%d", &ipxlsize);
00249 
00250           if (n2 != 1)
00251             throw rutz::error(rutz::sfmt("couldn't parse pixel size "
00252                                          "from '%s'", pxlsize),
00253                               SRC_POS);
00254         }
00255 
00256       result.size = ipxlsize;
00257     }
00258   else
00259     {
00260       rutz::fstring family, pxlsize, mods;
00261 
00262       parseFontSpec(spec, &family, &pxlsize, &mods);
00263 
00264       if (!family.is_empty())
00265         result.fontID = getFontId(family.c_str());
00266 
00267       if (!pxlsize.is_empty())
00268         result.size = atoi(pxlsize.c_str());
00269 
00270       result.face = 0;
00271 
00272       const char* mod = mods.c_str();
00273 
00274       while (*mod != '\0')
00275         {
00276           switch (*mod)
00277             {
00278             case 'b': result.face |= bold; break;
00279             case 'i': result.face |= italic; break;
00280             case 'o': result.face |= italic; break;
00281             case 'u': result.face |= underline; break;
00282             case 't': result.face |= outline; break;
00283             case 's': result.face |= shadow; break;
00284             case 'c': result.face |= condense; break;
00285             case 'e': result.face |= extend; break;
00286             }
00287           ++mod;
00288         }
00289     }
00290 
00291   return result;
00292 }
00293 
00294 const char* AglRasterFont::fontName() const
00295 {
00296 GVX_TRACE("AglRasterFont::fontName");
00297   return itsFontName.c_str();
00298 }
00299 
00300 unsigned int AglRasterFont::listBase() const
00301 {
00302 GVX_TRACE("AglRasterFont::listBase");
00303   return itsListBase;
00304 }
00305 
00306 namespace
00307 {
00308   int linelength(const char* p)
00309   {
00310     int n = 0;
00311     while (p[n] != '\n' && p[n] != '\0')
00312       {
00313         ++n;
00314       }
00315     return n;
00316   }
00317 }
00318 
00319 void AglRasterFont::bboxOf(const char* text, Gfx::Bbox& bbox) const
00320 {
00321 GVX_TRACE("AglRasterFont::bboxOf");
00322 
00323   const int asc = itsFontInfo.ascent;
00324   const int desc = itsFontInfo.descent;
00325   int maxwid = 0;
00326 
00327   int lines = 0;
00328 
00329   // make a copy so that we can pass a non-const pointer to StdTxMeas
00330   FontInfo finfo = itsFontInfo;
00331 
00332   CGrafPtr saveWorld;
00333   GDHandle saveDevice;
00334 
00335   static GWorldPtr gWorld = NULL;
00336 
00337   if (gWorld == 0)
00338     {
00339       Rect rect = {0, 0, 1, 1};
00340       SetFractEnable(0);
00341 
00342       if (NewGWorld(&gWorld, 0, &rect, NULL, NULL, 0) != noErr)
00343         {
00344           throw rutz::error("NewGWorld failed", SRC_POS);
00345         }
00346     }
00347 
00348   GetGWorld(&saveWorld, &saveDevice);
00349   SetGWorld(gWorld, NULL);
00350 
00351   TextFont(itsFontSpec.fontID);
00352   TextFace(itsFontSpec.face);
00353   TextSize(itsFontSpec.size);
00354 
00355   while (1)
00356     {
00357       int len = linelength(text);
00358 #if 0
00359       Point numer, denom;
00360       numer.h = numer.v = denom.h = denom.v = 1;
00361       int wid = StdTxMeas(len, text, &numer, &denom, &finfo);
00362 
00363       dbg_eval(2, numer.h); dbg_eval_nl(2, numer.v);
00364       dbg_eval(2, denom.h); dbg_eval_nl(2, denom.v);
00365 #else
00366       int wid = TextWidth(text, 0, len);
00367 #endif
00368 
00369       int wid2 = 0;
00370       for (int i = 0; i < len; ++i)
00371         {
00372           int widthOfChar = CharWidth(text[i]);
00373           wid2 += widthOfChar;
00374           dbg_eval(4, text[i]); dbg_eval_nl(4, widthOfChar);
00375         }
00376 
00377       dbg_eval(2, wid); dbg_eval_nl(2, wid2);
00378 
00379       text += len;
00380       if (wid > maxwid)
00381         maxwid = wid;
00382 
00383       ++lines;
00384 
00385       if (*text == '\0')
00386         break;
00387 
00388       GVX_ASSERT(*text == '\n');
00389       ++text;
00390     }
00391 
00392   dbg_eval(2, lines);
00393   dbg_eval(2, itsFontInfo.widMax);
00394   dbg_eval(2, asc);
00395   dbg_eval(2, desc);
00396   dbg_eval_nl(2, maxwid);
00397 
00398   const int l = 0;
00399   const int r = maxwid;
00400   const int b = -(itsFontInfo.descent + (lines - 1) * (rasterHeight()));
00401   const int t = itsFontInfo.ascent;
00402 
00403   dbg_eval(2, l);
00404   dbg_eval(2, r);
00405   dbg_eval(2, b);
00406   dbg_eval_nl(2, t);
00407 
00408   GVX_ASSERT(r >= 0);
00409   GVX_ASSERT(b <= 0);
00410   GVX_ASSERT(t >= 0);
00411 
00412   bbox.drawScreenRect(geom::vec3d::zeros(),
00413                       geom::rect<int>::ltrb(l,t,r,b));
00414 
00415   SetGWorld(saveWorld, saveDevice);
00416 }
00417 
00418 void AglRasterFont::drawText(const char* text, Gfx::Canvas& canvas) const
00419 {
00420 GVX_TRACE("AglRasterFont::drawText");
00421 
00422   canvas.drawRasterText(text, *this);
00423 }
00424 
00425 int AglRasterFont::rasterHeight() const
00426 {
00427 GVX_TRACE("AglRasterFont::rasterHeight");
00428 
00429   return itsFontInfo.ascent + itsFontInfo.descent + itsFontInfo.leading;
00430 }
00431 
00432 static const char __attribute__((used)) vcid_groovx_gfx_aglrasterfont_h_utc20050626084024[] = "$Id: aglrasterfont.h 10065 2007-04-12 05:54:56Z rjpeters $ $HeadURL: file:
00433 #endif // !GROOVX_GFX_AGLRASTERFONT_H_UTC20050626084024_DEFINED

The software described here is Copyright (c) 1998-2005, Rob Peters.
This page was generated Wed Dec 3 06:49:38 2008 by Doxygen version 1.5.5.