1 /* $Id: toglFont.c,v 1.8 2009/05/22 00:18:36 gregcouch Exp $ */
2
3 /* vi:set sw=4 expandtab: */
4
5 /*
6 * Togl - a Tk OpenGL widget
7 *
8 * Copyright (C) 1996-2002 Brian Paul and Ben Bederson
9 * Copyright (C) 2005-2008 Greg Couch
10 * See the LICENSE file for copyright details.
11 */
12
13 /*
14 * Togl Bitmap Font support
15 *
16 * If bitmap font support is requested, then this file is included into
17 * togl.c. Parts of this file are based on <http://wiki.tcl.tk/13881>,
18 * "Creating and Using Tcl Handles in C Extensions".
19 *
20 * Neither the Tk public nor the internal interface give enough information
21 * to reuse the font in OpenGL, so we copy the private structures here to
22 * access what we need.
23 *
24 * Globals needed by the font module are in togl.c
25 */
26
27 #include <tkFont.h>
28
29 struct Togl_BitmapFontInfo
30 {
31 GLuint base;
32 GLuint first;
33 GLuint last;
34 int contextTag;
35 /* TODO: keep original font and/or encoding */
36 };
37 typedef struct Togl_BitmapFontInfo Togl_BitmapFontInfo;
38
39 #define BITMAP_FONT_INFO(obj) \
40 ((Togl_BitmapFontInfo *) (obj)->internalRep.otherValuePtr)
41 #define SET_BITMAP_FONT_INFO(obj) \
42 (obj)->internalRep.otherValuePtr
43
44 static void Togl_FontFree(Tcl_Obj *obj);
45 static void Togl_FontDup(Tcl_Obj *src, Tcl_Obj *dup);
46 static void Togl_FontString(Tcl_Obj *obj);
47 static int Togl_FontSet(Tcl_Interp *interp, Tcl_Obj *obj);
48
49 static Tcl_ObjType Togl_BitmapFontType = {
50 "Togl BitmapFont", /* name */
51 Togl_FontFree, /* free internal rep */
52 Togl_FontDup, /* dup internal rep */
53 Togl_FontString, /* update string from internal rep */
54 Togl_FontSet /* set internal rep from string */
55 };
56
57 static int
Togl_FontSet(Tcl_Interp * interp,Tcl_Obj * obj)58 Togl_FontSet(Tcl_Interp *interp, Tcl_Obj *obj)
59 {
60 if (interp)
61 Tcl_AppendResult(interp, "cannot (re)build object of type \"",
62 Togl_BitmapFontType.name, "\"", NULL);
63 return TCL_ERROR;
64 }
65
66 static void
Togl_FontFree(Tcl_Obj * obj)67 Togl_FontFree(Tcl_Obj *obj)
68 {
69 Togl_BitmapFontInfo *bfi = BITMAP_FONT_INFO(obj);
70
71 ckfree((char *) bfi);
72 }
73
74 static void
Togl_FontString(Tcl_Obj * obj)75 Togl_FontString(Tcl_Obj *obj)
76 {
77 /* assert(obj->bytes == NULL) */
78 static char buf[256];
79 register unsigned len;
80 Togl_BitmapFontInfo *bfi = BITMAP_FONT_INFO(obj);
81
82 #if !defined(TOGL_AGL) && !defined(TOGL_NSOPENGL)
83 snprintf(buf, sizeof buf - 1, "{{%s} %d %d %d}",
84 Togl_BitmapFontType.name, bfi->base, bfi->first, bfi->last);
85 #else
86 /* unlike every other platform, on Aqua, GLint is long */
87 snprintf(buf, sizeof buf - 1, "{{%s} %ld %ld %ld}",
88 Togl_BitmapFontType.name, bfi->base, bfi->first, bfi->last);
89 #endif
90 buf[sizeof buf - 1] = '\0';
91 len = strlen(buf);
92 obj->bytes = (char *) ckalloc(len + 1);
93 strcpy(obj->bytes, buf);
94 obj->length = len;
95 }
96
97 static void
Togl_FontDup(Tcl_Obj * src,Tcl_Obj * dup)98 Togl_FontDup(Tcl_Obj *src, Tcl_Obj *dup)
99 {
100 /*
101 * When duplicated, lose the font-ness and just be a string.
102 * So don't copy the internal representation and don't set
103 * dup->typePtr.
104 */
105 }
106
107 #if defined(TOGL_X11)
108 /* From tkUnixFont.c */
109 /*
110 * The following structure encapsulates an individual screen font. A font
111 * object is made up of however many SubFonts are necessary to display a
112 * stream of multilingual characters.
113 */
114
115 typedef struct FontFamily FontFamily;
116
117 typedef struct SubFont
118 {
119 char **fontMap; /* Pointer to font map from the FontFamily,
120 * cached here to save a dereference. */
121 XFontStruct *fontStructPtr; /* The specific screen font that will be used
122 * when displaying/measuring chars belonging to
123 * the FontFamily. */
124 FontFamily *familyPtr; /* The FontFamily for this SubFont. */
125 } SubFont;
126
127 /*
128 * The following structure represents Unix's implementation of a font
129 * object.
130 */
131
132 # define SUBFONT_SPACE 3
133 # define BASE_CHARS 256
134
135 typedef struct UnixFont
136 {
137 TkFont font; /* Stuff used by generic font package. Must be
138 * first in structure. */
139 SubFont staticSubFonts[SUBFONT_SPACE];
140 /* Builtin space for a limited number of SubFonts. */
141 int numSubFonts; /* Length of following array. */
142 SubFont *subFontArray; /* Array of SubFonts that have been loaded in
143 * order to draw/measure all the characters
144 * encountered by this font so far. All fonts
145 * start off with one SubFont initialized by
146 * AllocFont() from the original set of font
147 * attributes. Usually points to
148 * staticSubFonts, but may point to malloced
149 * space if there are lots of SubFonts. */
150 SubFont controlSubFont; /* Font to use to display control-character
151 * expansions. */
152
153 # if 0
154 Display *display; /* Display that owns font. */
155 int pixelSize; /* Original pixel size used when font was
156 * constructed. */
157 TkXLFDAttributes xa; /* Additional attributes that specify the
158 * preferred foundry and encoding to use when
159 * constructing additional SubFonts. */
160 int widths[BASE_CHARS]; /* Widths of first 256 chars in the base font,
161 * for handling common case. */
162 int underlinePos; /* Offset from baseline to origin of underline
163 * bar (used when drawing underlined font)
164 * (pixels). */
165 int barHeight; /* Height of underline or overstrike bar (used
166 * when drawing underlined or strikeout font)
167 * (pixels). */
168 # endif
169 } UnixFont;
170
171 #elif defined(TOGL_WGL)
172 # include <tkWinInt.h>
173 /* From tkWinFont.c */
174
175 typedef struct FontFamily FontFamily;
176
177 /*
178 * The following structure encapsulates an individual screen font. A font
179 * object is made up of however many SubFonts are necessary to display a
180 * stream of multilingual characters.
181 */
182
183 typedef struct SubFont
184 {
185 char **fontMap; /* Pointer to font map from the FontFamily,
186 * cached here to save a dereference. */
187 HFONT hFont; /* The specific screen font that will be used
188 * when displaying/measuring chars belonging to
189 * the FontFamily. */
190 FontFamily *familyPtr; /* The FontFamily for this SubFont. */
191 } SubFont;
192
193 /*
194 * The following structure represents Windows' implementation of a font
195 * object.
196 */
197
198 # define SUBFONT_SPACE 3
199 # define BASE_CHARS 128
200
201 typedef struct WinFont
202 {
203 TkFont font; /* Stuff used by generic font package. Must be
204 * first in structure. */
205 SubFont staticSubFonts[SUBFONT_SPACE];
206 /* Builtin space for a limited number of SubFonts. */
207 int numSubFonts; /* Length of following array. */
208 SubFont *subFontArray; /* Array of SubFonts that have been loaded in
209 * order to draw/measure all the characters
210 * encountered by this font so far. All fonts
211 * start off with one SubFont initialized by
212 * AllocFont() from the original set of font
213 * attributes. Usually points to
214 * staticSubFonts, but may point to malloced
215 * space if there are lots of SubFonts. */
216
217 HWND hwnd; /* Toplevel window of application that owns
218 * this font, used for getting HDC for
219 * offscreen measurements. */
220 int pixelSize; /* Original pixel size used when font was
221 * constructed. */
222 int widths[BASE_CHARS]; /* Widths of first 128 chars in the base font,
223 * for handling common case. The base font is
224 * always used to draw characters between
225 * 0x0000 and 0x007f. */
226 } WinFont;
227
228 #elif defined(TOGL_AGL)
229
230 typedef struct FontFamily
231 {
232 struct FontFamily *nextPtr; /* Next in list of all known font families. */
233 int refCount; /* How many SubFonts are referring to this
234 * FontFamily. When the refCount drops to
235 * zero, this FontFamily may be freed. */
236 /*
237 * Key.
238 */
239
240 FMFontFamily faceNum; /* Unique face number key for this FontFamily. */
241
242 /*
243 * Derived properties.
244 */
245
246 Tcl_Encoding encoding; /* Encoding for this font family. */
247 # if 0
248 int isSymbolFont; /* Non-zero if this is a symbol family. */
249 int isMultiByteFont; /* Non-zero if this is a multi-byte family. */
250 char typeTable[256]; /* Table that identfies all lead bytes for a
251 * multi-byte family, used when measuring
252 * chars. If a byte is a lead byte, the value
253 * at the corresponding position in the
254 * typeTable is 1, otherwise 0. If this is a
255 * single-byte font, all entries are 0. */
256 char *fontMap[FONTMAP_PAGES];
257 /* Two-level sparse table used to determine quickly if the specified
258 * character exists. As characters are encountered, more pages in this
259 * table are dynamically added. The contents of each page is a bitmask
260 * consisting of FONTMAP_BITSPERPAGE bits, representing whether this font
261 * can be used to display the given character at the corresponding bit
262 * position. The high bits of the character are used to pick which page of
263 * the table is used. */
264 # endif
265 } FontFamily;
266
267 /*
268 * The following structure encapsulates an individual screen font. A font
269 * object is made up of however many SubFonts are necessary to display a
270 * stream of multilingual characters.
271 */
272
273 typedef struct SubFont
274 {
275 char **fontMap; /* Pointer to font map from the FontFamily,
276 * cached here to save a dereference. */
277 FontFamily *familyPtr; /* The FontFamily for this SubFont. */
278 } SubFont;
279
280 /*
281 * The following structure represents Macintosh's implementation of a font
282 * object.
283 */
284
285 # define SUBFONT_SPACE 3
286
287 typedef struct MacFont
288 {
289 TkFont font; /* Stuff used by generic font package. Must be
290 * first in structure. */
291 SubFont staticSubFonts[SUBFONT_SPACE];
292 /* Builtin space for a limited number of SubFonts. */
293 int numSubFonts; /* Length of following array. */
294 SubFont *subFontArray; /* Array of SubFonts that have been loaded in
295 * order to draw/measure all the characters
296 * encountered by this font so far. All fonts
297 * start off with one SubFont initialized by
298 * AllocFont() from the original set of font
299 * attributes. Usually points to
300 * staticSubFonts, but may point to malloced
301 * space if there are lots of SubFonts. */
302
303 short size; /* Font size in pixels, constructed from font
304 * attributes. */
305 short style; /* Style bits, constructed from font
306 * attributes. */
307 } MacFont;
308 #endif
309
310 /*
311 * Load the named bitmap font as a sequence of bitmaps in a display list.
312 * fontname may be any font recognized by Tk_GetFont.
313 */
314 Tcl_Obj *
Togl_LoadBitmapFont(const Togl * togl,const char * fontname)315 Togl_LoadBitmapFont(const Togl *togl, const char *fontname)
316 {
317 Tk_Font font;
318 Togl_BitmapFontInfo *bfi;
319 Tcl_Obj *obj;
320
321 #if defined(TOGL_X11)
322 UnixFont *unixfont;
323 XFontStruct *fontinfo;
324 #elif defined(TOGL_WGL)
325 WinFont *winfont;
326 HFONT oldFont;
327 TEXTMETRIC tm;
328 #elif defined(TOGL_AGL) || defined(TOGL_NSOPENGL)
329 MacFont *macfont;
330 #endif
331 int first, last, count;
332 GLuint fontbase;
333
334 if (!fontname) {
335 fontname = DEFAULT_FONTNAME;
336 }
337
338 font = Tk_GetFont(togl->Interp, togl->TkWin, fontname);
339 if (!font) {
340 return NULL;
341 }
342 #if defined(TOGL_X11)
343 unixfont = (UnixFont *) font;
344 fontinfo = unixfont->subFontArray->fontStructPtr;
345 first = fontinfo->min_char_or_byte2;
346 last = fontinfo->max_char_or_byte2;
347 #elif defined(TOGL_WGL)
348 winfont = (WinFont *) font;
349 oldFont =
350 (HFONT) SelectObject(togl->tglGLHdc, winfont->subFontArray->hFont);
351 GetTextMetrics(togl->tglGLHdc, &tm);
352 first = tm.tmFirstChar;
353 last = tm.tmLastChar;
354 #elif defined(TOGL_AGL) || defined(TOGL_NSOPENGL)
355 macfont = (MacFont *) font;
356 first = 10; /* don't know how to determine font range on
357 * Mac... */
358 last = 255;
359 #endif
360
361 if (last > 255)
362 last = 255; /* no unicode support */
363
364 count = last - first + 1;
365 fontbase = glGenLists((GLuint) (last + 1));
366 if (fontbase == 0) {
367 #ifdef TOGL_WGL
368 SelectObject(togl->tglGLHdc, oldFont);
369 #endif
370 Tk_FreeFont(font);
371 return NULL;
372 }
373 #if defined(TOGL_WGL)
374 wglUseFontBitmaps(togl->tglGLHdc, first, count, fontbase + first);
375 SelectObject(togl->tglGLHdc, oldFont);
376 #elif defined(TOGL_X11)
377 glXUseXFont(fontinfo->fid, first, count, (int) fontbase + first);
378 #elif defined(TOGL_AGL)
379 /* deprecated in OS X 10.5 */
380 aglUseFont(togl->Ctx,
381 macfont->subFontArray->familyPtr->faceNum,
382 macfont->style, macfont->size, first, count, fontbase + first);
383 #elif defined(TOGL_NSOPENGL)
384 /* No NSOpenGL equivalent to aglUseFont(). */
385 #endif
386 Tk_FreeFont(font);
387
388 bfi = (Togl_BitmapFontInfo *) ckalloc(sizeof (Togl_BitmapFontInfo));
389 bfi->base = fontbase;
390 bfi->first = first;
391 bfi->last = last;
392 bfi->contextTag = togl->contextTag;
393
394 obj = Tcl_NewObj();
395 SET_BITMAP_FONT_INFO(obj) = bfi;
396 obj->typePtr = &Togl_BitmapFontType;
397
398 return obj;
399 }
400
401 /*
402 * Release the display lists which were generated by Togl_LoadBitmapFont().
403 */
404 int
Togl_UnloadBitmapFont(const Togl * togl,Tcl_Obj * toglfont)405 Togl_UnloadBitmapFont(const Togl *togl, Tcl_Obj *toglfont)
406 {
407 Togl_BitmapFontInfo *bfi;
408
409 if (toglfont == NULL || toglfont->typePtr != &Togl_BitmapFontType) {
410 Tcl_Interp *interp = Togl_Interp(togl);
411
412 Tcl_AppendResult(interp, "font not found", NULL);
413 return TCL_ERROR;
414 }
415 bfi = BITMAP_FONT_INFO(toglfont);
416 glDeleteLists(bfi->base, bfi->last + 1); /* match glGenLists */
417 return TCL_OK;
418 }
419
420 int
Togl_WriteObj(const Togl * togl,const Tcl_Obj * toglfont,Tcl_Obj * obj)421 Togl_WriteObj(const Togl *togl, const Tcl_Obj *toglfont, Tcl_Obj *obj)
422 {
423 const char *str;
424 int len;
425
426 str = Tcl_GetStringFromObj(obj, &len);
427 return Togl_WriteChars(togl, toglfont, str, len);
428 }
429
430 int
Togl_WriteChars(const Togl * togl,const Tcl_Obj * toglfont,const char * str,int len)431 Togl_WriteChars(const Togl *togl, const Tcl_Obj *toglfont, const char *str,
432 int len)
433 {
434 /* TODO: assume utf8 encoding and convert to font encoding */
435 Togl_BitmapFontInfo *bfi;
436
437 if (toglfont == NULL || toglfont->typePtr != &Togl_BitmapFontType)
438 return -1;
439 bfi = BITMAP_FONT_INFO(toglfont);
440 if (Togl_ContextTag(togl) != bfi->contextTag)
441 return -1;
442 if (len == 0)
443 len = strlen(str);
444 glListBase(bfi->base);
445 glCallLists(len, GL_UNSIGNED_BYTE, str);
446 return len;
447 }
448