~ubuntu-branches/ubuntu/precise/arduino/precise

« back to all changes in this revision

Viewing changes to src/processing/core/PFont.java

  • Committer: Bazaar Package Importer
  • Author(s): Scott Howard
  • Date: 2010-04-13 22:32:24 UTC
  • Revision ID: james.westby@ubuntu.com-20100413223224-jduxnd0xxnkkda02
Tags: upstream-0018+dfsg
ImportĀ upstreamĀ versionĀ 0018+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
 
2
 
 
3
/*
 
4
  Part of the Processing project - http://processing.org
 
5
 
 
6
  Copyright (c) 2004-07 Ben Fry & Casey Reas
 
7
  Copyright (c) 2001-04 Massachusetts Institute of Technology
 
8
 
 
9
  This library is free software; you can redistribute it and/or
 
10
  modify it under the terms of the GNU Lesser General Public
 
11
  License as published by the Free Software Foundation; either
 
12
  version 2.1 of the License, or (at your option) any later version.
 
13
 
 
14
  This library is distributed in the hope that it will be useful,
 
15
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
17
  Lesser General Public License for more details.
 
18
 
 
19
  You should have received a copy of the GNU Lesser General
 
20
  Public License along with this library; if not, write to the
 
21
  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 
22
  Boston, MA  02111-1307  USA
 
23
*/
 
24
 
 
25
package processing.core;
 
26
 
 
27
import java.awt.*;
 
28
import java.awt.image.BufferedImage;
 
29
import java.awt.image.Raster;
 
30
import java.io.*;
 
31
//import java.lang.reflect.*;
 
32
import java.util.Arrays;
 
33
 
 
34
 
 
35
/**
 
36
 * Grayscale bitmap font class used by Processing.
 
37
 * <P>
 
38
 * Awful (and by that, I mean awesome) ascii (non)art for how this works:
 
39
 * <PRE>
 
40
 *   |
 
41
 *   |                   height is the full used height of the image
 
42
 *   |
 
43
 *   |   ..XX..       }
 
44
 *   |   ..XX..       }
 
45
 *   |   ......       }
 
46
 *   |   XXXX..       }  topExtent (top y is baseline - topExtent)
 
47
 *   |   ..XX..       }
 
48
 *   |   ..XX..       }  dotted areas are where the image data
 
49
 *   |   ..XX..       }  is actually located for the character
 
50
 *   +---XXXXXX----   }  (it extends to the right and down
 
51
 *   |                   for power of two texture sizes)
 
52
 *   ^^^^ leftExtent (amount to move over before drawing the image
 
53
 *
 
54
 *   ^^^^^^^^^^^^^^ setWidth (width displaced by char)
 
55
 * </PRE>
 
56
 */
 
57
public class PFont implements PConstants {
 
58
 
 
59
  public int charCount;
 
60
  public PImage images[];
 
61
 
 
62
  /**
 
63
   * Native Java version of the font. If possible, this allows the
 
64
   * PGraphics subclass to just use Java's font rendering stuff
 
65
   * in situations where that's faster.
 
66
   */
 
67
  protected Font font;
 
68
  protected boolean fontSearched;
 
69
 
 
70
  /**
 
71
   * Name of the font as seen by Java when it was created.
 
72
   * If the font is available, the native version will be used.
 
73
   */
 
74
  public String name;
 
75
 
 
76
  /**
 
77
   * Postscript name of the font that this bitmap was created from.
 
78
   */
 
79
  public String psname;
 
80
 
 
81
  /** "natural" size of the font (most often 48) */
 
82
  public int size;
 
83
 
 
84
  /** true if smoothing was enabled for this font, used for native impl */
 
85
  public boolean smooth;
 
86
 
 
87
  /** next power of 2 over the max image size (usually 64) */
 
88
  public int mbox2;
 
89
 
 
90
  /** floating point width (convenience) */
 
91
  protected float fwidth;
 
92
 
 
93
  /** floating point width (convenience) */
 
94
  protected float fheight;
 
95
 
 
96
  /** texture width, same as mbox2, but reserved for future use */
 
97
  public int twidth;
 
98
 
 
99
  /** texture height, same as mbox2, but reserved for future use */
 
100
  public int theight;
 
101
 
 
102
  public int value[];  // char code
 
103
  public int height[]; // height of the bitmap data
 
104
  public int width[];  // width of bitmap data
 
105
  public int setWidth[];  // width displaced by the char
 
106
  public int topExtent[];  // offset for the top
 
107
  public int leftExtent[];  // offset for the left
 
108
 
 
109
  public int ascent;
 
110
  public int descent;
 
111
 
 
112
  protected int ascii[];  // quick lookup for the ascii chars
 
113
 
 
114
  // shared by the text() functions to avoid incessant allocation of memory
 
115
  //protected char textBuffer[] = new char[8 * 1024];
 
116
  //protected char widthBuffer[] = new char[8 * 1024];
 
117
  
 
118
  static protected Font[] fonts;
 
119
 
 
120
 
 
121
  public PFont() { }  // for subclasses
 
122
 
 
123
 
 
124
  public PFont(InputStream input) throws IOException {
 
125
    DataInputStream is = new DataInputStream(input);
 
126
 
 
127
    // number of character images stored in this font
 
128
    charCount = is.readInt();
 
129
 
 
130
    // bit count is ignored since this is always 8
 
131
    //int numBits = is.readInt();
 
132
    // used to be the bitCount, but now used for version number.
 
133
    // version 8 is any font before 69, so 9 is anything from 83+
 
134
    // 9 was buggy so gonna increment to 10.
 
135
    int version = is.readInt();
 
136
 
 
137
    // this was formerly ignored, now it's the actual font size
 
138
    //mbox = is.readInt();
 
139
    size = is.readInt();
 
140
    // this was formerly mboxY, the one that was used
 
141
    // this will make new fonts downward compatible
 
142
    //mbox2 = is.readInt();
 
143
    mbox2 = is.readInt();
 
144
 
 
145
    fwidth = size; //mbox;
 
146
    fheight = size; //mbox;
 
147
 
 
148
    // size for image ("texture") is next power of 2
 
149
    // over the font size. for most vlw fonts, the size is 48
 
150
    // so the next power of 2 is 64.
 
151
    // double-check to make sure that mbox2 is a power of 2
 
152
    // there was a bug in the old font generator that broke this
 
153
    //mbox2 = (int) Math.pow(2, Math.ceil(Math.log(mbox2) / Math.log(2)));
 
154
    mbox2 = (int) Math.pow(2, Math.ceil(Math.log(mbox2) / Math.log(2)));
 
155
    // size for the texture is stored in the font
 
156
    twidth = theight = mbox2; //mbox2;
 
157
 
 
158
    ascent  = is.readInt();  // formerly baseHt (zero/ignored)
 
159
    descent = is.readInt();  // formerly ignored struct padding
 
160
 
 
161
    // allocate enough space for the character info
 
162
    value       = new int[charCount];
 
163
    height      = new int[charCount];
 
164
    width       = new int[charCount];
 
165
    setWidth    = new int[charCount];
 
166
    topExtent   = new int[charCount];
 
167
    leftExtent  = new int[charCount];
 
168
 
 
169
    ascii = new int[128];
 
170
    for (int i = 0; i < 128; i++) ascii[i] = -1;
 
171
 
 
172
    // read the information about the individual characters
 
173
    for (int i = 0; i < charCount; i++) {
 
174
      value[i]      = is.readInt();
 
175
      height[i]     = is.readInt();
 
176
      width[i]      = is.readInt();
 
177
      setWidth[i]   = is.readInt();
 
178
      topExtent[i]  = is.readInt();
 
179
      leftExtent[i] = is.readInt();
 
180
 
 
181
      // pointer in the c version, ignored
 
182
      is.readInt();
 
183
 
 
184
      // cache locations of the ascii charset
 
185
      if (value[i] < 128) ascii[value[i]] = i;
 
186
 
 
187
      // the values for getAscent() and getDescent() from FontMetrics
 
188
      // seem to be way too large.. perhaps they're the max?
 
189
      // as such, use a more traditional marker for ascent/descent
 
190
      if (value[i] == 'd') {
 
191
        if (ascent == 0) ascent = topExtent[i];
 
192
      }
 
193
      if (value[i] == 'p') {
 
194
        if (descent == 0) descent = -topExtent[i] + height[i];
 
195
      }
 
196
    }
 
197
 
 
198
    // not a roman font, so throw an error and ask to re-build.
 
199
    // that way can avoid a bunch of error checking hacks in here.
 
200
    if ((ascent == 0) && (descent == 0)) {
 
201
      throw new RuntimeException("Please use \"Create Font\" to " +
 
202
                                 "re-create this font.");
 
203
    }
 
204
 
 
205
    images = new PImage[charCount];
 
206
    for (int i = 0; i < charCount; i++) {
 
207
      images[i] = new PImage(twidth, theight, ALPHA);
 
208
      int bitmapSize = height[i] * width[i];
 
209
 
 
210
      byte temp[] = new byte[bitmapSize];
 
211
      is.readFully(temp);
 
212
 
 
213
      // convert the bitmap to an alpha channel
 
214
      int w = width[i];
 
215
      int h = height[i];
 
216
      for (int y = 0; y < h; y++) {
 
217
        for (int x = 0; x < w; x++) {
 
218
          int valu = temp[y*w + x] & 0xff;
 
219
          images[i].pixels[y * twidth + x] = valu;
 
220
          //(valu << 24) | 0xFFFFFF;  // windows
 
221
          //0xFFFFFF00 | valu;  // macosx
 
222
 
 
223
          //System.out.print((images[i].pixels[y*64+x] > 128) ? "*" : ".");
 
224
        }
 
225
        //System.out.println();
 
226
      }
 
227
      //System.out.println();
 
228
    }
 
229
 
 
230
    if (version >= 10) {  // includes the font name at the end of the file
 
231
      name = is.readUTF();
 
232
      psname = is.readUTF();
 
233
    }
 
234
    if (version == 11) {
 
235
      smooth = is.readBoolean();
 
236
    }
 
237
  }
 
238
 
 
239
 
 
240
  /**
 
241
   * Set the native complement of this font.
 
242
   */
 
243
  public void setFont(Font font) {
 
244
    this.font = font;
 
245
  }
 
246
  
 
247
  
 
248
  /**
 
249
   * Return the native java.awt.Font associated with this PFont (if any).
 
250
   */
 
251
  public Font getFont() {
 
252
//    if (font == null && !fontSearched) {
 
253
//      font = findFont();
 
254
//    }
 
255
    return font;
 
256
  }
 
257
 
 
258
 
 
259
  /**
 
260
   * Attempt to find the native version of this font.
 
261
   * (Public so that it can be used by OpenGL or other renderers.)
 
262
   */
 
263
  public Font findFont() {
 
264
    if (font == null) {
 
265
      if (!fontSearched) {
 
266
        // this font may or may not be installed
 
267
        font = new Font(name, Font.PLAIN, size);
 
268
        // if the ps name matches, then we're in fine shape
 
269
        if (!font.getPSName().equals(psname)) {
 
270
          // on osx java 1.4 (not 1.3.. ugh), you can specify the ps name
 
271
          // of the font, so try that in case this .vlw font was created on pc
 
272
          // and the name is different, but the ps name is found on the
 
273
          // java 1.4 mac that's currently running this sketch.
 
274
          font = new Font(psname, Font.PLAIN, size);
 
275
        }
 
276
        // check again, and if still bad, screw em
 
277
        if (!font.getPSName().equals(psname)) {
 
278
          font = null;
 
279
        }
 
280
        fontSearched = true;
 
281
      }
 
282
    }
 
283
    return font;
 
284
  }
 
285
 
 
286
 
 
287
  /**
 
288
   * Write this PFont to an OutputStream.
 
289
   * <p>
 
290
   * This is used by the Create Font tool, or whatever anyone else dreams
 
291
   * up for messing with fonts themselves.
 
292
   * <p>
 
293
   * It is assumed that the calling class will handle closing
 
294
   * the stream when finished.
 
295
   */
 
296
  public void save(OutputStream output) throws IOException {
 
297
    DataOutputStream os = new DataOutputStream(output);
 
298
 
 
299
    os.writeInt(charCount);
 
300
 
 
301
    if ((name == null) || (psname == null)) {
 
302
      name = "";
 
303
      psname = "";
 
304
    }
 
305
    // formerly numBits, now used for version number
 
306
    //os.writeInt((name != null) ? 11 : 8);
 
307
    os.writeInt(11);
 
308
 
 
309
    os.writeInt(size);    // formerly mboxX (was 64, now 48)
 
310
    os.writeInt(mbox2);   // formerly mboxY (was 64, still 64)
 
311
    os.writeInt(ascent);  // formerly baseHt (was ignored)
 
312
    os.writeInt(descent); // formerly struct padding for c version
 
313
 
 
314
    for (int i = 0; i < charCount; i++) {
 
315
      os.writeInt(value[i]);
 
316
      os.writeInt(height[i]);
 
317
      os.writeInt(width[i]);
 
318
      os.writeInt(setWidth[i]);
 
319
      os.writeInt(topExtent[i]);
 
320
      os.writeInt(leftExtent[i]);
 
321
      os.writeInt(0); // padding
 
322
    }
 
323
 
 
324
    for (int i = 0; i < charCount; i++) {
 
325
      for (int y = 0; y < height[i]; y++) {
 
326
        for (int x = 0; x < width[i]; x++) {
 
327
          os.write(images[i].pixels[y * mbox2 + x] & 0xff);
 
328
        }
 
329
      }
 
330
    }
 
331
 
 
332
    //if (name != null) {  // version 11
 
333
    os.writeUTF(name);
 
334
    os.writeUTF(psname);
 
335
    os.writeBoolean(smooth);
 
336
    //}
 
337
 
 
338
    os.flush();
 
339
  }
 
340
 
 
341
 
 
342
  /**
 
343
   * Get index for the char (convert from unicode to bagel charset).
 
344
   * @return index into arrays or -1 if not found
 
345
   */
 
346
  public int index(char c) {
 
347
    // degenerate case, but the find function will have trouble
 
348
    // if there are somehow zero chars in the lookup
 
349
    //if (value.length == 0) return -1;
 
350
    if (charCount == 0) return -1;
 
351
 
 
352
    // quicker lookup for the ascii fellers
 
353
    if (c < 128) return ascii[c];
 
354
 
 
355
    // some other unicode char, hunt it out
 
356
    //return index_hunt(c, 0, value.length-1);
 
357
    return indexHunt(c, 0, charCount-1);
 
358
  }
 
359
 
 
360
 
 
361
  protected int indexHunt(int c, int start, int stop) {
 
362
    int pivot = (start + stop) / 2;
 
363
 
 
364
    // if this is the char, then return it
 
365
    if (c == value[pivot]) return pivot;
 
366
 
 
367
    // char doesn't exist, otherwise would have been the pivot
 
368
    //if (start == stop) return -1;
 
369
    if (start >= stop) return -1;
 
370
 
 
371
    // if it's in the lower half, continue searching that
 
372
    if (c < value[pivot]) return indexHunt(c, start, pivot-1);
 
373
 
 
374
    // if it's in the upper half, continue there
 
375
    return indexHunt(c, pivot+1, stop);
 
376
  }
 
377
 
 
378
 
 
379
  /**
 
380
   * Currently un-implemented for .vlw fonts,
 
381
   * but honored for layout in case subclasses use it.
 
382
   */
 
383
  public float kern(char a, char b) {
 
384
    return 0;
 
385
  }
 
386
 
 
387
 
 
388
  /**
 
389
   * Returns the ascent of this font from the baseline.
 
390
   * The value is based on a font of size 1.
 
391
   */
 
392
  public float ascent() {
 
393
    return ((float)ascent / fheight);
 
394
  }
 
395
 
 
396
 
 
397
  /**
 
398
   * Returns how far this font descends from the baseline.
 
399
   * The value is based on a font size of 1.
 
400
   */
 
401
  public float descent() {
 
402
    return ((float)descent / fheight);
 
403
  }
 
404
 
 
405
 
 
406
  /**
 
407
   * Width of this character for a font of size 1.
 
408
   */
 
409
  public float width(char c) {
 
410
    if (c == 32) return width('i');
 
411
 
 
412
    int cc = index(c);
 
413
    if (cc == -1) return 0;
 
414
 
 
415
    return ((float)setWidth[cc] / fwidth);
 
416
  }
 
417
 
 
418
 
 
419
  //////////////////////////////////////////////////////////////
 
420
 
 
421
 
 
422
  static final char[] EXTRA_CHARS = {
 
423
    0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
 
424
    0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
 
425
    0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
 
426
    0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
 
427
    0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
 
428
    0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
 
429
    0x00B0, 0x00B1, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00BA,
 
430
    0x00BB, 0x00BF, 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5,
 
431
    0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD,
 
432
    0x00CE, 0x00CF, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6,
 
433
    0x00D7, 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DF,
 
434
    0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
 
435
    0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
 
436
    0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8,
 
437
    0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FF, 0x0102, 0x0103,
 
438
    0x0104, 0x0105, 0x0106, 0x0107, 0x010C, 0x010D, 0x010E, 0x010F,
 
439
    0x0110, 0x0111, 0x0118, 0x0119, 0x011A, 0x011B, 0x0131, 0x0139,
 
440
    0x013A, 0x013D, 0x013E, 0x0141, 0x0142, 0x0143, 0x0144, 0x0147,
 
441
    0x0148, 0x0150, 0x0151, 0x0152, 0x0153, 0x0154, 0x0155, 0x0158,
 
442
    0x0159, 0x015A, 0x015B, 0x015E, 0x015F, 0x0160, 0x0161, 0x0162,
 
443
    0x0163, 0x0164, 0x0165, 0x016E, 0x016F, 0x0170, 0x0171, 0x0178,
 
444
    0x0179, 0x017A, 0x017B, 0x017C, 0x017D, 0x017E, 0x0192, 0x02C6,
 
445
    0x02C7, 0x02D8, 0x02D9, 0x02DA, 0x02DB, 0x02DC, 0x02DD, 0x03A9,
 
446
    0x03C0, 0x2013, 0x2014, 0x2018, 0x2019, 0x201A, 0x201C, 0x201D,
 
447
    0x201E, 0x2020, 0x2021, 0x2022, 0x2026, 0x2030, 0x2039, 0x203A,
 
448
    0x2044, 0x20AC, 0x2122, 0x2202, 0x2206, 0x220F, 0x2211, 0x221A,
 
449
    0x221E, 0x222B, 0x2248, 0x2260, 0x2264, 0x2265, 0x25CA, 0xF8FF,
 
450
    0xFB01, 0xFB02
 
451
  };
 
452
 
 
453
 
 
454
  /**
 
455
   * The default Processing character set.
 
456
   * <P>
 
457
   * This is the union of the Mac Roman and Windows ANSI (CP1250)
 
458
   * character sets. ISO 8859-1 Latin 1 is Unicode characters 0x80 -> 0xFF,
 
459
   * and would seem a good standard, but in practice, most P5 users would
 
460
   * rather have characters that they expect from their platform's fonts.
 
461
   * <P>
 
462
   * This is more of an interim solution until a much better
 
463
   * font solution can be determined. (i.e. create fonts on
 
464
   * the fly from some sort of vector format).
 
465
   * <P>
 
466
   * Not that I expect that to happen.
 
467
   */
 
468
  static public char[] DEFAULT_CHARSET;
 
469
  static {
 
470
    DEFAULT_CHARSET = new char[126-33+1 + EXTRA_CHARS.length];
 
471
    int index = 0;
 
472
    for (int i = 33; i <= 126; i++) {
 
473
      DEFAULT_CHARSET[index++] = (char)i;
 
474
    }
 
475
    for (int i = 0; i < EXTRA_CHARS.length; i++) {
 
476
      DEFAULT_CHARSET[index++] = EXTRA_CHARS[i];
 
477
    }
 
478
  };
 
479
 
 
480
 
 
481
  /**
 
482
   * Create a new image-based font on the fly.
 
483
   *
 
484
   * @param font the font object to create from
 
485
   * @param charset array of all unicode chars that should be included
 
486
   * @param smooth true to enable smoothing/anti-aliasing
 
487
   */
 
488
  public PFont(Font font, boolean smooth, char charset[]) {
 
489
    // save this so that we can use the native version
 
490
    this.font = font;
 
491
    this.smooth = smooth;
 
492
 
 
493
    name = font.getName();
 
494
    psname = font.getPSName();
 
495
 
 
496
    // fix regression from sorting (bug #564)
 
497
    if (charset != null) {
 
498
      // charset needs to be sorted to make index lookup run more quickly
 
499
      // http://dev.processing.org/bugs/show_bug.cgi?id=494
 
500
      Arrays.sort(charset);
 
501
    }
 
502
 
 
503
    // the count gets reset later based on how many of
 
504
    // the chars are actually found inside the font.
 
505
    this.charCount = (charset == null) ? 65536 : charset.length;
 
506
    this.size = font.getSize();
 
507
 
 
508
    fwidth = fheight = size;
 
509
 
 
510
    PImage bitmaps[] = new PImage[charCount];
 
511
 
 
512
    // allocate enough space for the character info
 
513
    value       = new int[charCount];
 
514
    height      = new int[charCount];
 
515
    width       = new int[charCount];
 
516
    setWidth    = new int[charCount];
 
517
    topExtent   = new int[charCount];
 
518
    leftExtent  = new int[charCount];
 
519
 
 
520
    ascii = new int[128];
 
521
    for (int i = 0; i < 128; i++) ascii[i] = -1;
 
522
 
 
523
    int mbox3 = size * 3;
 
524
 
 
525
    BufferedImage playground =
 
526
      new BufferedImage(mbox3, mbox3, BufferedImage.TYPE_INT_RGB);
 
527
 
 
528
    Graphics2D g = (Graphics2D) playground.getGraphics();
 
529
    g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
 
530
                       smooth ?
 
531
                       RenderingHints.VALUE_ANTIALIAS_ON :
 
532
                       RenderingHints.VALUE_ANTIALIAS_OFF);
 
533
 
 
534
    g.setFont(font);
 
535
    FontMetrics metrics = g.getFontMetrics();
 
536
 
 
537
    int samples[] = new int[mbox3 * mbox3];
 
538
 
 
539
    int maxWidthHeight = 0;
 
540
    int index = 0;
 
541
    for (int i = 0; i < charCount; i++) {
 
542
      char c = (charset == null) ? (char)i : charset[i];
 
543
 
 
544
      if (!font.canDisplay(c)) {  // skip chars not in the font
 
545
        continue;
 
546
      }
 
547
 
 
548
      g.setColor(Color.white);
 
549
      g.fillRect(0, 0, mbox3, mbox3);
 
550
      g.setColor(Color.black);
 
551
      g.drawString(String.valueOf(c), size, size * 2);
 
552
 
 
553
      // grabs copy of the current data.. so no updates (do each time)
 
554
      Raster raster = playground.getData();
 
555
      raster.getSamples(0, 0, mbox3, mbox3, 0, samples);
 
556
 
 
557
      int minX = 1000, maxX = 0;
 
558
      int minY = 1000, maxY = 0;
 
559
      boolean pixelFound = false;
 
560
 
 
561
      for (int y = 0; y < mbox3; y++) {
 
562
        for (int x = 0; x < mbox3; x++) {
 
563
          //int sample = raster.getSample(x, y, 0);  // maybe?
 
564
          int sample = samples[y * mbox3 + x] & 0xff;
 
565
          // or int samples[] = raster.getPixel(x, y, null);
 
566
 
 
567
          //if (sample == 0) {  // or just not white? hmm
 
568
          if (sample != 255) {
 
569
            if (x < minX) minX = x;
 
570
            if (y < minY) minY = y;
 
571
            if (x > maxX) maxX = x;
 
572
            if (y > maxY) maxY = y;
 
573
            pixelFound = true;
 
574
          }
 
575
        }
 
576
      }
 
577
 
 
578
      if (!pixelFound) {
 
579
        minX = minY = 0;
 
580
        maxX = maxY = 0;
 
581
        // this will create a 1 pixel white (clear) character..
 
582
        // maybe better to set one to -1 so nothing is added?
 
583
      }
 
584
 
 
585
      value[index] = c;
 
586
      height[index] = (maxY - minY) + 1;
 
587
      width[index] = (maxX - minX) + 1;
 
588
      setWidth[index] = metrics.charWidth(c);
 
589
      //System.out.println((char)c + " " + setWidth[index]);
 
590
 
 
591
      // cache locations of the ascii charset
 
592
      //if (value[i] < 128) ascii[value[i]] = i;
 
593
      if (c < 128) ascii[c] = index;
 
594
 
 
595
      // offset from vertical location of baseline
 
596
      // of where the char was drawn (size*2)
 
597
      topExtent[index] = size*2 - minY;
 
598
 
 
599
      // offset from left of where coord was drawn
 
600
      leftExtent[index] = minX - size;
 
601
 
 
602
      if (c == 'd') {
 
603
        ascent = topExtent[index];
 
604
      }
 
605
      if (c == 'p') {
 
606
        descent = -topExtent[index] + height[index];
 
607
      }
 
608
 
 
609
      if (width[index] > maxWidthHeight) maxWidthHeight = width[index];
 
610
      if (height[index] > maxWidthHeight) maxWidthHeight = height[index];
 
611
 
 
612
      bitmaps[index] = new PImage(width[index], height[index], ALPHA);
 
613
 
 
614
      for (int y = minY; y <= maxY; y++) {
 
615
        for (int x = minX; x <= maxX; x++) {
 
616
          int val = 255 - (samples[y * mbox3 + x] & 0xff);
 
617
          int pindex = (y - minY) * width[index] + (x - minX);
 
618
          bitmaps[index].pixels[pindex] = val;
 
619
        }
 
620
      }
 
621
      index++;
 
622
    }
 
623
    charCount = index;
 
624
 
 
625
    // foreign font, so just make ascent the max topExtent
 
626
    if ((ascent == 0) && (descent == 0)) {
 
627
      for (int i = 0; i < charCount; i++) {
 
628
        char cc = (char) value[i];
 
629
        if (Character.isWhitespace(cc) ||
 
630
            (cc == '\u00A0') || (cc == '\u2007') || (cc == '\u202F')) {
 
631
          continue;
 
632
        }
 
633
        if (topExtent[i] > ascent) {
 
634
          ascent = topExtent[i];
 
635
        }
 
636
        int d = -topExtent[i] + height[i];
 
637
        if (d > descent) {
 
638
          descent = d;
 
639
        }
 
640
      }
 
641
    }
 
642
    // size for image/texture is next power of 2 over largest char
 
643
    mbox2 = (int)
 
644
      Math.pow(2, Math.ceil(Math.log(maxWidthHeight) / Math.log(2)));
 
645
    twidth = theight = mbox2;
 
646
 
 
647
    // shove the smaller PImage data into textures of next-power-of-2 size,
 
648
    // so that this font can be used immediately by p5.
 
649
    images = new PImage[charCount];
 
650
    for (int i = 0; i < charCount; i++) {
 
651
      images[i] = new PImage(mbox2, mbox2, ALPHA);
 
652
      for (int y = 0; y < height[i]; y++) {
 
653
        System.arraycopy(bitmaps[i].pixels, y*width[i],
 
654
                         images[i].pixels, y*mbox2,
 
655
                         width[i]);
 
656
      }
 
657
      bitmaps[i] = null;
 
658
    }
 
659
  }
 
660
 
 
661
 
 
662
  /**
 
663
   * Get a list of the fonts installed on the system that can be used
 
664
   * by Java. Not all fonts can be used in Java, in fact it's mostly
 
665
   * only TrueType fonts. OpenType fonts with CFF data such as Adobe's
 
666
   * OpenType fonts seem to have trouble (even though they're sort of
 
667
   * TrueType fonts as well, or may have a .ttf extension). Regular
 
668
   * PostScript fonts seem to work OK, however.
 
669
   * <P>
 
670
   * Not recommended for use in applets, but this is implemented
 
671
   * in PFont because the Java methods to access this information
 
672
   * have changed between 1.1 and 1.4, and the 1.4 method is
 
673
   * typical of the sort of undergraduate-level over-abstraction
 
674
   * that the seems to have made its way into the Java API after 1.1.
 
675
   */
 
676
  static public String[] list() {
 
677
    loadFonts();
 
678
    String list[] = new String[fonts.length];
 
679
    for (int i = 0; i < list.length; i++) {
 
680
      list[i] = fonts[i].getName();
 
681
    }
 
682
    return list;
 
683
  }
 
684
  
 
685
 
 
686
  static public void loadFonts() {
 
687
    if (fonts == null) {
 
688
      GraphicsEnvironment ge =
 
689
        GraphicsEnvironment.getLocalGraphicsEnvironment();
 
690
      fonts = ge.getAllFonts();
 
691
    }
 
692
  }
 
693
 
 
694
 
 
695
  /** 
 
696
   * Starting with Java 1.5, Apple broke the ability to specify most fonts.
 
697
   * This has been filed as bug #4769141 at bugreporter.apple.com. More info at
 
698
   * <a href="http://dev.processing.org/bugs/show_bug.cgi?id=407">Bug 407</a>.
 
699
  */
 
700
  static public Font findFont(String name) {
 
701
    loadFonts();
 
702
    if (PApplet.platform == PConstants.MACOSX) {
 
703
      for (int i = 0; i < fonts.length; i++) {
 
704
        if (name.equals(fonts[i].getName())) {
 
705
          return fonts[i];
 
706
        }
 
707
      }
 
708
    }
 
709
    return new Font(name, Font.PLAIN, 1);
 
710
  }
 
711
}