00001
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
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>
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
00107
00108
00109
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
00137
00138
00139
00140
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
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
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
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