diff --git a/core/PApplet.java b/core/PApplet.java index 7f7b2cbf3..c1d369f20 100644 --- a/core/PApplet.java +++ b/core/PApplet.java @@ -275,6 +275,10 @@ public class PApplet extends Applet public void depth() { + if (g.textFont != null) { + die("textFont() cannot be used before calling depth()"); + } + // OPT if PGraphics already exists, pass in its pixels[] // buffer so as not to re-allocate all that memory again if (g.width != 0) { @@ -1265,8 +1269,7 @@ public class PApplet extends Applet */ public void die(String what) { stop(); - - throw new RuntimeException("died: " + what); + throw new RuntimeException(what); /* if (online) { System.err.println("i'm dead.. " + what); @@ -2077,6 +2080,10 @@ public class PApplet extends Applet public PFont loadFont(String filename) { + //if (g == null) { // just for good measure + //die("loadFont() only be used inside setup() or draw()"); + //} + try { String lower = filename.toLowerCase(); InputStream input = openStream(filename); @@ -2085,6 +2092,7 @@ public class PApplet extends Applet input = new GZIPInputStream(input); } else if (!lower.endsWith(".vlw")) { + // this gets thrown down below throw new IOException("I don't know how to load a font named " + filename); } @@ -4880,18 +4888,18 @@ v PApplet.this.stop(); } - public void textFont(PFont which) { - if (recorder != null) recorder.textFont(which); - g.textFont(which); - } - - public void textFont(PFont which, float size) { if (recorder != null) recorder.textFont(which, size); g.textFont(which, size); } + public void textFont(PFont which) { + if (recorder != null) recorder.textFont(which); + g.textFont(which); + } + + public void textSize(float size) { if (recorder != null) recorder.textSize(size); g.textSize(size); @@ -4916,6 +4924,26 @@ v PApplet.this.stop(); } + public float textAscent() { + return g.textAscent(); + } + + + public float textDescent() { + return g.textDescent(); + } + + + public float textWidth(char c) { + return g.textWidth(c); + } + + + public float textWidth(String s) { + return g.textWidth(s); + } + + public void text(char c, float x, float y) { if (recorder != null) recorder.text(c, x, y); g.text(c, x, y); @@ -4946,9 +4974,9 @@ v PApplet.this.stop(); } - public void text(String s, float x1, float y1, float z, float x2, float y2) { - if (recorder != null) recorder.text(s, x1, y1, z, x2, y2); - g.text(s, x1, y1, z, x2, y2); + public void text(String s, float x1, float y1, float x2, float y2, float z) { + if (recorder != null) recorder.text(s, x1, y1, x2, y2, z); + g.text(s, x1, y1, x2, y2, z); } diff --git a/core/PConstants.java b/core/PConstants.java index aeb9247ee..e0ca62f84 100644 --- a/core/PConstants.java +++ b/core/PConstants.java @@ -174,6 +174,12 @@ public interface PConstants { static final int IMAGE_SPACE = 1; + // hrmm, can i avoid these? + + //static final int DEFAULT_SIZE = Float.NaN; + //static final int DEFAULT_LEADING = Float.NaN; + + // text placement modes static final int SCREEN_SPACE = 2; diff --git a/core/PFont.java b/core/PFont.java index 1be2d9bb9..2a6fe887f 100644 --- a/core/PFont.java +++ b/core/PFont.java @@ -4,7 +4,7 @@ PFont - font object for text rendering Part of the Processing project - http://processing.org - Copyright (c) 2004 Ben Fry & Casey Reas + Copyright (c) 2004-05 Ben Fry & Casey Reas Portions Copyright (c) 2001-04 Massachusetts Institute of Technology This library is free software; you can redistribute it and/or @@ -81,18 +81,19 @@ public class PFont implements PConstants { public int descent; // scaling, for convenience - public float size; - public float leading; - public int align; - public int space; + //public float size; + //public float leading; + //public int align; + //public int space; int ascii[]; // quick lookup for the ascii chars //boolean cached; - // used by the text() functions to avoid over-allocation of memory - private char textBuffer[] = new char[8 * 1024]; - private char widthBuffer[] = new char[8 * 1024]; + // shared by the text() functions to avoid incessant allocation of memory + protected char textBuffer[] = new char[8 * 1024]; + protected char widthBuffer[] = new char[8 * 1024]; + //public PGraphics parent; public PFont() { } // for PFontAI subclass and font builder @@ -194,9 +195,8 @@ public class PFont implements PConstants { int valu = temp[y*w + x] & 0xff; //images[i].pixels[y * twidth + x] = valu; - images[i].pixels[y * twidth + x] = - //valu; - (valu << 24) | 0xFFFFFF; // windows + images[i].pixels[y * twidth + x] = valu; + //(valu << 24) | 0xFFFFFF; // windows //0xFFFFFF00 | valu; // macosx //(valu << 24) | (valu << 16) | (valu << 8) | valu; @@ -210,10 +210,9 @@ public class PFont implements PConstants { } ///cached = false; - resetSize(); - //resetLeading(); // ?? - space = OBJECT_SPACE; - align = ALIGN_LEFT; + //resetSize(); + //space = OBJECT_SPACE; + //align = ALIGN_LEFT; } //static boolean isSpace(int c) { @@ -282,7 +281,7 @@ public class PFont implements PConstants { // whups, this used the p5 charset rather than what was inside the font // meaning that old fonts would crash.. fixed for 0069 - private int index_hunt(int c, int start, int stop) { + protected int index_hunt(int c, int start, int stop) { //System.err.println("checking between " + start + " and " + stop); int pivot = (start + stop) / 2; @@ -301,6 +300,7 @@ public class PFont implements PConstants { } + /* public void space(int which) { this.space = which; if (space == SCREEN_SPACE) { @@ -313,13 +313,19 @@ public class PFont implements PConstants { public void align(int which) { this.align = which; } + */ + /** + * Currently un-implemented for .vlw fonts, + * but honored for layout in case subclasses use it. + */ public float kern(char a, char b) { return 0; // * size, but since zero.. } + /* public void resetSize() { //size = 12; size = mbox; // default size for the font @@ -341,28 +347,45 @@ public class PFont implements PConstants { public void leading(float ileading) { leading = ileading; } + */ + /** + * Returns the ascent of this font from the baseline. + * The value is based on a font of size 1. + */ public float ascent() { - return ((float)ascent / fheight) * size; + return ((float)ascent / fheight); // * size; } + /** + * Returns how far this font descends from the baseline. + * The value is based on a font size of 1. + */ public float descent() { - return ((float)descent / fheight) * size; + return ((float)descent / fheight); // * size; } + /** + * Width of this character for a font of size 1. + */ public float width(char c) { if (c == 32) return width('i'); int cc = index(c); if (cc == -1) return 0; - return ((float)setWidth[cc] / fwidth) * size; + //return ((float)setWidth[cc] / fwidth) * size; + return ((float)setWidth[cc] / fwidth); // * size; } + /** + * Return the width of a line of text of size 1. If the text has + * multiple lines, this returns the length of the longest line. + */ public float width(String str) { int length = str.length(); if (length > widthBuffer.length) { @@ -399,12 +422,31 @@ public class PFont implements PConstants { } + /** + * Draw a character at an x, y position. + */ public void text(char c, float x, float y, PGraphics parent) { text(c, x, y, 0, parent); } public void text(char c, float x, float y, float z, PGraphics parent) { + if (parent.textMode == ALIGN_CENTER) { + x -= parent.textSize * width(c) / 2f; + + } else if (parent.textMode == ALIGN_RIGHT) { + x -= parent.textSize * width(c); + } + + textImpl(c, x, y, z, parent); + } + + + /** + * Draw a character at an x, y, z position. + */ + //public void text(char c, float x, float y, float z, PGraphics parent) { + protected void textImpl(char c, float x, float y, float z, PGraphics parent) { //if (!valid) return; //if (!exists(c)) return; @@ -422,21 +464,31 @@ public class PFont implements PConstants { } */ - if (space == OBJECT_SPACE) { + if (parent.textSpace == OBJECT_SPACE) { float high = (float) height[glyph] / fheight; float bwidth = (float) width[glyph] / fwidth; float lextent = (float) leftExtent[glyph] / fwidth; float textent = (float) topExtent[glyph] / fheight; - float x1 = x + lextent * size; - float y1 = y - textent * size; - float x2 = x1 + bwidth * size; - float y2 = y1 + high * size; + float x1 = x + lextent * parent.textSize; + float y1 = y - textent * parent.textSize; + float x2 = x1 + bwidth * parent.textSize; + float y2 = y1 + high * parent.textSize; + + //parent.rectImpl(x1, y1, x2, y2); + + //boolean savedTint = parent.tint; + //int savedTintColor = parent.tintColor; + //parent.tint = true; + //parent.tintColor = parent.fillColor; parent.imageImpl(images[glyph], x1, y1, x2-x1, y2-y1, 0, 0, width[glyph], height[glyph]); + //parent.tint = savedTint; + //parent.tintColor = savedTintColor; + /* // this code was moved here (instead of using parent.image) // because now images use tint() for their coloring, which @@ -547,7 +599,7 @@ public class PFont implements PConstants { if (textBuffer[index] == '\n') { textLine(start, index, x, y, z, parent); start = index + 1; - y += leading; + y += parent.textLeading; } index++; } @@ -564,15 +616,15 @@ public class PFont implements PConstants { //int index = 0; //char previous = 0; - if (align == ALIGN_CENTER) { - x -= calcWidth(textBuffer, start, stop) / 2f; + if (parent.textMode == ALIGN_CENTER) { + x -= parent.textSize * calcWidth(textBuffer, start, stop) / 2f; - } else if (align == ALIGN_RIGHT) { - x -= calcWidth(textBuffer, start, stop); + } else if (parent.textMode == ALIGN_RIGHT) { + x -= parent.textSize * calcWidth(textBuffer, start, stop); } for (int index = start; index < stop; index++) { - text(textBuffer[index], x, y, z, parent); + textImpl(textBuffer[index], x, y, z, parent); x += width(textBuffer[index]); } } @@ -605,9 +657,9 @@ public class PFont implements PConstants { //float right = x + w; float lineX = boxX1; - if (align == ALIGN_CENTER) { + if (parent.textMode == ALIGN_CENTER) { lineX = lineX + boxWidth/2f; - } else if (align == ALIGN_RIGHT) { + } else if (parent.textMode == ALIGN_RIGHT) { lineX = boxX2; } @@ -666,7 +718,7 @@ public class PFont implements PConstants { wordStart = index; wordStop = index; runningX = boxX1; - currentY += leading; + currentY += parent.textLeading; if (currentY > boxY2) return; // box is now full } else { @@ -682,7 +734,7 @@ public class PFont implements PConstants { } lineStart = index + 1; wordStart = lineStart; - currentY += leading; + currentY += parent.textLeading; if (currentY > boxY2) return; // box is now full } index++; @@ -696,248 +748,6 @@ public class PFont implements PConstants { } - // ................................................................. - - - /** - * Draw SCREEN_SPACE text on its left edge. - * This method is incomplete and should not be used. - */ - public void ltext(String str, float x, float y, PGraphics parent) { - float startY = y; - int index = 0; - char previous = 0; - - int length = str.length(); - if (length > textBuffer.length) { - textBuffer = new char[length + 10]; - } - str.getChars(0, length, textBuffer, 0); - - while (index < length) { - if (textBuffer[index] == '\n') { - y = startY; - x += leading; - previous = 0; - - } else { - ltext(textBuffer[index], x, y, parent); - y -= width(textBuffer[index]); - if (previous != 0) - y -= kern(previous, textBuffer[index]); - previous = textBuffer[index]; - } - index++; - } - } - - - /** - * Draw SCREEN_SPACE text on its left edge. - * This method is incomplete and should not be used. - */ - public void ltext(char c, float x, float y, PGraphics parent) { - int glyph = index(c); - if (glyph == -1) return; - - // top-lefthand corner of the char - int sx = (int) x - topExtent[glyph]; - int sy = (int) y - leftExtent[glyph]; - - // boundary of the character's pixel buffer to copy - int px = 0; - int py = 0; - int pw = width[glyph]; - int ph = height[glyph]; - - // if the character is off the screen - if ((sx >= parent.width) || // top of letter past width - (sy - pw >= parent.height) || - (sy + pw < 0) || - (sx + ph < 0)) return; - - if (sx < 0) { // if starting x is off screen - py -= sx; - ph += sx; - sx = 0; - } - if (sx + ph >= parent.width) { - ph -= ((sx + ph) - parent.width); - } - - if (sy < pw) { - //int extra = pw - sy; - pw -= -1 + pw - sy; - //px -= sy; - //pw += sy; - //sy = 0; - } - if (sy >= parent.height) { // off bottom edge - int extra = 1 + sy - parent.height; - pw -= extra; - px += extra; - sy -= extra; - //pw -= ((sy + pw) - parent.height); - } - - int fr = parent.fillRi; - int fg = parent.fillGi; - int fb = parent.fillBi; - int fa = parent.fillAi; - - int pixels1[] = images[glyph].pixels; - int pixels2[] = parent.pixels; - - // loop over the source pixels in the character image - // row & col is the row and column of the source image - // (but they become col & row in the target image) - for (int row = py; row < py + ph; row++) { - for (int col = px; col < px + pw; col++) { - int a1 = (fa * pixels1[row * twidth + col]) >> 8; - int a2 = a1 ^ 0xff; - int p1 = pixels1[row * width[glyph] + col]; - - try { - int index = (sy + px-col)*parent.width + (sx+row-py); - int p2 = pixels2[index]; - - pixels2[index] = - (0xff000000 | - (((a1 * fr + a2 * ((p2 >> 16) & 0xff)) & 0xff00) << 8) | - (( a1 * fg + a2 * ((p2 >> 8) & 0xff)) & 0xff00) | - (( a1 * fb + a2 * ( p2 & 0xff)) >> 8)); - } catch (ArrayIndexOutOfBoundsException e) { - System.out.println("out of bounds " + sy + " " + px + " " + col); - } - } - } - } - - - // ................................................................. - - - /** - * Draw SCREEN_SPACE text on its right edge. - * This method is incomplete and should not be used. - */ - public void rtext(String str, float x, float y, PGraphics parent) { - float startY = y; - int index = 0; - char previous = 0; - - int length = str.length(); - if (length > textBuffer.length) { - textBuffer = new char[length + 10]; - } - str.getChars(0, length, textBuffer, 0); - - while (index < length) { - if (textBuffer[index] == '\n') { - y = startY; - x += leading; - previous = 0; - - } else { - rtext(textBuffer[index], x, y, parent); - y += width(textBuffer[index]); - if (previous != 0) - y += kern(previous, textBuffer[index]); - previous = textBuffer[index]; - } - index++; - } - } - - - /** - * Draw SCREEN_SPACE text on its right edge. - * This method is incomplete and should not be used. - */ - public void rtext(char c, float x, float y, PGraphics parent) { - int glyph = index(c); - if (glyph == -1) return; - - // starting point on the screen - int sx = (int) x + topExtent[glyph]; - int sy = (int) y + leftExtent[glyph]; - - // boundary of the character's pixel buffer to copy - int px = 0; - int py = 0; - int pw = width[glyph]; - int ph = height[glyph]; - - // if the character is off the screen - if ((sx - ph >= parent.width) || (sy >= parent.height) || - (sy + pw < 0) || (sx < 0)) return; - - // off the left of screen, cut off bottom of letter - if (sx < ph) { - //x0 -= xx; // chop that amount off of the image area to be copied - //w0 += xx; // and reduce the width by that (negative) amount - //py0 -= xx; // if x = -3, cut off 3 pixels from the bottom - //ph0 += xx; - ph -= (ph - sx) - 1; - //sx = 0; - } - // off the right of the screen, cut off top of the letter - if (sx >= parent.width) { - int extra = sx - (parent.width-1); - py += extra; - ph -= extra; - //sx = parent.width-1; - } - // off the top, cut off left edge of letter - if (sy < 0) { - int extra = -sy; - px += extra; - pw -= extra; - sy = 0; - } - // off the bottom, cut off right edge of letter - if (sy + pw >= parent.height-1) { - int extra = (sy + pw) - parent.height; - pw -= extra; - } - - int fr = parent.fillRi; - int fg = parent.fillGi; - int fb = parent.fillBi; - int fa = parent.fillAi; - - int fpixels[] = images[glyph].pixels; - int spixels[] = parent.pixels; - - // loop over the source pixels in the character image - // row & col is the row and column of the source image - // (but they become col & row in the target image) - for (int row = py; row < py + ph; row++) { - for (int col = px; col < px + pw; col++) { - int a1 = (fa * fpixels[row * twidth + col]) >> 8; - int a2 = a1 ^ 0xff; - int p1 = fpixels[row * width[glyph] + col]; - - try { - //int index = (yy + x0-col)*parent.width + (xx+row-y0); - //int index = (sy + px-col)*parent.width + (sx+row-py); - int index = (sy + px+col)*parent.width + (sx-row); - int p2 = spixels[index]; - - // x coord is backwards - spixels[index] = - (0xff000000 | - (((a1 * fr + a2 * ((p2 >> 16) & 0xff)) & 0xff00) << 8) | - (( a1 * fg + a2 * ((p2 >> 8) & 0xff)) & 0xff00) | - (( a1 * fb + a2 * ( p2 & 0xff)) >> 8)); - } catch (ArrayIndexOutOfBoundsException e) { - System.out.println("out of bounds " + sy + " " + px + " " + col); - } - } - } - } - - // .................................................................... @@ -1006,6 +816,15 @@ public class PFont implements PConstants { this(new Font(name, Font.PLAIN, size), false, smooth); } + + /** + * Use reflection to create a new .vlw font on the fly. + * This only works with Java 1.3 and higher. + * + * @param Font the font object to create from + * @param all true to include all available characters in the font + * @param smooth true to enable smoothing/anti-aliasing + */ public PFont(Font font, boolean all, boolean smooth) { try { this.charCount = all ? 65536 : charset.length; diff --git a/core/PGraphics.java b/core/PGraphics.java index 02e32578a..40e7bc33f 100644 --- a/core/PGraphics.java +++ b/core/PGraphics.java @@ -385,6 +385,10 @@ public class PGraphics extends PImage implements PConstants { // no current font textFont = null; + textSize = 12; + textLeading = 14; + textMode = ALIGN_LEFT; + textSpace = OBJECT_SPACE; //text_mode = ALIGN_LEFT; //text_space = OBJECT_SPACE; } @@ -1411,11 +1415,17 @@ public class PGraphics extends PImage implements PConstants { // TEXT/FONTS + public void textFont(PFont which, float size) { + textFont(which); + textSize(size); + } + + public void textFont(PFont which) { if (which != null) { textFont = which; - textFont.resetSize(); - textFont.resetLeading(); + //textFont.resetSize(); + //textFont.resetLeading(); } else { throw new RuntimeException("a null PFont was passed to textFont()"); @@ -1423,16 +1433,10 @@ public class PGraphics extends PImage implements PConstants { } - public void textFont(PFont which, float size) { - textFont(which); - textSize(size); - } - - public void textSize(float size) { if (textFont != null) { - //textFont.size(size); textSize = size; + resetLeading(); } else { throw new RuntimeException("use textFont() before textSize()"); @@ -1440,33 +1444,91 @@ public class PGraphics extends PImage implements PConstants { } + protected void resetLeading() { + textLeading = (textFont.ascent() + textFont.descent()) * 1.275f; + } + + public void textLeading(float leading) { + textLeading = leading; + /* if (textFont != null) { textFont.leading(leading); } else { throw new RuntimeException("use textFont() before textLeading()"); } + */ } public void textMode(int mode) { + textMode = mode; + /* if (textFont != null) { textFont.align(mode); } else { throw new RuntimeException("use textFont() before textMode()"); } + */ } public void textSpace(int space) { + textSpace = space; + /* if (textFont != null) { textFont.space(space); } else { throw new RuntimeException("use textFont() before textSpace()"); } + */ + } + + + public float textAscent() { + if (textFont != null) { + return textFont.ascent() * textSize; + + } else { + throw new RuntimeException("use textFont() before textAscent()"); + } + } + + + public float textDescent() { + if (textFont != null) { + return textFont.descent() * textSize; + + } else { + throw new RuntimeException("use textFont() before textDescent()"); + } + } + + + public float textWidth(char c) { + if (textFont != null) { + return textFont.width(c) * textSize; + + } else { + throw new RuntimeException("use textFont() before textWidth()"); + } + } + + + /** + * Return the width of a line of text. If the text has multiple + * lines, this returns the length of the longest line. + */ + public float textWidth(String s) { + if (textFont != null) { + return textFont.width(s) * textSize; + + } else { + throw new RuntimeException("use textFont() before textWidth()"); + } } @@ -1481,7 +1543,21 @@ public class PGraphics extends PImage implements PConstants { public void text(char c, float x, float y, float z) { - // not supported in 2D + if ((z != 0) && (textSpace == SCREEN_SPACE)) { + String msg = "textSpace(SCREEN_SPACE) cannot have a z coordinate"; + throw new RuntimeException(msg); + } + + // this just has to pass through.. if z is not zero when + // drawing to non-depth(), the PFont will have to throw an error. + if (textFont != null) { + textFont.text(c, x, y, z, this); + + } else { + throw new RuntimeException("use textFont() before text()"); + } + //throw new RuntimeException("text() with a z coordinate is " + + // "only supported when depth() is used"); } @@ -1496,7 +1572,21 @@ public class PGraphics extends PImage implements PConstants { public void text(String s, float x, float y, float z) { - // not supported in 2D + if ((z != 0) && (textSpace == SCREEN_SPACE)) { + String msg = "textSpace(SCREEN_SPACE) cannot have a z coordinate"; + throw new RuntimeException(msg); + } + + // this just has to pass through.. if z is not zero when + // drawing to non-depth(), the PFont will have to throw an error. + if (textFont != null) { + textFont.text(s, x, y, z, this); + + } else { + throw new RuntimeException("use textFont() before text()"); + } + //throw new RuntimeException("text() with a z coordinate is " + + // "only supported when depth() is used"); } @@ -1537,8 +1627,9 @@ public class PGraphics extends PImage implements PConstants { } - public void text(String s, float x1, float y1, float z, float x2, float y2) { - // not supported in 2D + public void text(String s, float x1, float y1, float x2, float y2, float z) { + throw new RuntimeException("text() with a z coordinate is " + + "only supported when depth() is used"); } @@ -1548,7 +1639,9 @@ public class PGraphics extends PImage implements PConstants { public void text(int num, float x, float y, float z) { - // not supported in 2D + text(String.valueOf(num), x, y, z); + //throw new RuntimeException("text() with a z coordinate is " + + // "only supported when depth() is used"); } diff --git a/core/PMethods.java b/core/PMethods.java index d616c963e..104ae9272 100755 --- a/core/PMethods.java +++ b/core/PMethods.java @@ -171,6 +171,14 @@ public interface PMethods { public void textSpace(int space); + public float textAscent(); + + public float textDescent(); + + public float textWidth(char c); + + public float textWidth(String s); + public void text(char c, float x, float y); public void text(char c, float x, float y, float z); @@ -181,7 +189,7 @@ public interface PMethods { public void text(String s, float x, float y, float w, float h); - public void text(String s, float x1, float y1, float z, float x2, float y2); + public void text(String s, float x1, float y1, float x2, float y2, float z); public void text(int num, float x, float y);