mirror of
https://github.com/esp8266/Arduino.git
synced 2025-06-20 21:01:25 +03:00
Importing Processing rev. 5503 (1.0.3).
This commit is contained in:
8076
core/src/processing/core/PApplet.java
Normal file
8076
core/src/processing/core/PApplet.java
Normal file
File diff suppressed because it is too large
Load Diff
461
core/src/processing/core/PConstants.java
Normal file
461
core/src/processing/core/PConstants.java
Normal file
@ -0,0 +1,461 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2004-08 Ben Fry and Casey Reas
|
||||
Copyright (c) 2001-04 Massachusetts Institute of Technology
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.core;
|
||||
|
||||
import java.awt.Cursor;
|
||||
import java.awt.event.KeyEvent;
|
||||
|
||||
|
||||
/**
|
||||
* Numbers shared throughout processing.core.
|
||||
* <P>
|
||||
* An attempt is made to keep the constants as short/non-verbose
|
||||
* as possible. For instance, the constant is TIFF instead of
|
||||
* FILE_TYPE_TIFF. We'll do this as long as we can get away with it.
|
||||
*/
|
||||
public interface PConstants {
|
||||
|
||||
static public final int X = 0; // model coords xyz (formerly MX/MY/MZ)
|
||||
static public final int Y = 1;
|
||||
static public final int Z = 2;
|
||||
|
||||
static public final int R = 3; // actual rgb, after lighting
|
||||
static public final int G = 4; // fill stored here, transform in place
|
||||
static public final int B = 5; // TODO don't do that anymore (?)
|
||||
static public final int A = 6;
|
||||
|
||||
static public final int U = 7; // texture
|
||||
static public final int V = 8;
|
||||
|
||||
static public final int NX = 9; // normal
|
||||
static public final int NY = 10;
|
||||
static public final int NZ = 11;
|
||||
|
||||
static public final int EDGE = 12;
|
||||
|
||||
|
||||
// stroke
|
||||
|
||||
/** stroke argb values */
|
||||
static public final int SR = 13;
|
||||
static public final int SG = 14;
|
||||
static public final int SB = 15;
|
||||
static public final int SA = 16;
|
||||
|
||||
/** stroke weight */
|
||||
static public final int SW = 17;
|
||||
|
||||
|
||||
// transformations (2D and 3D)
|
||||
|
||||
static public final int TX = 18; // transformed xyzw
|
||||
static public final int TY = 19;
|
||||
static public final int TZ = 20;
|
||||
|
||||
static public final int VX = 21; // view space coords
|
||||
static public final int VY = 22;
|
||||
static public final int VZ = 23;
|
||||
static public final int VW = 24;
|
||||
|
||||
|
||||
// material properties
|
||||
|
||||
// Ambient color (usually to be kept the same as diffuse)
|
||||
// fill(_) sets both ambient and diffuse.
|
||||
static public final int AR = 25;
|
||||
static public final int AG = 26;
|
||||
static public final int AB = 27;
|
||||
|
||||
// Diffuse is shared with fill.
|
||||
static public final int DR = 3; // TODO needs to not be shared, this is a material property
|
||||
static public final int DG = 4;
|
||||
static public final int DB = 5;
|
||||
static public final int DA = 6;
|
||||
|
||||
// specular (by default kept white)
|
||||
static public final int SPR = 28;
|
||||
static public final int SPG = 29;
|
||||
static public final int SPB = 30;
|
||||
|
||||
static public final int SHINE = 31;
|
||||
|
||||
// emissive (by default kept black)
|
||||
static public final int ER = 32;
|
||||
static public final int EG = 33;
|
||||
static public final int EB = 34;
|
||||
|
||||
// has this vertex been lit yet
|
||||
static public final int BEEN_LIT = 35;
|
||||
|
||||
static public final int VERTEX_FIELD_COUNT = 36;
|
||||
|
||||
|
||||
// renderers known to processing.core
|
||||
|
||||
static final String P2D = "processing.core.PGraphics2D";
|
||||
static final String P3D = "processing.core.PGraphics3D";
|
||||
static final String JAVA2D = "processing.core.PGraphicsJava2D";
|
||||
static final String OPENGL = "processing.opengl.PGraphicsOpenGL";
|
||||
static final String PDF = "processing.pdf.PGraphicsPDF";
|
||||
static final String DXF = "processing.dxf.RawDXF";
|
||||
|
||||
|
||||
// platform IDs for PApplet.platform
|
||||
|
||||
static final int OTHER = 0;
|
||||
static final int WINDOWS = 1;
|
||||
static final int MACOSX = 2;
|
||||
static final int LINUX = 3;
|
||||
|
||||
static final String[] platformNames = {
|
||||
"other", "windows", "macosx", "linux"
|
||||
};
|
||||
|
||||
|
||||
static final float EPSILON = 0.0001f;
|
||||
|
||||
|
||||
// max/min values for numbers
|
||||
|
||||
/**
|
||||
* Same as Float.MAX_VALUE, but included for parity with MIN_VALUE,
|
||||
* and to avoid teaching static methods on the first day.
|
||||
*/
|
||||
static final float MAX_FLOAT = Float.MAX_VALUE;
|
||||
/**
|
||||
* Note that Float.MIN_VALUE is the smallest <EM>positive</EM> value
|
||||
* for a floating point number, not actually the minimum (negative) value
|
||||
* for a float. This constant equals 0xFF7FFFFF, the smallest (farthest
|
||||
* negative) value a float can have before it hits NaN.
|
||||
*/
|
||||
static final float MIN_FLOAT = -Float.MAX_VALUE;
|
||||
/** Largest possible (positive) integer value */
|
||||
static final int MAX_INT = Integer.MAX_VALUE;
|
||||
/** Smallest possible (negative) integer value */
|
||||
static final int MIN_INT = Integer.MIN_VALUE;
|
||||
|
||||
|
||||
// useful goodness
|
||||
|
||||
static final float PI = (float) Math.PI;
|
||||
static final float HALF_PI = PI / 2.0f;
|
||||
static final float THIRD_PI = PI / 3.0f;
|
||||
static final float QUARTER_PI = PI / 4.0f;
|
||||
static final float TWO_PI = PI * 2.0f;
|
||||
|
||||
static final float DEG_TO_RAD = PI/180.0f;
|
||||
static final float RAD_TO_DEG = 180.0f/PI;
|
||||
|
||||
|
||||
// angle modes
|
||||
|
||||
//static final int RADIANS = 0;
|
||||
//static final int DEGREES = 1;
|
||||
|
||||
|
||||
// used by split, all the standard whitespace chars
|
||||
// (also includes unicode nbsp, that little bostage)
|
||||
|
||||
static final String WHITESPACE = " \t\n\r\f\u00A0";
|
||||
|
||||
|
||||
// for colors and/or images
|
||||
|
||||
static final int RGB = 1; // image & color
|
||||
static final int ARGB = 2; // image
|
||||
static final int HSB = 3; // color
|
||||
static final int ALPHA = 4; // image
|
||||
static final int CMYK = 5; // image & color (someday)
|
||||
|
||||
|
||||
// image file types
|
||||
|
||||
static final int TIFF = 0;
|
||||
static final int TARGA = 1;
|
||||
static final int JPEG = 2;
|
||||
static final int GIF = 3;
|
||||
|
||||
|
||||
// filter/convert types
|
||||
|
||||
static final int BLUR = 11;
|
||||
static final int GRAY = 12;
|
||||
static final int INVERT = 13;
|
||||
static final int OPAQUE = 14;
|
||||
static final int POSTERIZE = 15;
|
||||
static final int THRESHOLD = 16;
|
||||
static final int ERODE = 17;
|
||||
static final int DILATE = 18;
|
||||
|
||||
|
||||
// blend mode keyword definitions
|
||||
// @see processing.core.PImage#blendColor(int,int,int)
|
||||
|
||||
public final static int REPLACE = 0;
|
||||
public final static int BLEND = 1 << 0;
|
||||
public final static int ADD = 1 << 1;
|
||||
public final static int SUBTRACT = 1 << 2;
|
||||
public final static int LIGHTEST = 1 << 3;
|
||||
public final static int DARKEST = 1 << 4;
|
||||
public final static int DIFFERENCE = 1 << 5;
|
||||
public final static int EXCLUSION = 1 << 6;
|
||||
public final static int MULTIPLY = 1 << 7;
|
||||
public final static int SCREEN = 1 << 8;
|
||||
public final static int OVERLAY = 1 << 9;
|
||||
public final static int HARD_LIGHT = 1 << 10;
|
||||
public final static int SOFT_LIGHT = 1 << 11;
|
||||
public final static int DODGE = 1 << 12;
|
||||
public final static int BURN = 1 << 13;
|
||||
|
||||
// colour component bitmasks
|
||||
|
||||
public static final int ALPHA_MASK = 0xff000000;
|
||||
public static final int RED_MASK = 0x00ff0000;
|
||||
public static final int GREEN_MASK = 0x0000ff00;
|
||||
public static final int BLUE_MASK = 0x000000ff;
|
||||
|
||||
|
||||
// for messages
|
||||
|
||||
static final int CHATTER = 0;
|
||||
static final int COMPLAINT = 1;
|
||||
static final int PROBLEM = 2;
|
||||
|
||||
|
||||
// types of projection matrices
|
||||
|
||||
static final int CUSTOM = 0; // user-specified fanciness
|
||||
static final int ORTHOGRAPHIC = 2; // 2D isometric projection
|
||||
static final int PERSPECTIVE = 3; // perspective matrix
|
||||
|
||||
|
||||
// shapes
|
||||
|
||||
// the low four bits set the variety,
|
||||
// higher bits set the specific shape type
|
||||
|
||||
//static final int GROUP = (1 << 2);
|
||||
|
||||
static final int POINT = 2; // shared with light (!)
|
||||
static final int POINTS = 2;
|
||||
|
||||
static final int LINE = 4;
|
||||
static final int LINES = 4;
|
||||
|
||||
static final int TRIANGLE = 8;
|
||||
static final int TRIANGLES = 9;
|
||||
static final int TRIANGLE_STRIP = 10;
|
||||
static final int TRIANGLE_FAN = 11;
|
||||
|
||||
static final int QUAD = 16;
|
||||
static final int QUADS = 16;
|
||||
static final int QUAD_STRIP = 17;
|
||||
|
||||
static final int POLYGON = 20;
|
||||
static final int PATH = 21;
|
||||
|
||||
static final int RECT = 30;
|
||||
static final int ELLIPSE = 31;
|
||||
static final int ARC = 32;
|
||||
|
||||
static final int SPHERE = 40;
|
||||
static final int BOX = 41;
|
||||
|
||||
|
||||
// shape closing modes
|
||||
|
||||
static final int OPEN = 1;
|
||||
static final int CLOSE = 2;
|
||||
|
||||
|
||||
// shape drawing modes
|
||||
|
||||
/** Draw mode convention to use (x, y) to (width, height) */
|
||||
static final int CORNER = 0;
|
||||
/** Draw mode convention to use (x1, y1) to (x2, y2) coordinates */
|
||||
static final int CORNERS = 1;
|
||||
/** Draw mode from the center, and using the radius */
|
||||
static final int RADIUS = 2;
|
||||
/** @deprecated Use RADIUS instead. */
|
||||
static final int CENTER_RADIUS = 2;
|
||||
/**
|
||||
* Draw from the center, using second pair of values as the diameter.
|
||||
* Formerly called CENTER_DIAMETER in alpha releases.
|
||||
*/
|
||||
static final int CENTER = 3;
|
||||
/**
|
||||
* Synonym for the CENTER constant. Draw from the center,
|
||||
* using second pair of values as the diameter.
|
||||
*/
|
||||
static final int DIAMETER = 3;
|
||||
/** @deprecated Use DIAMETER instead. */
|
||||
static final int CENTER_DIAMETER = 3;
|
||||
|
||||
|
||||
// vertically alignment modes for text
|
||||
|
||||
/** Default vertical alignment for text placement */
|
||||
static final int BASELINE = 0;
|
||||
/** Align text to the top */
|
||||
static final int TOP = 101;
|
||||
/** Align text from the bottom, using the baseline. */
|
||||
static final int BOTTOM = 102;
|
||||
|
||||
|
||||
// uv texture orientation modes
|
||||
|
||||
/** texture coordinates in 0..1 range */
|
||||
static final int NORMAL = 1;
|
||||
/** @deprecated use NORMAL instead */
|
||||
static final int NORMALIZED = 1;
|
||||
/** texture coordinates based on image width/height */
|
||||
static final int IMAGE = 2;
|
||||
|
||||
|
||||
// text placement modes
|
||||
|
||||
/**
|
||||
* textMode(MODEL) is the default, meaning that characters
|
||||
* will be affected by transformations like any other shapes.
|
||||
* <p/>
|
||||
* Changed value in 0093 to not interfere with LEFT, CENTER, and RIGHT.
|
||||
*/
|
||||
static final int MODEL = 4;
|
||||
|
||||
/**
|
||||
* textMode(SHAPE) draws text using the the glyph outlines of
|
||||
* individual characters rather than as textures. If the outlines are
|
||||
* not available, then textMode(SHAPE) will be ignored and textMode(MODEL)
|
||||
* will be used instead. For this reason, be sure to call textMode()
|
||||
* <EM>after</EM> calling textFont().
|
||||
* <p/>
|
||||
* Currently, textMode(SHAPE) is only supported by OPENGL mode.
|
||||
* It also requires Java 1.2 or higher (OPENGL requires 1.4 anyway)
|
||||
*/
|
||||
static final int SHAPE = 5;
|
||||
|
||||
|
||||
// text alignment modes
|
||||
// are inherited from LEFT, CENTER, RIGHT
|
||||
|
||||
|
||||
// stroke modes
|
||||
|
||||
static final int SQUARE = 1 << 0; // called 'butt' in the svg spec
|
||||
static final int ROUND = 1 << 1;
|
||||
static final int PROJECT = 1 << 2; // called 'square' in the svg spec
|
||||
static final int MITER = 1 << 3;
|
||||
static final int BEVEL = 1 << 5;
|
||||
|
||||
|
||||
// lighting
|
||||
|
||||
static final int AMBIENT = 0;
|
||||
static final int DIRECTIONAL = 1;
|
||||
//static final int POINT = 2; // shared with shape feature
|
||||
static final int SPOT = 3;
|
||||
|
||||
|
||||
// key constants
|
||||
|
||||
// only including the most-used of these guys
|
||||
// if people need more esoteric keys, they can learn about
|
||||
// the esoteric java KeyEvent api and of virtual keys
|
||||
|
||||
// both key and keyCode will equal these values
|
||||
// for 0125, these were changed to 'char' values, because they
|
||||
// can be upgraded to ints automatically by Java, but having them
|
||||
// as ints prevented split(blah, TAB) from working
|
||||
static final char BACKSPACE = 8;
|
||||
static final char TAB = 9;
|
||||
static final char ENTER = 10;
|
||||
static final char RETURN = 13;
|
||||
static final char ESC = 27;
|
||||
static final char DELETE = 127;
|
||||
|
||||
// i.e. if ((key == CODED) && (keyCode == UP))
|
||||
static final int CODED = 0xffff;
|
||||
|
||||
// key will be CODED and keyCode will be this value
|
||||
static final int UP = KeyEvent.VK_UP;
|
||||
static final int DOWN = KeyEvent.VK_DOWN;
|
||||
static final int LEFT = KeyEvent.VK_LEFT;
|
||||
static final int RIGHT = KeyEvent.VK_RIGHT;
|
||||
|
||||
// key will be CODED and keyCode will be this value
|
||||
static final int ALT = KeyEvent.VK_ALT;
|
||||
static final int CONTROL = KeyEvent.VK_CONTROL;
|
||||
static final int SHIFT = KeyEvent.VK_SHIFT;
|
||||
|
||||
|
||||
// cursor types
|
||||
|
||||
static final int ARROW = Cursor.DEFAULT_CURSOR;
|
||||
static final int CROSS = Cursor.CROSSHAIR_CURSOR;
|
||||
static final int HAND = Cursor.HAND_CURSOR;
|
||||
static final int MOVE = Cursor.MOVE_CURSOR;
|
||||
static final int TEXT = Cursor.TEXT_CURSOR;
|
||||
static final int WAIT = Cursor.WAIT_CURSOR;
|
||||
|
||||
|
||||
// hints - hint values are positive for the alternate version,
|
||||
// negative of the same value returns to the normal/default state
|
||||
|
||||
static final int DISABLE_OPENGL_2X_SMOOTH = 1;
|
||||
static final int ENABLE_OPENGL_2X_SMOOTH = -1;
|
||||
static final int ENABLE_OPENGL_4X_SMOOTH = 2;
|
||||
|
||||
static final int ENABLE_NATIVE_FONTS = 3;
|
||||
|
||||
static final int DISABLE_DEPTH_TEST = 4;
|
||||
static final int ENABLE_DEPTH_TEST = -4;
|
||||
|
||||
static final int ENABLE_DEPTH_SORT = 5;
|
||||
static final int DISABLE_DEPTH_SORT = -5;
|
||||
|
||||
static final int DISABLE_OPENGL_ERROR_REPORT = 6;
|
||||
static final int ENABLE_OPENGL_ERROR_REPORT = -6;
|
||||
|
||||
static final int ENABLE_ACCURATE_TEXTURES = 7;
|
||||
static final int DISABLE_ACCURATE_TEXTURES = -7;
|
||||
|
||||
static final int HINT_COUNT = 10;
|
||||
|
||||
|
||||
// error messages
|
||||
|
||||
static final String ERROR_BACKGROUND_IMAGE_SIZE =
|
||||
"background image must be the same size as your application";
|
||||
static final String ERROR_BACKGROUND_IMAGE_FORMAT =
|
||||
"background images should be RGB or ARGB";
|
||||
|
||||
static final String ERROR_TEXTFONT_NULL_PFONT =
|
||||
"A null PFont was passed to textFont()";
|
||||
|
||||
static final String ERROR_PUSHMATRIX_OVERFLOW =
|
||||
"Too many calls to pushMatrix().";
|
||||
static final String ERROR_PUSHMATRIX_UNDERFLOW =
|
||||
"Too many calls to popMatrix(), and not enough to pushMatrix().";
|
||||
}
|
711
core/src/processing/core/PFont.java
Normal file
711
core/src/processing/core/PFont.java
Normal file
@ -0,0 +1,711 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2004-07 Ben Fry & Casey Reas
|
||||
Copyright (c) 2001-04 Massachusetts Institute of Technology
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.core;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.Raster;
|
||||
import java.io.*;
|
||||
//import java.lang.reflect.*;
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
/**
|
||||
* Grayscale bitmap font class used by Processing.
|
||||
* <P>
|
||||
* Awful (and by that, I mean awesome) ascii (non)art for how this works:
|
||||
* <PRE>
|
||||
* |
|
||||
* | height is the full used height of the image
|
||||
* |
|
||||
* | ..XX.. }
|
||||
* | ..XX.. }
|
||||
* | ...... }
|
||||
* | XXXX.. } topExtent (top y is baseline - topExtent)
|
||||
* | ..XX.. }
|
||||
* | ..XX.. } dotted areas are where the image data
|
||||
* | ..XX.. } is actually located for the character
|
||||
* +---XXXXXX---- } (it extends to the right and down
|
||||
* | for power of two texture sizes)
|
||||
* ^^^^ leftExtent (amount to move over before drawing the image
|
||||
*
|
||||
* ^^^^^^^^^^^^^^ setWidth (width displaced by char)
|
||||
* </PRE>
|
||||
*/
|
||||
public class PFont implements PConstants {
|
||||
|
||||
public int charCount;
|
||||
public PImage images[];
|
||||
|
||||
/**
|
||||
* Native Java version of the font. If possible, this allows the
|
||||
* PGraphics subclass to just use Java's font rendering stuff
|
||||
* in situations where that's faster.
|
||||
*/
|
||||
protected Font font;
|
||||
protected boolean fontSearched;
|
||||
|
||||
/**
|
||||
* Name of the font as seen by Java when it was created.
|
||||
* If the font is available, the native version will be used.
|
||||
*/
|
||||
public String name;
|
||||
|
||||
/**
|
||||
* Postscript name of the font that this bitmap was created from.
|
||||
*/
|
||||
public String psname;
|
||||
|
||||
/** "natural" size of the font (most often 48) */
|
||||
public int size;
|
||||
|
||||
/** true if smoothing was enabled for this font, used for native impl */
|
||||
public boolean smooth;
|
||||
|
||||
/** next power of 2 over the max image size (usually 64) */
|
||||
public int mbox2;
|
||||
|
||||
/** floating point width (convenience) */
|
||||
protected float fwidth;
|
||||
|
||||
/** floating point width (convenience) */
|
||||
protected float fheight;
|
||||
|
||||
/** texture width, same as mbox2, but reserved for future use */
|
||||
public int twidth;
|
||||
|
||||
/** texture height, same as mbox2, but reserved for future use */
|
||||
public int theight;
|
||||
|
||||
public int value[]; // char code
|
||||
public int height[]; // height of the bitmap data
|
||||
public int width[]; // width of bitmap data
|
||||
public int setWidth[]; // width displaced by the char
|
||||
public int topExtent[]; // offset for the top
|
||||
public int leftExtent[]; // offset for the left
|
||||
|
||||
public int ascent;
|
||||
public int descent;
|
||||
|
||||
protected int ascii[]; // quick lookup for the ascii chars
|
||||
|
||||
// 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];
|
||||
|
||||
static protected Font[] fonts;
|
||||
|
||||
|
||||
public PFont() { } // for subclasses
|
||||
|
||||
|
||||
public PFont(InputStream input) throws IOException {
|
||||
DataInputStream is = new DataInputStream(input);
|
||||
|
||||
// number of character images stored in this font
|
||||
charCount = is.readInt();
|
||||
|
||||
// bit count is ignored since this is always 8
|
||||
//int numBits = is.readInt();
|
||||
// used to be the bitCount, but now used for version number.
|
||||
// version 8 is any font before 69, so 9 is anything from 83+
|
||||
// 9 was buggy so gonna increment to 10.
|
||||
int version = is.readInt();
|
||||
|
||||
// this was formerly ignored, now it's the actual font size
|
||||
//mbox = is.readInt();
|
||||
size = is.readInt();
|
||||
// this was formerly mboxY, the one that was used
|
||||
// this will make new fonts downward compatible
|
||||
//mbox2 = is.readInt();
|
||||
mbox2 = is.readInt();
|
||||
|
||||
fwidth = size; //mbox;
|
||||
fheight = size; //mbox;
|
||||
|
||||
// size for image ("texture") is next power of 2
|
||||
// over the font size. for most vlw fonts, the size is 48
|
||||
// so the next power of 2 is 64.
|
||||
// double-check to make sure that mbox2 is a power of 2
|
||||
// there was a bug in the old font generator that broke this
|
||||
//mbox2 = (int) Math.pow(2, Math.ceil(Math.log(mbox2) / Math.log(2)));
|
||||
mbox2 = (int) Math.pow(2, Math.ceil(Math.log(mbox2) / Math.log(2)));
|
||||
// size for the texture is stored in the font
|
||||
twidth = theight = mbox2; //mbox2;
|
||||
|
||||
ascent = is.readInt(); // formerly baseHt (zero/ignored)
|
||||
descent = is.readInt(); // formerly ignored struct padding
|
||||
|
||||
// allocate enough space for the character info
|
||||
value = new int[charCount];
|
||||
height = new int[charCount];
|
||||
width = new int[charCount];
|
||||
setWidth = new int[charCount];
|
||||
topExtent = new int[charCount];
|
||||
leftExtent = new int[charCount];
|
||||
|
||||
ascii = new int[128];
|
||||
for (int i = 0; i < 128; i++) ascii[i] = -1;
|
||||
|
||||
// read the information about the individual characters
|
||||
for (int i = 0; i < charCount; i++) {
|
||||
value[i] = is.readInt();
|
||||
height[i] = is.readInt();
|
||||
width[i] = is.readInt();
|
||||
setWidth[i] = is.readInt();
|
||||
topExtent[i] = is.readInt();
|
||||
leftExtent[i] = is.readInt();
|
||||
|
||||
// pointer in the c version, ignored
|
||||
is.readInt();
|
||||
|
||||
// cache locations of the ascii charset
|
||||
if (value[i] < 128) ascii[value[i]] = i;
|
||||
|
||||
// the values for getAscent() and getDescent() from FontMetrics
|
||||
// seem to be way too large.. perhaps they're the max?
|
||||
// as such, use a more traditional marker for ascent/descent
|
||||
if (value[i] == 'd') {
|
||||
if (ascent == 0) ascent = topExtent[i];
|
||||
}
|
||||
if (value[i] == 'p') {
|
||||
if (descent == 0) descent = -topExtent[i] + height[i];
|
||||
}
|
||||
}
|
||||
|
||||
// not a roman font, so throw an error and ask to re-build.
|
||||
// that way can avoid a bunch of error checking hacks in here.
|
||||
if ((ascent == 0) && (descent == 0)) {
|
||||
throw new RuntimeException("Please use \"Create Font\" to " +
|
||||
"re-create this font.");
|
||||
}
|
||||
|
||||
images = new PImage[charCount];
|
||||
for (int i = 0; i < charCount; i++) {
|
||||
images[i] = new PImage(twidth, theight, ALPHA);
|
||||
int bitmapSize = height[i] * width[i];
|
||||
|
||||
byte temp[] = new byte[bitmapSize];
|
||||
is.readFully(temp);
|
||||
|
||||
// convert the bitmap to an alpha channel
|
||||
int w = width[i];
|
||||
int h = height[i];
|
||||
for (int y = 0; y < h; y++) {
|
||||
for (int x = 0; x < w; x++) {
|
||||
int valu = temp[y*w + x] & 0xff;
|
||||
images[i].pixels[y * twidth + x] = valu;
|
||||
//(valu << 24) | 0xFFFFFF; // windows
|
||||
//0xFFFFFF00 | valu; // macosx
|
||||
|
||||
//System.out.print((images[i].pixels[y*64+x] > 128) ? "*" : ".");
|
||||
}
|
||||
//System.out.println();
|
||||
}
|
||||
//System.out.println();
|
||||
}
|
||||
|
||||
if (version >= 10) { // includes the font name at the end of the file
|
||||
name = is.readUTF();
|
||||
psname = is.readUTF();
|
||||
}
|
||||
if (version == 11) {
|
||||
smooth = is.readBoolean();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the native complement of this font.
|
||||
*/
|
||||
public void setFont(Font font) {
|
||||
this.font = font;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the native java.awt.Font associated with this PFont (if any).
|
||||
*/
|
||||
public Font getFont() {
|
||||
// if (font == null && !fontSearched) {
|
||||
// font = findFont();
|
||||
// }
|
||||
return font;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Attempt to find the native version of this font.
|
||||
* (Public so that it can be used by OpenGL or other renderers.)
|
||||
*/
|
||||
public Font findFont() {
|
||||
if (font == null) {
|
||||
if (!fontSearched) {
|
||||
// this font may or may not be installed
|
||||
font = new Font(name, Font.PLAIN, size);
|
||||
// if the ps name matches, then we're in fine shape
|
||||
if (!font.getPSName().equals(psname)) {
|
||||
// on osx java 1.4 (not 1.3.. ugh), you can specify the ps name
|
||||
// of the font, so try that in case this .vlw font was created on pc
|
||||
// and the name is different, but the ps name is found on the
|
||||
// java 1.4 mac that's currently running this sketch.
|
||||
font = new Font(psname, Font.PLAIN, size);
|
||||
}
|
||||
// check again, and if still bad, screw em
|
||||
if (!font.getPSName().equals(psname)) {
|
||||
font = null;
|
||||
}
|
||||
fontSearched = true;
|
||||
}
|
||||
}
|
||||
return font;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write this PFont to an OutputStream.
|
||||
* <p>
|
||||
* This is used by the Create Font tool, or whatever anyone else dreams
|
||||
* up for messing with fonts themselves.
|
||||
* <p>
|
||||
* It is assumed that the calling class will handle closing
|
||||
* the stream when finished.
|
||||
*/
|
||||
public void save(OutputStream output) throws IOException {
|
||||
DataOutputStream os = new DataOutputStream(output);
|
||||
|
||||
os.writeInt(charCount);
|
||||
|
||||
if ((name == null) || (psname == null)) {
|
||||
name = "";
|
||||
psname = "";
|
||||
}
|
||||
// formerly numBits, now used for version number
|
||||
//os.writeInt((name != null) ? 11 : 8);
|
||||
os.writeInt(11);
|
||||
|
||||
os.writeInt(size); // formerly mboxX (was 64, now 48)
|
||||
os.writeInt(mbox2); // formerly mboxY (was 64, still 64)
|
||||
os.writeInt(ascent); // formerly baseHt (was ignored)
|
||||
os.writeInt(descent); // formerly struct padding for c version
|
||||
|
||||
for (int i = 0; i < charCount; i++) {
|
||||
os.writeInt(value[i]);
|
||||
os.writeInt(height[i]);
|
||||
os.writeInt(width[i]);
|
||||
os.writeInt(setWidth[i]);
|
||||
os.writeInt(topExtent[i]);
|
||||
os.writeInt(leftExtent[i]);
|
||||
os.writeInt(0); // padding
|
||||
}
|
||||
|
||||
for (int i = 0; i < charCount; i++) {
|
||||
for (int y = 0; y < height[i]; y++) {
|
||||
for (int x = 0; x < width[i]; x++) {
|
||||
os.write(images[i].pixels[y * mbox2 + x] & 0xff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//if (name != null) { // version 11
|
||||
os.writeUTF(name);
|
||||
os.writeUTF(psname);
|
||||
os.writeBoolean(smooth);
|
||||
//}
|
||||
|
||||
os.flush();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get index for the char (convert from unicode to bagel charset).
|
||||
* @return index into arrays or -1 if not found
|
||||
*/
|
||||
public int index(char c) {
|
||||
// degenerate case, but the find function will have trouble
|
||||
// if there are somehow zero chars in the lookup
|
||||
//if (value.length == 0) return -1;
|
||||
if (charCount == 0) return -1;
|
||||
|
||||
// quicker lookup for the ascii fellers
|
||||
if (c < 128) return ascii[c];
|
||||
|
||||
// some other unicode char, hunt it out
|
||||
//return index_hunt(c, 0, value.length-1);
|
||||
return indexHunt(c, 0, charCount-1);
|
||||
}
|
||||
|
||||
|
||||
protected int indexHunt(int c, int start, int stop) {
|
||||
int pivot = (start + stop) / 2;
|
||||
|
||||
// if this is the char, then return it
|
||||
if (c == value[pivot]) return pivot;
|
||||
|
||||
// char doesn't exist, otherwise would have been the pivot
|
||||
//if (start == stop) return -1;
|
||||
if (start >= stop) return -1;
|
||||
|
||||
// if it's in the lower half, continue searching that
|
||||
if (c < value[pivot]) return indexHunt(c, start, pivot-1);
|
||||
|
||||
// if it's in the upper half, continue there
|
||||
return indexHunt(c, pivot+1, stop);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Currently un-implemented for .vlw fonts,
|
||||
* but honored for layout in case subclasses use it.
|
||||
*/
|
||||
public float kern(char a, char b) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
static final char[] EXTRA_CHARS = {
|
||||
0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
|
||||
0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
|
||||
0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
|
||||
0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
|
||||
0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
|
||||
0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
|
||||
0x00B0, 0x00B1, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00BA,
|
||||
0x00BB, 0x00BF, 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5,
|
||||
0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD,
|
||||
0x00CE, 0x00CF, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6,
|
||||
0x00D7, 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DF,
|
||||
0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
|
||||
0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
|
||||
0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8,
|
||||
0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FF, 0x0102, 0x0103,
|
||||
0x0104, 0x0105, 0x0106, 0x0107, 0x010C, 0x010D, 0x010E, 0x010F,
|
||||
0x0110, 0x0111, 0x0118, 0x0119, 0x011A, 0x011B, 0x0131, 0x0139,
|
||||
0x013A, 0x013D, 0x013E, 0x0141, 0x0142, 0x0143, 0x0144, 0x0147,
|
||||
0x0148, 0x0150, 0x0151, 0x0152, 0x0153, 0x0154, 0x0155, 0x0158,
|
||||
0x0159, 0x015A, 0x015B, 0x015E, 0x015F, 0x0160, 0x0161, 0x0162,
|
||||
0x0163, 0x0164, 0x0165, 0x016E, 0x016F, 0x0170, 0x0171, 0x0178,
|
||||
0x0179, 0x017A, 0x017B, 0x017C, 0x017D, 0x017E, 0x0192, 0x02C6,
|
||||
0x02C7, 0x02D8, 0x02D9, 0x02DA, 0x02DB, 0x02DC, 0x02DD, 0x03A9,
|
||||
0x03C0, 0x2013, 0x2014, 0x2018, 0x2019, 0x201A, 0x201C, 0x201D,
|
||||
0x201E, 0x2020, 0x2021, 0x2022, 0x2026, 0x2030, 0x2039, 0x203A,
|
||||
0x2044, 0x20AC, 0x2122, 0x2202, 0x2206, 0x220F, 0x2211, 0x221A,
|
||||
0x221E, 0x222B, 0x2248, 0x2260, 0x2264, 0x2265, 0x25CA, 0xF8FF,
|
||||
0xFB01, 0xFB02
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The default Processing character set.
|
||||
* <P>
|
||||
* This is the union of the Mac Roman and Windows ANSI (CP1250)
|
||||
* character sets. ISO 8859-1 Latin 1 is Unicode characters 0x80 -> 0xFF,
|
||||
* and would seem a good standard, but in practice, most P5 users would
|
||||
* rather have characters that they expect from their platform's fonts.
|
||||
* <P>
|
||||
* This is more of an interim solution until a much better
|
||||
* font solution can be determined. (i.e. create fonts on
|
||||
* the fly from some sort of vector format).
|
||||
* <P>
|
||||
* Not that I expect that to happen.
|
||||
*/
|
||||
static public char[] DEFAULT_CHARSET;
|
||||
static {
|
||||
DEFAULT_CHARSET = new char[126-33+1 + EXTRA_CHARS.length];
|
||||
int index = 0;
|
||||
for (int i = 33; i <= 126; i++) {
|
||||
DEFAULT_CHARSET[index++] = (char)i;
|
||||
}
|
||||
for (int i = 0; i < EXTRA_CHARS.length; i++) {
|
||||
DEFAULT_CHARSET[index++] = EXTRA_CHARS[i];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a new image-based font on the fly.
|
||||
*
|
||||
* @param font the font object to create from
|
||||
* @param charset array of all unicode chars that should be included
|
||||
* @param smooth true to enable smoothing/anti-aliasing
|
||||
*/
|
||||
public PFont(Font font, boolean smooth, char charset[]) {
|
||||
// save this so that we can use the native version
|
||||
this.font = font;
|
||||
this.smooth = smooth;
|
||||
|
||||
name = font.getName();
|
||||
psname = font.getPSName();
|
||||
|
||||
// fix regression from sorting (bug #564)
|
||||
if (charset != null) {
|
||||
// charset needs to be sorted to make index lookup run more quickly
|
||||
// http://dev.processing.org/bugs/show_bug.cgi?id=494
|
||||
Arrays.sort(charset);
|
||||
}
|
||||
|
||||
// the count gets reset later based on how many of
|
||||
// the chars are actually found inside the font.
|
||||
this.charCount = (charset == null) ? 65536 : charset.length;
|
||||
this.size = font.getSize();
|
||||
|
||||
fwidth = fheight = size;
|
||||
|
||||
PImage bitmaps[] = new PImage[charCount];
|
||||
|
||||
// allocate enough space for the character info
|
||||
value = new int[charCount];
|
||||
height = new int[charCount];
|
||||
width = new int[charCount];
|
||||
setWidth = new int[charCount];
|
||||
topExtent = new int[charCount];
|
||||
leftExtent = new int[charCount];
|
||||
|
||||
ascii = new int[128];
|
||||
for (int i = 0; i < 128; i++) ascii[i] = -1;
|
||||
|
||||
int mbox3 = size * 3;
|
||||
|
||||
BufferedImage playground =
|
||||
new BufferedImage(mbox3, mbox3, BufferedImage.TYPE_INT_RGB);
|
||||
|
||||
Graphics2D g = (Graphics2D) playground.getGraphics();
|
||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
|
||||
smooth ?
|
||||
RenderingHints.VALUE_ANTIALIAS_ON :
|
||||
RenderingHints.VALUE_ANTIALIAS_OFF);
|
||||
|
||||
g.setFont(font);
|
||||
FontMetrics metrics = g.getFontMetrics();
|
||||
|
||||
int samples[] = new int[mbox3 * mbox3];
|
||||
|
||||
int maxWidthHeight = 0;
|
||||
int index = 0;
|
||||
for (int i = 0; i < charCount; i++) {
|
||||
char c = (charset == null) ? (char)i : charset[i];
|
||||
|
||||
if (!font.canDisplay(c)) { // skip chars not in the font
|
||||
continue;
|
||||
}
|
||||
|
||||
g.setColor(Color.white);
|
||||
g.fillRect(0, 0, mbox3, mbox3);
|
||||
g.setColor(Color.black);
|
||||
g.drawString(String.valueOf(c), size, size * 2);
|
||||
|
||||
// grabs copy of the current data.. so no updates (do each time)
|
||||
Raster raster = playground.getData();
|
||||
raster.getSamples(0, 0, mbox3, mbox3, 0, samples);
|
||||
|
||||
int minX = 1000, maxX = 0;
|
||||
int minY = 1000, maxY = 0;
|
||||
boolean pixelFound = false;
|
||||
|
||||
for (int y = 0; y < mbox3; y++) {
|
||||
for (int x = 0; x < mbox3; x++) {
|
||||
//int sample = raster.getSample(x, y, 0); // maybe?
|
||||
int sample = samples[y * mbox3 + x] & 0xff;
|
||||
// or int samples[] = raster.getPixel(x, y, null);
|
||||
|
||||
//if (sample == 0) { // or just not white? hmm
|
||||
if (sample != 255) {
|
||||
if (x < minX) minX = x;
|
||||
if (y < minY) minY = y;
|
||||
if (x > maxX) maxX = x;
|
||||
if (y > maxY) maxY = y;
|
||||
pixelFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!pixelFound) {
|
||||
minX = minY = 0;
|
||||
maxX = maxY = 0;
|
||||
// this will create a 1 pixel white (clear) character..
|
||||
// maybe better to set one to -1 so nothing is added?
|
||||
}
|
||||
|
||||
value[index] = c;
|
||||
height[index] = (maxY - minY) + 1;
|
||||
width[index] = (maxX - minX) + 1;
|
||||
setWidth[index] = metrics.charWidth(c);
|
||||
//System.out.println((char)c + " " + setWidth[index]);
|
||||
|
||||
// cache locations of the ascii charset
|
||||
//if (value[i] < 128) ascii[value[i]] = i;
|
||||
if (c < 128) ascii[c] = index;
|
||||
|
||||
// offset from vertical location of baseline
|
||||
// of where the char was drawn (size*2)
|
||||
topExtent[index] = size*2 - minY;
|
||||
|
||||
// offset from left of where coord was drawn
|
||||
leftExtent[index] = minX - size;
|
||||
|
||||
if (c == 'd') {
|
||||
ascent = topExtent[index];
|
||||
}
|
||||
if (c == 'p') {
|
||||
descent = -topExtent[index] + height[index];
|
||||
}
|
||||
|
||||
if (width[index] > maxWidthHeight) maxWidthHeight = width[index];
|
||||
if (height[index] > maxWidthHeight) maxWidthHeight = height[index];
|
||||
|
||||
bitmaps[index] = new PImage(width[index], height[index], ALPHA);
|
||||
|
||||
for (int y = minY; y <= maxY; y++) {
|
||||
for (int x = minX; x <= maxX; x++) {
|
||||
int val = 255 - (samples[y * mbox3 + x] & 0xff);
|
||||
int pindex = (y - minY) * width[index] + (x - minX);
|
||||
bitmaps[index].pixels[pindex] = val;
|
||||
}
|
||||
}
|
||||
index++;
|
||||
}
|
||||
charCount = index;
|
||||
|
||||
// foreign font, so just make ascent the max topExtent
|
||||
if ((ascent == 0) && (descent == 0)) {
|
||||
for (int i = 0; i < charCount; i++) {
|
||||
char cc = (char) value[i];
|
||||
if (Character.isWhitespace(cc) ||
|
||||
(cc == '\u00A0') || (cc == '\u2007') || (cc == '\u202F')) {
|
||||
continue;
|
||||
}
|
||||
if (topExtent[i] > ascent) {
|
||||
ascent = topExtent[i];
|
||||
}
|
||||
int d = -topExtent[i] + height[i];
|
||||
if (d > descent) {
|
||||
descent = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
// size for image/texture is next power of 2 over largest char
|
||||
mbox2 = (int)
|
||||
Math.pow(2, Math.ceil(Math.log(maxWidthHeight) / Math.log(2)));
|
||||
twidth = theight = mbox2;
|
||||
|
||||
// shove the smaller PImage data into textures of next-power-of-2 size,
|
||||
// so that this font can be used immediately by p5.
|
||||
images = new PImage[charCount];
|
||||
for (int i = 0; i < charCount; i++) {
|
||||
images[i] = new PImage(mbox2, mbox2, ALPHA);
|
||||
for (int y = 0; y < height[i]; y++) {
|
||||
System.arraycopy(bitmaps[i].pixels, y*width[i],
|
||||
images[i].pixels, y*mbox2,
|
||||
width[i]);
|
||||
}
|
||||
bitmaps[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a list of the fonts installed on the system that can be used
|
||||
* by Java. Not all fonts can be used in Java, in fact it's mostly
|
||||
* only TrueType fonts. OpenType fonts with CFF data such as Adobe's
|
||||
* OpenType fonts seem to have trouble (even though they're sort of
|
||||
* TrueType fonts as well, or may have a .ttf extension). Regular
|
||||
* PostScript fonts seem to work OK, however.
|
||||
* <P>
|
||||
* Not recommended for use in applets, but this is implemented
|
||||
* in PFont because the Java methods to access this information
|
||||
* have changed between 1.1 and 1.4, and the 1.4 method is
|
||||
* typical of the sort of undergraduate-level over-abstraction
|
||||
* that the seems to have made its way into the Java API after 1.1.
|
||||
*/
|
||||
static public String[] list() {
|
||||
loadFonts();
|
||||
String list[] = new String[fonts.length];
|
||||
for (int i = 0; i < list.length; i++) {
|
||||
list[i] = fonts[i].getName();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
static public void loadFonts() {
|
||||
if (fonts == null) {
|
||||
GraphicsEnvironment ge =
|
||||
GraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||
fonts = ge.getAllFonts();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Starting with Java 1.5, Apple broke the ability to specify most fonts.
|
||||
* This has been filed as bug #4769141 at bugreporter.apple.com. More info at
|
||||
* <a href="http://dev.processing.org/bugs/show_bug.cgi?id=407">Bug 407</a>.
|
||||
*/
|
||||
static public Font findFont(String name) {
|
||||
loadFonts();
|
||||
if (PApplet.platform == PConstants.MACOSX) {
|
||||
for (int i = 0; i < fonts.length; i++) {
|
||||
if (name.equals(fonts[i].getName())) {
|
||||
return fonts[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return new Font(name, Font.PLAIN, 1);
|
||||
}
|
||||
}
|
5043
core/src/processing/core/PGraphics.java
Normal file
5043
core/src/processing/core/PGraphics.java
Normal file
File diff suppressed because it is too large
Load Diff
2149
core/src/processing/core/PGraphics2D.java
Normal file
2149
core/src/processing/core/PGraphics2D.java
Normal file
File diff suppressed because it is too large
Load Diff
4340
core/src/processing/core/PGraphics3D.java
Normal file
4340
core/src/processing/core/PGraphics3D.java
Normal file
File diff suppressed because it is too large
Load Diff
1836
core/src/processing/core/PGraphicsJava2D.java
Normal file
1836
core/src/processing/core/PGraphicsJava2D.java
Normal file
File diff suppressed because it is too large
Load Diff
2709
core/src/processing/core/PImage.java
Normal file
2709
core/src/processing/core/PImage.java
Normal file
File diff suppressed because it is too large
Load Diff
1278
core/src/processing/core/PLine.java
Normal file
1278
core/src/processing/core/PLine.java
Normal file
File diff suppressed because it is too large
Load Diff
150
core/src/processing/core/PMatrix.java
Normal file
150
core/src/processing/core/PMatrix.java
Normal file
@ -0,0 +1,150 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2005-08 Ben Fry and Casey Reas
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.core;
|
||||
|
||||
|
||||
public interface PMatrix {
|
||||
|
||||
public void reset();
|
||||
|
||||
/**
|
||||
* Returns a copy of this PMatrix.
|
||||
*/
|
||||
public PMatrix get();
|
||||
|
||||
/**
|
||||
* Copies the matrix contents into a float array.
|
||||
* If target is null (or not the correct size), a new array will be created.
|
||||
*/
|
||||
public float[] get(float[] target);
|
||||
|
||||
|
||||
public void set(PMatrix src);
|
||||
|
||||
public void set(float[] source);
|
||||
|
||||
public void set(float m00, float m01, float m02,
|
||||
float m10, float m11, float m12);
|
||||
|
||||
public void set(float m00, float m01, float m02, float m03,
|
||||
float m10, float m11, float m12, float m13,
|
||||
float m20, float m21, float m22, float m23,
|
||||
float m30, float m31, float m32, float m33);
|
||||
|
||||
|
||||
public void translate(float tx, float ty);
|
||||
|
||||
public void translate(float tx, float ty, float tz);
|
||||
|
||||
public void rotate(float angle);
|
||||
|
||||
public void rotateX(float angle);
|
||||
|
||||
public void rotateY(float angle);
|
||||
|
||||
public void rotateZ(float angle);
|
||||
|
||||
public void rotate(float angle, float v0, float v1, float v2);
|
||||
|
||||
public void scale(float s);
|
||||
|
||||
public void scale(float sx, float sy);
|
||||
|
||||
public void scale(float x, float y, float z);
|
||||
|
||||
public void skewX(float angle);
|
||||
|
||||
public void skewY(float angle);
|
||||
|
||||
/**
|
||||
* Multiply this matrix by another.
|
||||
*/
|
||||
public void apply(PMatrix source);
|
||||
|
||||
public void apply(PMatrix2D source);
|
||||
|
||||
public void apply(PMatrix3D source);
|
||||
|
||||
public void apply(float n00, float n01, float n02,
|
||||
float n10, float n11, float n12);
|
||||
|
||||
public void apply(float n00, float n01, float n02, float n03,
|
||||
float n10, float n11, float n12, float n13,
|
||||
float n20, float n21, float n22, float n23,
|
||||
float n30, float n31, float n32, float n33);
|
||||
|
||||
/**
|
||||
* Apply another matrix to the left of this one.
|
||||
*/
|
||||
public void preApply(PMatrix2D left);
|
||||
|
||||
public void preApply(PMatrix3D left);
|
||||
|
||||
public void preApply(float n00, float n01, float n02,
|
||||
float n10, float n11, float n12);
|
||||
|
||||
public void preApply(float n00, float n01, float n02, float n03,
|
||||
float n10, float n11, float n12, float n13,
|
||||
float n20, float n21, float n22, float n23,
|
||||
float n30, float n31, float n32, float n33);
|
||||
|
||||
|
||||
/**
|
||||
* Multiply a PVector by this matrix.
|
||||
*/
|
||||
public PVector mult(PVector source, PVector target);
|
||||
|
||||
|
||||
/**
|
||||
* Multiply a multi-element vector against this matrix.
|
||||
*/
|
||||
public float[] mult(float[] source, float[] target);
|
||||
|
||||
|
||||
// public float multX(float x, float y);
|
||||
// public float multY(float x, float y);
|
||||
|
||||
// public float multX(float x, float y, float z);
|
||||
// public float multY(float x, float y, float z);
|
||||
// public float multZ(float x, float y, float z);
|
||||
|
||||
|
||||
/**
|
||||
* Transpose this matrix.
|
||||
*/
|
||||
public void transpose();
|
||||
|
||||
|
||||
/**
|
||||
* Invert this matrix.
|
||||
* @return true if successful
|
||||
*/
|
||||
public boolean invert();
|
||||
|
||||
|
||||
/**
|
||||
* @return the determinant of the matrix
|
||||
*/
|
||||
public float determinant();
|
||||
}
|
450
core/src/processing/core/PMatrix2D.java
Normal file
450
core/src/processing/core/PMatrix2D.java
Normal file
@ -0,0 +1,450 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2005-08 Ben Fry and Casey Reas
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.core;
|
||||
|
||||
|
||||
/**
|
||||
* 3x2 affine matrix implementation.
|
||||
*/
|
||||
public class PMatrix2D implements PMatrix {
|
||||
|
||||
public float m00, m01, m02;
|
||||
public float m10, m11, m12;
|
||||
|
||||
|
||||
public PMatrix2D() {
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
public PMatrix2D(float m00, float m01, float m02,
|
||||
float m10, float m11, float m12) {
|
||||
set(m00, m01, m02,
|
||||
m10, m11, m12);
|
||||
}
|
||||
|
||||
|
||||
public PMatrix2D(PMatrix matrix) {
|
||||
set(matrix);
|
||||
}
|
||||
|
||||
|
||||
public void reset() {
|
||||
set(1, 0, 0,
|
||||
0, 1, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a copy of this PMatrix.
|
||||
*/
|
||||
public PMatrix2D get() {
|
||||
PMatrix2D outgoing = new PMatrix2D();
|
||||
outgoing.set(this);
|
||||
return outgoing;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Copies the matrix contents into a 6 entry float array.
|
||||
* If target is null (or not the correct size), a new array will be created.
|
||||
*/
|
||||
public float[] get(float[] target) {
|
||||
if ((target == null) || (target.length != 6)) {
|
||||
target = new float[6];
|
||||
}
|
||||
target[0] = m00;
|
||||
target[1] = m01;
|
||||
target[2] = m02;
|
||||
|
||||
target[3] = m10;
|
||||
target[4] = m11;
|
||||
target[5] = m12;
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
public void set(PMatrix matrix) {
|
||||
if (matrix instanceof PMatrix2D) {
|
||||
PMatrix2D src = (PMatrix2D) matrix;
|
||||
set(src.m00, src.m01, src.m02,
|
||||
src.m10, src.m11, src.m12);
|
||||
} else {
|
||||
throw new IllegalArgumentException("PMatrix2D.set() only accepts PMatrix2D objects.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void set(PMatrix3D src) {
|
||||
}
|
||||
|
||||
|
||||
public void set(float[] source) {
|
||||
m00 = source[0];
|
||||
m01 = source[1];
|
||||
m02 = source[2];
|
||||
|
||||
m10 = source[3];
|
||||
m11 = source[4];
|
||||
m12 = source[5];
|
||||
}
|
||||
|
||||
|
||||
public void set(float m00, float m01, float m02,
|
||||
float m10, float m11, float m12) {
|
||||
this.m00 = m00; this.m01 = m01; this.m02 = m02;
|
||||
this.m10 = m10; this.m11 = m11; this.m12 = m12;
|
||||
}
|
||||
|
||||
|
||||
public void set(float m00, float m01, float m02, float m03,
|
||||
float m10, float m11, float m12, float m13,
|
||||
float m20, float m21, float m22, float m23,
|
||||
float m30, float m31, float m32, float m33) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void translate(float tx, float ty) {
|
||||
m02 = tx*m00 + ty*m01 + m02;
|
||||
m12 = tx*m10 + ty*m11 + m12;
|
||||
}
|
||||
|
||||
|
||||
public void translate(float x, float y, float z) {
|
||||
throw new IllegalArgumentException("Cannot use translate(x, y, z) on a PMatrix2D.");
|
||||
}
|
||||
|
||||
|
||||
// Implementation roughly based on AffineTransform.
|
||||
public void rotate(float angle) {
|
||||
float s = sin(angle);
|
||||
float c = cos(angle);
|
||||
|
||||
float temp1 = m00;
|
||||
float temp2 = m01;
|
||||
m00 = c * temp1 + s * temp2;
|
||||
m01 = -s * temp1 + c * temp2;
|
||||
temp1 = m10;
|
||||
temp2 = m11;
|
||||
m10 = c * temp1 + s * temp2;
|
||||
m11 = -s * temp1 + c * temp2;
|
||||
}
|
||||
|
||||
|
||||
public void rotateX(float angle) {
|
||||
throw new IllegalArgumentException("Cannot use rotateX() on a PMatrix2D.");
|
||||
}
|
||||
|
||||
|
||||
public void rotateY(float angle) {
|
||||
throw new IllegalArgumentException("Cannot use rotateY() on a PMatrix2D.");
|
||||
}
|
||||
|
||||
|
||||
public void rotateZ(float angle) {
|
||||
rotate(angle);
|
||||
}
|
||||
|
||||
|
||||
public void rotate(float angle, float v0, float v1, float v2) {
|
||||
throw new IllegalArgumentException("Cannot use this version of rotate() on a PMatrix2D.");
|
||||
}
|
||||
|
||||
|
||||
public void scale(float s) {
|
||||
scale(s, s);
|
||||
}
|
||||
|
||||
|
||||
public void scale(float sx, float sy) {
|
||||
m00 *= sx; m01 *= sy;
|
||||
m10 *= sx; m11 *= sy;
|
||||
}
|
||||
|
||||
|
||||
public void scale(float x, float y, float z) {
|
||||
throw new IllegalArgumentException("Cannot use this version of scale() on a PMatrix2D.");
|
||||
}
|
||||
|
||||
|
||||
public void skewX(float angle) {
|
||||
apply(1, 0, 1, angle, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
public void skewY(float angle) {
|
||||
apply(1, 0, 1, 0, angle, 0);
|
||||
}
|
||||
|
||||
|
||||
public void apply(PMatrix source) {
|
||||
if (source instanceof PMatrix2D) {
|
||||
apply((PMatrix2D) source);
|
||||
} else if (source instanceof PMatrix3D) {
|
||||
apply((PMatrix3D) source);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void apply(PMatrix2D source) {
|
||||
apply(source.m00, source.m01, source.m02,
|
||||
source.m10, source.m11, source.m12);
|
||||
}
|
||||
|
||||
|
||||
public void apply(PMatrix3D source) {
|
||||
throw new IllegalArgumentException("Cannot use apply(PMatrix3D) on a PMatrix2D.");
|
||||
}
|
||||
|
||||
|
||||
public void apply(float n00, float n01, float n02,
|
||||
float n10, float n11, float n12) {
|
||||
float t0 = m00;
|
||||
float t1 = m01;
|
||||
m00 = n00 * t0 + n10 * t1;
|
||||
m01 = n01 * t0 + n11 * t1;
|
||||
m02 += n02 * t0 + n12 * t1;
|
||||
|
||||
t0 = m10;
|
||||
t1 = m11;
|
||||
m10 = n00 * t0 + n10 * t1;
|
||||
m11 = n01 * t0 + n11 * t1;
|
||||
m12 += n02 * t0 + n12 * t1;
|
||||
}
|
||||
|
||||
|
||||
public void apply(float n00, float n01, float n02, float n03,
|
||||
float n10, float n11, float n12, float n13,
|
||||
float n20, float n21, float n22, float n23,
|
||||
float n30, float n31, float n32, float n33) {
|
||||
throw new IllegalArgumentException("Cannot use this version of apply() on a PMatrix2D.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Apply another matrix to the left of this one.
|
||||
*/
|
||||
public void preApply(PMatrix2D left) {
|
||||
preApply(left.m00, left.m01, left.m02,
|
||||
left.m10, left.m11, left.m12);
|
||||
}
|
||||
|
||||
|
||||
public void preApply(PMatrix3D left) {
|
||||
throw new IllegalArgumentException("Cannot use preApply(PMatrix3D) on a PMatrix2D.");
|
||||
}
|
||||
|
||||
|
||||
public void preApply(float n00, float n01, float n02,
|
||||
float n10, float n11, float n12) {
|
||||
float t0 = m02;
|
||||
float t1 = m12;
|
||||
n02 += t0 * n00 + t1 * n01;
|
||||
n12 += t0 * n10 + t1 * n11;
|
||||
|
||||
m02 = n02;
|
||||
m12 = n12;
|
||||
|
||||
t0 = m00;
|
||||
t1 = m10;
|
||||
m00 = t0 * n00 + t1 * n01;
|
||||
m10 = t0 * n10 + t1 * n11;
|
||||
|
||||
t0 = m01;
|
||||
t1 = m11;
|
||||
m01 = t0 * n00 + t1 * n01;
|
||||
m11 = t0 * n10 + t1 * n11;
|
||||
}
|
||||
|
||||
|
||||
public void preApply(float n00, float n01, float n02, float n03,
|
||||
float n10, float n11, float n12, float n13,
|
||||
float n20, float n21, float n22, float n23,
|
||||
float n30, float n31, float n32, float n33) {
|
||||
throw new IllegalArgumentException("Cannot use this version of preApply() on a PMatrix2D.");
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Multiply the x and y coordinates of a PVector against this matrix.
|
||||
*/
|
||||
public PVector mult(PVector source, PVector target) {
|
||||
if (target == null) {
|
||||
target = new PVector();
|
||||
}
|
||||
target.x = m00*source.x + m01*source.y + m02;
|
||||
target.y = m10*source.x + m11*source.y + m12;
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Multiply a two element vector against this matrix.
|
||||
* If out is null or not length four, a new float array will be returned.
|
||||
* The values for vec and out can be the same (though that's less efficient).
|
||||
*/
|
||||
public float[] mult(float vec[], float out[]) {
|
||||
if (out == null || out.length != 2) {
|
||||
out = new float[2];
|
||||
}
|
||||
|
||||
if (vec == out) {
|
||||
float tx = m00*vec[0] + m01*vec[1] + m02;
|
||||
float ty = m10*vec[0] + m11*vec[1] + m12;
|
||||
|
||||
out[0] = tx;
|
||||
out[1] = ty;
|
||||
|
||||
} else {
|
||||
out[0] = m00*vec[0] + m01*vec[1] + m02;
|
||||
out[1] = m10*vec[0] + m11*vec[1] + m12;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
public float multX(float x, float y) {
|
||||
return m00*x + m01*y + m02;
|
||||
}
|
||||
|
||||
|
||||
public float multY(float x, float y) {
|
||||
return m10*x + m11*y + m12;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Transpose this matrix.
|
||||
*/
|
||||
public void transpose() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Invert this matrix. Implementation stolen from OpenJDK.
|
||||
* @return true if successful
|
||||
*/
|
||||
public boolean invert() {
|
||||
float determinant = determinant();
|
||||
if (Math.abs(determinant) <= Float.MIN_VALUE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
float t00 = m00;
|
||||
float t01 = m01;
|
||||
float t02 = m02;
|
||||
float t10 = m10;
|
||||
float t11 = m11;
|
||||
float t12 = m12;
|
||||
|
||||
m00 = t11 / determinant;
|
||||
m10 = -t10 / determinant;
|
||||
m01 = -t01 / determinant;
|
||||
m11 = t00 / determinant;
|
||||
m02 = (t01 * t12 - t11 * t02) / determinant;
|
||||
m12 = (t10 * t02 - t00 * t12) / determinant;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the determinant of the matrix
|
||||
*/
|
||||
public float determinant() {
|
||||
return m00 * m11 - m01 * m10;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
public void print() {
|
||||
int big = (int) abs(max(PApplet.max(abs(m00), abs(m01), abs(m02)),
|
||||
PApplet.max(abs(m10), abs(m11), abs(m12))));
|
||||
|
||||
int digits = 1;
|
||||
if (Float.isNaN(big) || Float.isInfinite(big)) { // avoid infinite loop
|
||||
digits = 5;
|
||||
} else {
|
||||
while ((big /= 10) != 0) digits++; // cheap log()
|
||||
}
|
||||
|
||||
System.out.println(PApplet.nfs(m00, digits, 4) + " " +
|
||||
PApplet.nfs(m01, digits, 4) + " " +
|
||||
PApplet.nfs(m02, digits, 4));
|
||||
|
||||
System.out.println(PApplet.nfs(m10, digits, 4) + " " +
|
||||
PApplet.nfs(m11, digits, 4) + " " +
|
||||
PApplet.nfs(m12, digits, 4));
|
||||
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
// TODO these need to be added as regular API, but the naming and
|
||||
// implementation needs to be improved first. (e.g. actually keeping track
|
||||
// of whether the matrix is in fact identity internally.)
|
||||
|
||||
|
||||
protected boolean isIdentity() {
|
||||
return ((m00 == 1) && (m01 == 0) && (m02 == 0) &&
|
||||
(m10 == 0) && (m11 == 1) && (m12 == 0));
|
||||
}
|
||||
|
||||
|
||||
// TODO make this more efficient, or move into PMatrix2D
|
||||
protected boolean isWarped() {
|
||||
return ((m00 != 1) || (m01 != 0) &&
|
||||
(m10 != 0) || (m11 != 1));
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
private final float max(float a, float b) {
|
||||
return (a > b) ? a : b;
|
||||
}
|
||||
|
||||
private final float abs(float a) {
|
||||
return (a < 0) ? -a : a;
|
||||
}
|
||||
|
||||
private final float sin(float angle) {
|
||||
return (float)Math.sin(angle);
|
||||
}
|
||||
|
||||
private final float cos(float angle) {
|
||||
return (float)Math.cos(angle);
|
||||
}
|
||||
}
|
782
core/src/processing/core/PMatrix3D.java
Normal file
782
core/src/processing/core/PMatrix3D.java
Normal file
@ -0,0 +1,782 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2005-08 Ben Fry and Casey Reas
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.core;
|
||||
|
||||
|
||||
/**
|
||||
* 4x4 matrix implementation.
|
||||
*/
|
||||
public final class PMatrix3D implements PMatrix /*, PConstants*/ {
|
||||
|
||||
public float m00, m01, m02, m03;
|
||||
public float m10, m11, m12, m13;
|
||||
public float m20, m21, m22, m23;
|
||||
public float m30, m31, m32, m33;
|
||||
|
||||
|
||||
// locally allocated version to avoid creating new memory
|
||||
protected PMatrix3D inverseCopy;
|
||||
|
||||
|
||||
public PMatrix3D() {
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
public PMatrix3D(float m00, float m01, float m02,
|
||||
float m10, float m11, float m12) {
|
||||
set(m00, m01, m02, 0,
|
||||
m10, m11, m12, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
public PMatrix3D(float m00, float m01, float m02, float m03,
|
||||
float m10, float m11, float m12, float m13,
|
||||
float m20, float m21, float m22, float m23,
|
||||
float m30, float m31, float m32, float m33) {
|
||||
set(m00, m01, m02, m03,
|
||||
m10, m11, m12, m13,
|
||||
m20, m21, m22, m23,
|
||||
m30, m31, m32, m33);
|
||||
}
|
||||
|
||||
|
||||
public PMatrix3D(PMatrix matrix) {
|
||||
set(matrix);
|
||||
}
|
||||
|
||||
|
||||
public void reset() {
|
||||
set(1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a copy of this PMatrix.
|
||||
*/
|
||||
public PMatrix3D get() {
|
||||
PMatrix3D outgoing = new PMatrix3D();
|
||||
outgoing.set(this);
|
||||
return outgoing;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Copies the matrix contents into a 16 entry float array.
|
||||
* If target is null (or not the correct size), a new array will be created.
|
||||
*/
|
||||
public float[] get(float[] target) {
|
||||
if ((target == null) || (target.length != 16)) {
|
||||
target = new float[16];
|
||||
}
|
||||
target[0] = m00;
|
||||
target[1] = m01;
|
||||
target[2] = m02;
|
||||
target[3] = m03;
|
||||
|
||||
target[4] = m10;
|
||||
target[5] = m11;
|
||||
target[6] = m12;
|
||||
target[7] = m13;
|
||||
|
||||
target[8] = m20;
|
||||
target[9] = m21;
|
||||
target[10] = m22;
|
||||
target[11] = m23;
|
||||
|
||||
target[12] = m30;
|
||||
target[13] = m31;
|
||||
target[14] = m32;
|
||||
target[15] = m33;
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
public void set(PMatrix matrix) {
|
||||
if (matrix instanceof PMatrix3D) {
|
||||
PMatrix3D src = (PMatrix3D) matrix;
|
||||
set(src.m00, src.m01, src.m02, src.m03,
|
||||
src.m10, src.m11, src.m12, src.m13,
|
||||
src.m20, src.m21, src.m22, src.m23,
|
||||
src.m30, src.m31, src.m32, src.m33);
|
||||
} else {
|
||||
PMatrix2D src = (PMatrix2D) matrix;
|
||||
set(src.m00, src.m01, 0, src.m02,
|
||||
src.m10, src.m11, 0, src.m12,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void set(float[] source) {
|
||||
if (source.length == 6) {
|
||||
set(source[0], source[1], source[2],
|
||||
source[3], source[4], source[5]);
|
||||
|
||||
} else if (source.length == 16) {
|
||||
m00 = source[0];
|
||||
m01 = source[1];
|
||||
m02 = source[2];
|
||||
m03 = source[3];
|
||||
|
||||
m10 = source[4];
|
||||
m11 = source[5];
|
||||
m12 = source[6];
|
||||
m13 = source[7];
|
||||
|
||||
m20 = source[8];
|
||||
m21 = source[9];
|
||||
m22 = source[10];
|
||||
m23 = source[11];
|
||||
|
||||
m30 = source[12];
|
||||
m31 = source[13];
|
||||
m32 = source[14];
|
||||
m33 = source[15];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void set(float m00, float m01, float m02,
|
||||
float m10, float m11, float m12) {
|
||||
set(m00, m01, 0, m02,
|
||||
m10, m11, 0, m12,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
public void set(float m00, float m01, float m02, float m03,
|
||||
float m10, float m11, float m12, float m13,
|
||||
float m20, float m21, float m22, float m23,
|
||||
float m30, float m31, float m32, float m33) {
|
||||
this.m00 = m00; this.m01 = m01; this.m02 = m02; this.m03 = m03;
|
||||
this.m10 = m10; this.m11 = m11; this.m12 = m12; this.m13 = m13;
|
||||
this.m20 = m20; this.m21 = m21; this.m22 = m22; this.m23 = m23;
|
||||
this.m30 = m30; this.m31 = m31; this.m32 = m32; this.m33 = m33;
|
||||
}
|
||||
|
||||
|
||||
public void translate(float tx, float ty) {
|
||||
translate(tx, ty, 0);
|
||||
}
|
||||
|
||||
// public void invTranslate(float tx, float ty) {
|
||||
// invTranslate(tx, ty, 0);
|
||||
// }
|
||||
|
||||
|
||||
public void translate(float tx, float ty, float tz) {
|
||||
m03 += tx*m00 + ty*m01 + tz*m02;
|
||||
m13 += tx*m10 + ty*m11 + tz*m12;
|
||||
m23 += tx*m20 + ty*m21 + tz*m22;
|
||||
m33 += tx*m30 + ty*m31 + tz*m32;
|
||||
}
|
||||
|
||||
|
||||
public void rotate(float angle) {
|
||||
rotateZ(angle);
|
||||
}
|
||||
|
||||
|
||||
public void rotateX(float angle) {
|
||||
float c = cos(angle);
|
||||
float s = sin(angle);
|
||||
apply(1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
public void rotateY(float angle) {
|
||||
float c = cos(angle);
|
||||
float s = sin(angle);
|
||||
apply(c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
public void rotateZ(float angle) {
|
||||
float c = cos(angle);
|
||||
float s = sin(angle);
|
||||
apply(c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
public void rotate(float angle, float v0, float v1, float v2) {
|
||||
// TODO should make sure this vector is normalized
|
||||
|
||||
float c = cos(angle);
|
||||
float s = sin(angle);
|
||||
float t = 1.0f - c;
|
||||
|
||||
apply((t*v0*v0) + c, (t*v0*v1) - (s*v2), (t*v0*v2) + (s*v1), 0,
|
||||
(t*v0*v1) + (s*v2), (t*v1*v1) + c, (t*v1*v2) - (s*v0), 0,
|
||||
(t*v0*v2) - (s*v1), (t*v1*v2) + (s*v0), (t*v2*v2) + c, 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
public void scale(float s) {
|
||||
//apply(s, 0, 0, 0, 0, s, 0, 0, 0, 0, s, 0, 0, 0, 0, 1);
|
||||
scale(s, s, s);
|
||||
}
|
||||
|
||||
|
||||
public void scale(float sx, float sy) {
|
||||
//apply(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
scale(sx, sy, 1);
|
||||
}
|
||||
|
||||
|
||||
public void scale(float x, float y, float z) {
|
||||
//apply(x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1);
|
||||
m00 *= x; m01 *= y; m02 *= z;
|
||||
m10 *= x; m11 *= y; m12 *= z;
|
||||
m20 *= x; m21 *= y; m22 *= z;
|
||||
m30 *= x; m31 *= y; m32 *= z;
|
||||
}
|
||||
|
||||
|
||||
public void skewX(float angle) {
|
||||
float t = (float) Math.tan(angle);
|
||||
apply(1, t, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
public void skewY(float angle) {
|
||||
float t = (float) Math.tan(angle);
|
||||
apply(1, 0, 0, 0,
|
||||
t, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
public void apply(PMatrix source) {
|
||||
if (source instanceof PMatrix2D) {
|
||||
apply((PMatrix2D) source);
|
||||
} else if (source instanceof PMatrix3D) {
|
||||
apply((PMatrix3D) source);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void apply(PMatrix2D source) {
|
||||
apply(source.m00, source.m01, 0, source.m02,
|
||||
source.m10, source.m11, 0, source.m12,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
public void apply(PMatrix3D source) {
|
||||
apply(source.m00, source.m01, source.m02, source.m03,
|
||||
source.m10, source.m11, source.m12, source.m13,
|
||||
source.m20, source.m21, source.m22, source.m23,
|
||||
source.m30, source.m31, source.m32, source.m33);
|
||||
}
|
||||
|
||||
|
||||
public void apply(float n00, float n01, float n02,
|
||||
float n10, float n11, float n12) {
|
||||
apply(n00, n01, 0, n02,
|
||||
n10, n11, 0, n12,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
public void apply(float n00, float n01, float n02, float n03,
|
||||
float n10, float n11, float n12, float n13,
|
||||
float n20, float n21, float n22, float n23,
|
||||
float n30, float n31, float n32, float n33) {
|
||||
|
||||
float r00 = m00*n00 + m01*n10 + m02*n20 + m03*n30;
|
||||
float r01 = m00*n01 + m01*n11 + m02*n21 + m03*n31;
|
||||
float r02 = m00*n02 + m01*n12 + m02*n22 + m03*n32;
|
||||
float r03 = m00*n03 + m01*n13 + m02*n23 + m03*n33;
|
||||
|
||||
float r10 = m10*n00 + m11*n10 + m12*n20 + m13*n30;
|
||||
float r11 = m10*n01 + m11*n11 + m12*n21 + m13*n31;
|
||||
float r12 = m10*n02 + m11*n12 + m12*n22 + m13*n32;
|
||||
float r13 = m10*n03 + m11*n13 + m12*n23 + m13*n33;
|
||||
|
||||
float r20 = m20*n00 + m21*n10 + m22*n20 + m23*n30;
|
||||
float r21 = m20*n01 + m21*n11 + m22*n21 + m23*n31;
|
||||
float r22 = m20*n02 + m21*n12 + m22*n22 + m23*n32;
|
||||
float r23 = m20*n03 + m21*n13 + m22*n23 + m23*n33;
|
||||
|
||||
float r30 = m30*n00 + m31*n10 + m32*n20 + m33*n30;
|
||||
float r31 = m30*n01 + m31*n11 + m32*n21 + m33*n31;
|
||||
float r32 = m30*n02 + m31*n12 + m32*n22 + m33*n32;
|
||||
float r33 = m30*n03 + m31*n13 + m32*n23 + m33*n33;
|
||||
|
||||
m00 = r00; m01 = r01; m02 = r02; m03 = r03;
|
||||
m10 = r10; m11 = r11; m12 = r12; m13 = r13;
|
||||
m20 = r20; m21 = r21; m22 = r22; m23 = r23;
|
||||
m30 = r30; m31 = r31; m32 = r32; m33 = r33;
|
||||
}
|
||||
|
||||
|
||||
public void preApply(PMatrix2D left) {
|
||||
preApply(left.m00, left.m01, 0, left.m02,
|
||||
left.m10, left.m11, 0, left.m12,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Apply another matrix to the left of this one.
|
||||
*/
|
||||
public void preApply(PMatrix3D left) {
|
||||
preApply(left.m00, left.m01, left.m02, left.m03,
|
||||
left.m10, left.m11, left.m12, left.m13,
|
||||
left.m20, left.m21, left.m22, left.m23,
|
||||
left.m30, left.m31, left.m32, left.m33);
|
||||
}
|
||||
|
||||
|
||||
public void preApply(float n00, float n01, float n02,
|
||||
float n10, float n11, float n12) {
|
||||
preApply(n00, n01, 0, n02,
|
||||
n10, n11, 0, n12,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
public void preApply(float n00, float n01, float n02, float n03,
|
||||
float n10, float n11, float n12, float n13,
|
||||
float n20, float n21, float n22, float n23,
|
||||
float n30, float n31, float n32, float n33) {
|
||||
|
||||
float r00 = n00*m00 + n01*m10 + n02*m20 + n03*m30;
|
||||
float r01 = n00*m01 + n01*m11 + n02*m21 + n03*m31;
|
||||
float r02 = n00*m02 + n01*m12 + n02*m22 + n03*m32;
|
||||
float r03 = n00*m03 + n01*m13 + n02*m23 + n03*m33;
|
||||
|
||||
float r10 = n10*m00 + n11*m10 + n12*m20 + n13*m30;
|
||||
float r11 = n10*m01 + n11*m11 + n12*m21 + n13*m31;
|
||||
float r12 = n10*m02 + n11*m12 + n12*m22 + n13*m32;
|
||||
float r13 = n10*m03 + n11*m13 + n12*m23 + n13*m33;
|
||||
|
||||
float r20 = n20*m00 + n21*m10 + n22*m20 + n23*m30;
|
||||
float r21 = n20*m01 + n21*m11 + n22*m21 + n23*m31;
|
||||
float r22 = n20*m02 + n21*m12 + n22*m22 + n23*m32;
|
||||
float r23 = n20*m03 + n21*m13 + n22*m23 + n23*m33;
|
||||
|
||||
float r30 = n30*m00 + n31*m10 + n32*m20 + n33*m30;
|
||||
float r31 = n30*m01 + n31*m11 + n32*m21 + n33*m31;
|
||||
float r32 = n30*m02 + n31*m12 + n32*m22 + n33*m32;
|
||||
float r33 = n30*m03 + n31*m13 + n32*m23 + n33*m33;
|
||||
|
||||
m00 = r00; m01 = r01; m02 = r02; m03 = r03;
|
||||
m10 = r10; m11 = r11; m12 = r12; m13 = r13;
|
||||
m20 = r20; m21 = r21; m22 = r22; m23 = r23;
|
||||
m30 = r30; m31 = r31; m32 = r32; m33 = r33;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
public PVector mult(PVector source, PVector target) {
|
||||
if (target == null) {
|
||||
target = new PVector();
|
||||
}
|
||||
target.x = m00*source.x + m01*source.y + m02*source.z + m03;
|
||||
target.y = m10*source.x + m11*source.y + m12*source.z + m13;
|
||||
target.z = m20*source.x + m21*source.y + m22*source.z + m23;
|
||||
// float tw = m30*source.x + m31*source.y + m32*source.z + m33;
|
||||
// if (tw != 0 && tw != 1) {
|
||||
// target.div(tw);
|
||||
// }
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
public PVector cmult(PVector source, PVector target) {
|
||||
if (target == null) {
|
||||
target = new PVector();
|
||||
}
|
||||
target.x = m00*source.x + m10*source.y + m20*source.z + m30;
|
||||
target.y = m01*source.x + m11*source.y + m21*source.z + m31;
|
||||
target.z = m02*source.x + m12*source.y + m22*source.z + m32;
|
||||
float tw = m03*source.x + m13*source.y + m23*source.z + m33;
|
||||
if (tw != 0 && tw != 1) {
|
||||
target.div(tw);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Multiply a three or four element vector against this matrix. If out is
|
||||
* null or not length 3 or 4, a new float array (length 3) will be returned.
|
||||
*/
|
||||
public float[] mult(float[] source, float[] target) {
|
||||
if (target == null || target.length < 3) {
|
||||
target = new float[3];
|
||||
}
|
||||
if (source == target) {
|
||||
throw new RuntimeException("The source and target vectors used in " +
|
||||
"PMatrix3D.mult() cannot be identical.");
|
||||
}
|
||||
if (target.length == 3) {
|
||||
target[0] = m00*source[0] + m01*source[1] + m02*source[2] + m03;
|
||||
target[1] = m10*source[0] + m11*source[1] + m12*source[2] + m13;
|
||||
target[2] = m20*source[0] + m21*source[1] + m22*source[2] + m23;
|
||||
//float w = m30*source[0] + m31*source[1] + m32*source[2] + m33;
|
||||
//if (w != 0 && w != 1) {
|
||||
// target[0] /= w; target[1] /= w; target[2] /= w;
|
||||
//}
|
||||
} else if (target.length > 3) {
|
||||
target[0] = m00*source[0] + m01*source[1] + m02*source[2] + m03*source[3];
|
||||
target[1] = m10*source[0] + m11*source[1] + m12*source[2] + m13*source[3];
|
||||
target[2] = m20*source[0] + m21*source[1] + m22*source[2] + m23*source[3];
|
||||
target[3] = m30*source[0] + m31*source[1] + m32*source[2] + m33*source[3];
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
public float multX(float x, float y) {
|
||||
return m00*x + m01*y + m03;
|
||||
}
|
||||
|
||||
|
||||
public float multY(float x, float y) {
|
||||
return m10*x + m11*y + m13;
|
||||
}
|
||||
|
||||
|
||||
public float multX(float x, float y, float z) {
|
||||
return m00*x + m01*y + m02*z + m03;
|
||||
}
|
||||
|
||||
|
||||
public float multY(float x, float y, float z) {
|
||||
return m10*x + m11*y + m12*z + m13;
|
||||
}
|
||||
|
||||
|
||||
public float multZ(float x, float y, float z) {
|
||||
return m20*x + m21*y + m22*z + m23;
|
||||
}
|
||||
|
||||
|
||||
public float multW(float x, float y, float z) {
|
||||
return m30*x + m31*y + m32*z + m33;
|
||||
}
|
||||
|
||||
|
||||
public float multX(float x, float y, float z, float w) {
|
||||
return m00*x + m01*y + m02*z + m03*w;
|
||||
}
|
||||
|
||||
|
||||
public float multY(float x, float y, float z, float w) {
|
||||
return m10*x + m11*y + m12*z + m13*w;
|
||||
}
|
||||
|
||||
|
||||
public float multZ(float x, float y, float z, float w) {
|
||||
return m20*x + m21*y + m22*z + m23*w;
|
||||
}
|
||||
|
||||
|
||||
public float multW(float x, float y, float z, float w) {
|
||||
return m30*x + m31*y + m32*z + m33*w;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Transpose this matrix.
|
||||
*/
|
||||
public void transpose() {
|
||||
float temp;
|
||||
temp = m01; m01 = m10; m10 = temp;
|
||||
temp = m02; m02 = m20; m20 = temp;
|
||||
temp = m03; m03 = m30; m30 = temp;
|
||||
temp = m12; m12 = m21; m21 = temp;
|
||||
temp = m13; m13 = m31; m31 = temp;
|
||||
temp = m23; m23 = m32; m32 = temp;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Invert this matrix.
|
||||
* @return true if successful
|
||||
*/
|
||||
public boolean invert() {
|
||||
float determinant = determinant();
|
||||
if (determinant == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// first row
|
||||
float t00 = determinant3x3(m11, m12, m13, m21, m22, m23, m31, m32, m33);
|
||||
float t01 = -determinant3x3(m10, m12, m13, m20, m22, m23, m30, m32, m33);
|
||||
float t02 = determinant3x3(m10, m11, m13, m20, m21, m23, m30, m31, m33);
|
||||
float t03 = -determinant3x3(m10, m11, m12, m20, m21, m22, m30, m31, m32);
|
||||
|
||||
// second row
|
||||
float t10 = -determinant3x3(m01, m02, m03, m21, m22, m23, m31, m32, m33);
|
||||
float t11 = determinant3x3(m00, m02, m03, m20, m22, m23, m30, m32, m33);
|
||||
float t12 = -determinant3x3(m00, m01, m03, m20, m21, m23, m30, m31, m33);
|
||||
float t13 = determinant3x3(m00, m01, m02, m20, m21, m22, m30, m31, m32);
|
||||
|
||||
// third row
|
||||
float t20 = determinant3x3(m01, m02, m03, m11, m12, m13, m31, m32, m33);
|
||||
float t21 = -determinant3x3(m00, m02, m03, m10, m12, m13, m30, m32, m33);
|
||||
float t22 = determinant3x3(m00, m01, m03, m10, m11, m13, m30, m31, m33);
|
||||
float t23 = -determinant3x3(m00, m01, m02, m10, m11, m12, m30, m31, m32);
|
||||
|
||||
// fourth row
|
||||
float t30 = -determinant3x3(m01, m02, m03, m11, m12, m13, m21, m22, m23);
|
||||
float t31 = determinant3x3(m00, m02, m03, m10, m12, m13, m20, m22, m23);
|
||||
float t32 = -determinant3x3(m00, m01, m03, m10, m11, m13, m20, m21, m23);
|
||||
float t33 = determinant3x3(m00, m01, m02, m10, m11, m12, m20, m21, m22);
|
||||
|
||||
// transpose and divide by the determinant
|
||||
m00 = t00 / determinant;
|
||||
m01 = t10 / determinant;
|
||||
m02 = t20 / determinant;
|
||||
m03 = t30 / determinant;
|
||||
|
||||
m10 = t01 / determinant;
|
||||
m11 = t11 / determinant;
|
||||
m12 = t21 / determinant;
|
||||
m13 = t31 / determinant;
|
||||
|
||||
m20 = t02 / determinant;
|
||||
m21 = t12 / determinant;
|
||||
m22 = t22 / determinant;
|
||||
m23 = t32 / determinant;
|
||||
|
||||
m30 = t03 / determinant;
|
||||
m31 = t13 / determinant;
|
||||
m32 = t23 / determinant;
|
||||
m33 = t33 / determinant;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculate the determinant of a 3x3 matrix.
|
||||
* @return result
|
||||
*/
|
||||
private float determinant3x3(float t00, float t01, float t02,
|
||||
float t10, float t11, float t12,
|
||||
float t20, float t21, float t22) {
|
||||
return (t00 * (t11 * t22 - t12 * t21) +
|
||||
t01 * (t12 * t20 - t10 * t22) +
|
||||
t02 * (t10 * t21 - t11 * t20));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the determinant of the matrix
|
||||
*/
|
||||
public float determinant() {
|
||||
float f =
|
||||
m00
|
||||
* ((m11 * m22 * m33 + m12 * m23 * m31 + m13 * m21 * m32)
|
||||
- m13 * m22 * m31
|
||||
- m11 * m23 * m32
|
||||
- m12 * m21 * m33);
|
||||
f -= m01
|
||||
* ((m10 * m22 * m33 + m12 * m23 * m30 + m13 * m20 * m32)
|
||||
- m13 * m22 * m30
|
||||
- m10 * m23 * m32
|
||||
- m12 * m20 * m33);
|
||||
f += m02
|
||||
* ((m10 * m21 * m33 + m11 * m23 * m30 + m13 * m20 * m31)
|
||||
- m13 * m21 * m30
|
||||
- m10 * m23 * m31
|
||||
- m11 * m20 * m33);
|
||||
f -= m03
|
||||
* ((m10 * m21 * m32 + m11 * m22 * m30 + m12 * m20 * m31)
|
||||
- m12 * m21 * m30
|
||||
- m10 * m22 * m31
|
||||
- m11 * m20 * m32);
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
// REVERSE VERSIONS OF MATRIX OPERATIONS
|
||||
|
||||
// These functions should not be used, as they will be removed in the future.
|
||||
|
||||
|
||||
protected void invTranslate(float tx, float ty, float tz) {
|
||||
preApply(1, 0, 0, -tx,
|
||||
0, 1, 0, -ty,
|
||||
0, 0, 1, -tz,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
protected void invRotateX(float angle) {
|
||||
float c = cos(-angle);
|
||||
float s = sin(-angle);
|
||||
preApply(1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
protected void invRotateY(float angle) {
|
||||
float c = cos(-angle);
|
||||
float s = sin(-angle);
|
||||
preApply(c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
protected void invRotateZ(float angle) {
|
||||
float c = cos(-angle);
|
||||
float s = sin(-angle);
|
||||
preApply(c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
protected void invRotate(float angle, float v0, float v1, float v2) {
|
||||
//TODO should make sure this vector is normalized
|
||||
|
||||
float c = cos(-angle);
|
||||
float s = sin(-angle);
|
||||
float t = 1.0f - c;
|
||||
|
||||
preApply((t*v0*v0) + c, (t*v0*v1) - (s*v2), (t*v0*v2) + (s*v1), 0,
|
||||
(t*v0*v1) + (s*v2), (t*v1*v1) + c, (t*v1*v2) - (s*v0), 0,
|
||||
(t*v0*v2) - (s*v1), (t*v1*v2) + (s*v0), (t*v2*v2) + c, 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
protected void invScale(float x, float y, float z) {
|
||||
preApply(1/x, 0, 0, 0, 0, 1/y, 0, 0, 0, 0, 1/z, 0, 0, 0, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
protected boolean invApply(float n00, float n01, float n02, float n03,
|
||||
float n10, float n11, float n12, float n13,
|
||||
float n20, float n21, float n22, float n23,
|
||||
float n30, float n31, float n32, float n33) {
|
||||
if (inverseCopy == null) {
|
||||
inverseCopy = new PMatrix3D();
|
||||
}
|
||||
inverseCopy.set(n00, n01, n02, n03,
|
||||
n10, n11, n12, n13,
|
||||
n20, n21, n22, n23,
|
||||
n30, n31, n32, n33);
|
||||
if (!inverseCopy.invert()) {
|
||||
return false;
|
||||
}
|
||||
preApply(inverseCopy);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
public void print() {
|
||||
/*
|
||||
System.out.println(m00 + " " + m01 + " " + m02 + " " + m03 + "\n" +
|
||||
m10 + " " + m11 + " " + m12 + " " + m13 + "\n" +
|
||||
m20 + " " + m21 + " " + m22 + " " + m23 + "\n" +
|
||||
m30 + " " + m31 + " " + m32 + " " + m33 + "\n");
|
||||
*/
|
||||
int big = (int) Math.abs(max(max(max(max(abs(m00), abs(m01)),
|
||||
max(abs(m02), abs(m03))),
|
||||
max(max(abs(m10), abs(m11)),
|
||||
max(abs(m12), abs(m13)))),
|
||||
max(max(max(abs(m20), abs(m21)),
|
||||
max(abs(m22), abs(m23))),
|
||||
max(max(abs(m30), abs(m31)),
|
||||
max(abs(m32), abs(m33))))));
|
||||
|
||||
int digits = 1;
|
||||
if (Float.isNaN(big) || Float.isInfinite(big)) { // avoid infinite loop
|
||||
digits = 5;
|
||||
} else {
|
||||
while ((big /= 10) != 0) digits++; // cheap log()
|
||||
}
|
||||
|
||||
System.out.println(PApplet.nfs(m00, digits, 4) + " " +
|
||||
PApplet.nfs(m01, digits, 4) + " " +
|
||||
PApplet.nfs(m02, digits, 4) + " " +
|
||||
PApplet.nfs(m03, digits, 4));
|
||||
|
||||
System.out.println(PApplet.nfs(m10, digits, 4) + " " +
|
||||
PApplet.nfs(m11, digits, 4) + " " +
|
||||
PApplet.nfs(m12, digits, 4) + " " +
|
||||
PApplet.nfs(m13, digits, 4));
|
||||
|
||||
System.out.println(PApplet.nfs(m20, digits, 4) + " " +
|
||||
PApplet.nfs(m21, digits, 4) + " " +
|
||||
PApplet.nfs(m22, digits, 4) + " " +
|
||||
PApplet.nfs(m23, digits, 4));
|
||||
|
||||
System.out.println(PApplet.nfs(m30, digits, 4) + " " +
|
||||
PApplet.nfs(m31, digits, 4) + " " +
|
||||
PApplet.nfs(m32, digits, 4) + " " +
|
||||
PApplet.nfs(m33, digits, 4));
|
||||
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
private final float max(float a, float b) {
|
||||
return (a > b) ? a : b;
|
||||
}
|
||||
|
||||
private final float abs(float a) {
|
||||
return (a < 0) ? -a : a;
|
||||
}
|
||||
|
||||
private final float sin(float angle) {
|
||||
return (float) Math.sin(angle);
|
||||
}
|
||||
|
||||
private final float cos(float angle) {
|
||||
return (float) Math.cos(angle);
|
||||
}
|
||||
}
|
701
core/src/processing/core/PPolygon.java
Normal file
701
core/src/processing/core/PPolygon.java
Normal file
@ -0,0 +1,701 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2004-08 Ben Fry and Casey Reas
|
||||
Copyright (c) 2001-04 Massachusetts Institute of Technology
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.core;
|
||||
|
||||
|
||||
/**
|
||||
* Z-buffer polygon rendering object used by PGraphics2D.
|
||||
*/
|
||||
public class PPolygon implements PConstants {
|
||||
|
||||
static final int DEFAULT_SIZE = 64; // this is needed for spheres
|
||||
float vertices[][] = new float[DEFAULT_SIZE][VERTEX_FIELD_COUNT];
|
||||
int vertexCount;
|
||||
|
||||
float r[] = new float[DEFAULT_SIZE]; // storage used by incrementalize
|
||||
float dr[] = new float[DEFAULT_SIZE];
|
||||
float l[] = new float[DEFAULT_SIZE]; // more storage for incrementalize
|
||||
float dl[] = new float[DEFAULT_SIZE];
|
||||
float sp[] = new float[DEFAULT_SIZE]; // temporary storage for scanline
|
||||
float sdp[] = new float[DEFAULT_SIZE];
|
||||
|
||||
protected boolean interpX;
|
||||
protected boolean interpUV; // is this necessary? could just check timage != null
|
||||
protected boolean interpARGB;
|
||||
|
||||
private int rgba;
|
||||
private int r2, g2, b2, a2, a2orig;
|
||||
|
||||
PGraphics parent;
|
||||
int[] pixels;
|
||||
// the parent's width/height,
|
||||
// or if smooth is enabled, parent's w/h scaled
|
||||
// up by the smooth dimension
|
||||
int width, height;
|
||||
int width1, height1;
|
||||
|
||||
PImage timage;
|
||||
int[] tpixels;
|
||||
int theight, twidth;
|
||||
int theight1, twidth1;
|
||||
int tformat;
|
||||
|
||||
// for anti-aliasing
|
||||
static final int SUBXRES = 8;
|
||||
static final int SUBXRES1 = 7;
|
||||
static final int SUBYRES = 8;
|
||||
static final int SUBYRES1 = 7;
|
||||
static final int MAX_COVERAGE = SUBXRES * SUBYRES;
|
||||
|
||||
boolean smooth;
|
||||
int firstModY;
|
||||
int lastModY;
|
||||
int lastY;
|
||||
int aaleft[] = new int[SUBYRES];
|
||||
int aaright[] = new int[SUBYRES];
|
||||
int aaleftmin, aarightmin;
|
||||
int aaleftmax, aarightmax;
|
||||
int aaleftfull, aarightfull;
|
||||
|
||||
final private int MODYRES(int y) {
|
||||
return (y & SUBYRES1);
|
||||
}
|
||||
|
||||
|
||||
public PPolygon(PGraphics iparent) {
|
||||
parent = iparent;
|
||||
reset(0);
|
||||
}
|
||||
|
||||
|
||||
protected void reset(int count) {
|
||||
vertexCount = count;
|
||||
interpX = true;
|
||||
// interpZ = true;
|
||||
interpUV = false;
|
||||
interpARGB = true;
|
||||
timage = null;
|
||||
}
|
||||
|
||||
|
||||
protected float[] nextVertex() {
|
||||
if (vertexCount == vertices.length) {
|
||||
float temp[][] = new float[vertexCount<<1][VERTEX_FIELD_COUNT];
|
||||
System.arraycopy(vertices, 0, temp, 0, vertexCount);
|
||||
vertices = temp;
|
||||
|
||||
r = new float[vertices.length];
|
||||
dr = new float[vertices.length];
|
||||
l = new float[vertices.length];
|
||||
dl = new float[vertices.length];
|
||||
sp = new float[vertices.length];
|
||||
sdp = new float[vertices.length];
|
||||
}
|
||||
return vertices[vertexCount++]; // returns v[0], sets vc to 1
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return true if this vertex is redundant. If so, will also
|
||||
* decrement the vertex count.
|
||||
*/
|
||||
/*
|
||||
public boolean redundantVertex(float x, float y, float z) {
|
||||
// because vertexCount will be 2 when setting vertex[1]
|
||||
if (vertexCount < 2) return false;
|
||||
|
||||
// vertexCount-1 is the current vertex that would be used
|
||||
// vertexCount-2 would be the previous feller
|
||||
if ((Math.abs(vertices[vertexCount-2][MX] - x) < EPSILON) &&
|
||||
(Math.abs(vertices[vertexCount-2][MY] - y) < EPSILON) &&
|
||||
(Math.abs(vertices[vertexCount-2][MZ] - z) < EPSILON)) {
|
||||
vertexCount--;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
protected void texture(PImage image) {
|
||||
this.timage = image;
|
||||
|
||||
if (image != null) {
|
||||
this.tpixels = image.pixels;
|
||||
this.twidth = image.width;
|
||||
this.theight = image.height;
|
||||
this.tformat = image.format;
|
||||
|
||||
twidth1 = twidth - 1;
|
||||
theight1 = theight - 1;
|
||||
interpUV = true;
|
||||
|
||||
} else {
|
||||
interpUV = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void renderPolygon(float[][] v, int count) {
|
||||
vertices = v;
|
||||
vertexCount = count;
|
||||
|
||||
if (r.length < vertexCount) {
|
||||
r = new float[vertexCount]; // storage used by incrementalize
|
||||
dr = new float[vertexCount];
|
||||
l = new float[vertexCount]; // more storage for incrementalize
|
||||
dl = new float[vertexCount];
|
||||
sp = new float[vertexCount]; // temporary storage for scanline
|
||||
sdp = new float[vertexCount];
|
||||
}
|
||||
|
||||
render();
|
||||
checkExpand();
|
||||
}
|
||||
|
||||
|
||||
protected void renderTriangle(float[] v1, float[] v2, float[] v3) {
|
||||
// Calling code will have already done reset(3).
|
||||
// Can't do it here otherwise would nuke any texture settings.
|
||||
|
||||
vertices[0] = v1;
|
||||
vertices[1] = v2;
|
||||
vertices[2] = v3;
|
||||
|
||||
render();
|
||||
checkExpand();
|
||||
}
|
||||
|
||||
|
||||
protected void checkExpand() {
|
||||
if (smooth) {
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
vertices[i][TX] /= SUBXRES;
|
||||
vertices[i][TY] /= SUBYRES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void render() {
|
||||
if (vertexCount < 3) return;
|
||||
|
||||
// these may have changed due to a resize()
|
||||
// so they should be refreshed here
|
||||
pixels = parent.pixels;
|
||||
//zbuffer = parent.zbuffer;
|
||||
|
||||
// noDepthTest = parent.hints[DISABLE_DEPTH_TEST];
|
||||
smooth = parent.smooth;
|
||||
|
||||
// by default, text turns on smooth for the textures
|
||||
// themselves. but this should be shut off if the hint
|
||||
// for DISABLE_TEXT_SMOOTH is set.
|
||||
// texture_smooth = true;
|
||||
|
||||
width = smooth ? parent.width*SUBXRES : parent.width;
|
||||
height = smooth ? parent.height*SUBYRES : parent.height;
|
||||
|
||||
width1 = width - 1;
|
||||
height1 = height - 1;
|
||||
|
||||
if (!interpARGB) {
|
||||
r2 = (int) (vertices[0][R] * 255);
|
||||
g2 = (int) (vertices[0][G] * 255);
|
||||
b2 = (int) (vertices[0][B] * 255);
|
||||
a2 = (int) (vertices[0][A] * 255);
|
||||
a2orig = a2; // save an extra copy
|
||||
rgba = 0xff000000 | (r2 << 16) | (g2 << 8) | b2;
|
||||
}
|
||||
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
r[i] = 0; dr[i] = 0; l[i] = 0; dl[i] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
// hack to not make polygons fly into the screen
|
||||
if (parent.hints[DISABLE_FLYING_POO]) {
|
||||
float nwidth2 = -width * 2;
|
||||
float nheight2 = -height * 2;
|
||||
float width2 = width * 2;
|
||||
float height2 = height * 2;
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
if ((vertices[i][TX] < nwidth2) ||
|
||||
(vertices[i][TX] > width2) ||
|
||||
(vertices[i][TY] < nheight2) ||
|
||||
(vertices[i][TY] > height2)) {
|
||||
return; // this is a bad poly
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// for (int i = 0; i < 4; i++) {
|
||||
// System.out.println(vertices[i][R] + " " + vertices[i][G] + " " + vertices[i][B]);
|
||||
// }
|
||||
// System.out.println();
|
||||
|
||||
if (smooth) {
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
vertices[i][TX] *= SUBXRES;
|
||||
vertices[i][TY] *= SUBYRES;
|
||||
}
|
||||
firstModY = -1;
|
||||
}
|
||||
|
||||
// find top vertex (y is zero at top, higher downwards)
|
||||
int topi = 0;
|
||||
float ymin = vertices[0][TY];
|
||||
float ymax = vertices[0][TY]; // fry 031001
|
||||
for (int i = 1; i < vertexCount; i++) {
|
||||
if (vertices[i][TY] < ymin) {
|
||||
ymin = vertices[i][TY];
|
||||
topi = i;
|
||||
}
|
||||
if (vertices[i][TY] > ymax) {
|
||||
ymax = vertices[i][TY];
|
||||
}
|
||||
}
|
||||
|
||||
// the last row is an exceptional case, because there won't
|
||||
// necessarily be 8 rows of subpixel lines that will force
|
||||
// the final line to render. so instead, the algo keeps track
|
||||
// of the lastY (in subpixel resolution) that will be rendered
|
||||
// and that will force a scanline to happen the same as
|
||||
// every eighth in the other situations
|
||||
//lastY = -1; // fry 031001
|
||||
lastY = (int) (ymax - 0.5f); // global to class bc used by other fxns
|
||||
|
||||
int lefti = topi; // li, index of left vertex
|
||||
int righti = topi; // ri, index of right vertex
|
||||
int y = (int) (ymin + 0.5f); // current scan line
|
||||
int lefty = y - 1; // lower end of left edge
|
||||
int righty = y - 1; // lower end of right edge
|
||||
|
||||
interpX = true;
|
||||
|
||||
int remaining = vertexCount;
|
||||
|
||||
// scan in y, activating new edges on left & right
|
||||
// as scan line passes over new vertices
|
||||
while (remaining > 0) {
|
||||
// advance left edge?
|
||||
while ((lefty <= y) && (remaining > 0)) {
|
||||
remaining--;
|
||||
// step ccw down left side
|
||||
int i = (lefti != 0) ? (lefti-1) : (vertexCount-1);
|
||||
incrementalizeY(vertices[lefti], vertices[i], l, dl, y);
|
||||
lefty = (int) (vertices[i][TY] + 0.5f);
|
||||
lefti = i;
|
||||
}
|
||||
|
||||
// advance right edge?
|
||||
while ((righty <= y) && (remaining > 0)) {
|
||||
remaining--;
|
||||
// step cw down right edge
|
||||
int i = (righti != vertexCount-1) ? (righti + 1) : 0;
|
||||
incrementalizeY(vertices[righti], vertices[i], r, dr, y);
|
||||
righty = (int) (vertices[i][TY] + 0.5f);
|
||||
righti = i;
|
||||
}
|
||||
|
||||
// do scanlines till end of l or r edge
|
||||
while (y < lefty && y < righty) {
|
||||
// this doesn't work because it's not always set here
|
||||
//if (remaining == 0) {
|
||||
//lastY = (lefty < righty) ? lefty-1 : righty-1;
|
||||
//System.out.println("lastY is " + lastY);
|
||||
//}
|
||||
|
||||
if ((y >= 0) && (y < height)) {
|
||||
//try { // hopefully this bug is fixed
|
||||
if (l[TX] <= r[TX]) scanline(y, l, r);
|
||||
else scanline(y, r, l);
|
||||
//} catch (ArrayIndexOutOfBoundsException e) {
|
||||
//e.printStackTrace();
|
||||
//}
|
||||
}
|
||||
y++;
|
||||
// this increment probably needs to be different
|
||||
// UV and RGB shouldn't be incremented until line is emitted
|
||||
increment(l, dl);
|
||||
increment(r, dr);
|
||||
}
|
||||
}
|
||||
//if (smooth) {
|
||||
//System.out.println("y/lasty/lastmody = " + y + " " + lastY + " " + lastModY);
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
private void scanline(int y, float l[], float r[]) {
|
||||
//System.out.println("scanline " + y);
|
||||
for (int i = 0; i < vertexCount; i++) { // should be moved later
|
||||
sp[i] = 0; sdp[i] = 0;
|
||||
}
|
||||
|
||||
// this rounding doesn't seem to be relevant with smooth
|
||||
int lx = (int) (l[TX] + 0.49999f); // ceil(l[TX]-.5);
|
||||
if (lx < 0) lx = 0;
|
||||
int rx = (int) (r[TX] - 0.5f);
|
||||
if (rx > width1) rx = width1;
|
||||
|
||||
if (lx > rx) return;
|
||||
|
||||
if (smooth) {
|
||||
int mody = MODYRES(y);
|
||||
|
||||
aaleft[mody] = lx;
|
||||
aaright[mody] = rx;
|
||||
|
||||
if (firstModY == -1) {
|
||||
firstModY = mody;
|
||||
aaleftmin = lx; aaleftmax = lx;
|
||||
aarightmin = rx; aarightmax = rx;
|
||||
|
||||
} else {
|
||||
if (aaleftmin > aaleft[mody]) aaleftmin = aaleft[mody];
|
||||
if (aaleftmax < aaleft[mody]) aaleftmax = aaleft[mody];
|
||||
if (aarightmin > aaright[mody]) aarightmin = aaright[mody];
|
||||
if (aarightmax < aaright[mody]) aarightmax = aaright[mody];
|
||||
}
|
||||
|
||||
lastModY = mody; // moved up here (before the return) 031001
|
||||
// not the eighth (or lastY) line, so not scanning this time
|
||||
if ((mody != SUBYRES1) && (y != lastY)) return;
|
||||
//lastModY = mody; // eeK! this was missing
|
||||
//return;
|
||||
|
||||
//if (y == lastY) {
|
||||
//System.out.println("y is lasty");
|
||||
//}
|
||||
//lastModY = mody;
|
||||
aaleftfull = aaleftmax/SUBXRES + 1;
|
||||
aarightfull = aarightmin/SUBXRES - 1;
|
||||
}
|
||||
|
||||
// this is the setup, based on lx
|
||||
incrementalizeX(l, r, sp, sdp, lx);
|
||||
|
||||
// scan in x, generating pixels
|
||||
// using parent.width to get actual pixel index
|
||||
// rather than scaled by smooth factor
|
||||
int offset = smooth ? parent.width * (y / SUBYRES) : parent.width*y;
|
||||
|
||||
int truelx = 0, truerx = 0;
|
||||
if (smooth) {
|
||||
truelx = lx / SUBXRES;
|
||||
truerx = (rx + SUBXRES1) / SUBXRES;
|
||||
|
||||
lx = aaleftmin / SUBXRES;
|
||||
rx = (aarightmax + SUBXRES1) / SUBXRES;
|
||||
if (lx < 0) lx = 0;
|
||||
if (rx > parent.width1) rx = parent.width1;
|
||||
}
|
||||
|
||||
interpX = false;
|
||||
int tr, tg, tb, ta;
|
||||
|
||||
// System.out.println("P2D interp uv " + interpUV + " " +
|
||||
// vertices[2][U] + " " + vertices[2][V]);
|
||||
for (int x = lx; x <= rx; x++) {
|
||||
// map texture based on U, V coords in sp[U] and sp[V]
|
||||
if (interpUV) {
|
||||
int tu = (int) (sp[U] * twidth);
|
||||
int tv = (int) (sp[V] * theight);
|
||||
|
||||
if (tu > twidth1) tu = twidth1;
|
||||
if (tv > theight1) tv = theight1;
|
||||
if (tu < 0) tu = 0;
|
||||
if (tv < 0) tv = 0;
|
||||
|
||||
int txy = tv*twidth + tu;
|
||||
|
||||
int tuf1 = (int) (255f * (sp[U]*twidth - (float)tu));
|
||||
int tvf1 = (int) (255f * (sp[V]*theight - (float)tv));
|
||||
|
||||
// the closer sp[U or V] is to the decimal being zero
|
||||
// the more coverage it should get of the original pixel
|
||||
int tuf = 255 - tuf1;
|
||||
int tvf = 255 - tvf1;
|
||||
|
||||
// this code sucks! filled with bugs and slow as hell!
|
||||
int pixel00 = tpixels[txy];
|
||||
int pixel01 = (tv < theight1) ?
|
||||
tpixels[txy + twidth] : tpixels[txy];
|
||||
int pixel10 = (tu < twidth1) ?
|
||||
tpixels[txy + 1] : tpixels[txy];
|
||||
int pixel11 = ((tv < theight1) && (tu < twidth1)) ?
|
||||
tpixels[txy + twidth + 1] : tpixels[txy];
|
||||
|
||||
int p00, p01, p10, p11;
|
||||
int px0, px1; //, pxy;
|
||||
|
||||
|
||||
// calculate alpha component (ta)
|
||||
|
||||
if (tformat == ALPHA) {
|
||||
px0 = (pixel00*tuf + pixel10*tuf1) >> 8;
|
||||
px1 = (pixel01*tuf + pixel11*tuf1) >> 8;
|
||||
ta = (((px0*tvf + px1*tvf1) >> 8) *
|
||||
(interpARGB ? ((int) (sp[A]*255)) : a2orig)) >> 8;
|
||||
|
||||
} else if (tformat == ARGB) {
|
||||
p00 = (pixel00 >> 24) & 0xff;
|
||||
p01 = (pixel01 >> 24) & 0xff;
|
||||
p10 = (pixel10 >> 24) & 0xff;
|
||||
p11 = (pixel11 >> 24) & 0xff;
|
||||
|
||||
px0 = (p00*tuf + p10*tuf1) >> 8;
|
||||
px1 = (p01*tuf + p11*tuf1) >> 8;
|
||||
ta = (((px0*tvf + px1*tvf1) >> 8) *
|
||||
(interpARGB ? ((int) (sp[A]*255)) : a2orig)) >> 8;
|
||||
|
||||
} else { // RGB image, no alpha
|
||||
ta = interpARGB ? ((int) (sp[A]*255)) : a2orig;
|
||||
}
|
||||
|
||||
// calculate r,g,b components (tr, tg, tb)
|
||||
|
||||
if ((tformat == RGB) || (tformat == ARGB)) {
|
||||
p00 = (pixel00 >> 16) & 0xff; // red
|
||||
p01 = (pixel01 >> 16) & 0xff;
|
||||
p10 = (pixel10 >> 16) & 0xff;
|
||||
p11 = (pixel11 >> 16) & 0xff;
|
||||
|
||||
px0 = (p00*tuf + p10*tuf1) >> 8;
|
||||
px1 = (p01*tuf + p11*tuf1) >> 8;
|
||||
tr = (((px0*tvf + px1*tvf1) >> 8) *
|
||||
(interpARGB ? ((int) (sp[R]*255)) : r2)) >> 8;
|
||||
|
||||
p00 = (pixel00 >> 8) & 0xff; // green
|
||||
p01 = (pixel01 >> 8) & 0xff;
|
||||
p10 = (pixel10 >> 8) & 0xff;
|
||||
p11 = (pixel11 >> 8) & 0xff;
|
||||
|
||||
px0 = (p00*tuf + p10*tuf1) >> 8;
|
||||
px1 = (p01*tuf + p11*tuf1) >> 8;
|
||||
tg = (((px0*tvf + px1*tvf1) >> 8) *
|
||||
(interpARGB ? ((int) (sp[G]*255)) : g2)) >> 8;
|
||||
|
||||
p00 = pixel00 & 0xff; // blue
|
||||
p01 = pixel01 & 0xff;
|
||||
p10 = pixel10 & 0xff;
|
||||
p11 = pixel11 & 0xff;
|
||||
|
||||
px0 = (p00*tuf + p10*tuf1) >> 8;
|
||||
px1 = (p01*tuf + p11*tuf1) >> 8;
|
||||
tb = (((px0*tvf + px1*tvf1) >> 8) *
|
||||
(interpARGB ? ((int) (sp[B]*255)) : b2)) >> 8;
|
||||
|
||||
} else { // alpha image, only use current fill color
|
||||
if (interpARGB) {
|
||||
tr = (int) (sp[R] * 255);
|
||||
tg = (int) (sp[G] * 255);
|
||||
tb = (int) (sp[B] * 255);
|
||||
|
||||
} else {
|
||||
tr = r2;
|
||||
tg = g2;
|
||||
tb = b2;
|
||||
}
|
||||
}
|
||||
|
||||
int weight = smooth ? coverage(x) : 255;
|
||||
if (weight != 255) ta = ta*weight >> 8;
|
||||
|
||||
if ((ta == 254) || (ta == 255)) { // if (ta & 0xf8) would be good
|
||||
// no need to blend
|
||||
pixels[offset+x] = 0xff000000 | (tr << 16) | (tg << 8) | tb;
|
||||
|
||||
} else {
|
||||
// blend with pixel on screen
|
||||
int a1 = 255-ta;
|
||||
int r1 = (pixels[offset+x] >> 16) & 0xff;
|
||||
int g1 = (pixels[offset+x] >> 8) & 0xff;
|
||||
int b1 = (pixels[offset+x]) & 0xff;
|
||||
|
||||
pixels[offset+x] = 0xff000000 |
|
||||
(((tr*ta + r1*a1) >> 8) << 16) |
|
||||
((tg*ta + g1*a1) & 0xff00) |
|
||||
((tb*ta + b1*a1) >> 8);
|
||||
}
|
||||
|
||||
} else { // no image applied
|
||||
int weight = smooth ? coverage(x) : 255;
|
||||
|
||||
if (interpARGB) {
|
||||
r2 = (int) (sp[R] * 255);
|
||||
g2 = (int) (sp[G] * 255);
|
||||
b2 = (int) (sp[B] * 255);
|
||||
if (sp[A] != 1) weight = (weight * ((int) (sp[A] * 255))) >> 8;
|
||||
if (weight == 255) {
|
||||
rgba = 0xff000000 | (r2 << 16) | (g2 << 8) | b2;
|
||||
}
|
||||
} else {
|
||||
if (a2orig != 255) weight = (weight * a2orig) >> 8;
|
||||
}
|
||||
|
||||
if (weight == 255) {
|
||||
// no blend, no aa, just the rgba
|
||||
pixels[offset+x] = rgba;
|
||||
//zbuffer[offset+x] = sp[Z];
|
||||
|
||||
} else {
|
||||
int r1 = (pixels[offset+x] >> 16) & 0xff;
|
||||
int g1 = (pixels[offset+x] >> 8) & 0xff;
|
||||
int b1 = (pixels[offset+x]) & 0xff;
|
||||
a2 = weight;
|
||||
|
||||
int a1 = 255 - a2;
|
||||
pixels[offset+x] = (0xff000000 |
|
||||
((r1*a1 + r2*a2) >> 8) << 16 |
|
||||
// use & instead of >> and << below
|
||||
((g1*a1 + g2*a2) >> 8) << 8 |
|
||||
((b1*a1 + b2*a2) >> 8));
|
||||
}
|
||||
}
|
||||
|
||||
// if smooth enabled, don't increment values
|
||||
// for the pixel in the stretch out version
|
||||
// of the scanline used to get smooth edges.
|
||||
if (!smooth || ((x >= truelx) && (x <= truerx))) {
|
||||
increment(sp, sdp);
|
||||
}
|
||||
}
|
||||
firstModY = -1;
|
||||
interpX = true;
|
||||
}
|
||||
|
||||
|
||||
// x is in screen, not huge 8x coordinates
|
||||
private int coverage(int x) {
|
||||
if ((x >= aaleftfull) && (x <= aarightfull) &&
|
||||
// important since not all SUBYRES lines may have been covered
|
||||
(firstModY == 0) && (lastModY == SUBYRES1)) {
|
||||
return 255;
|
||||
}
|
||||
|
||||
int pixelLeft = x*SUBXRES; // huh?
|
||||
int pixelRight = pixelLeft + 8;
|
||||
|
||||
int amt = 0;
|
||||
for (int i = firstModY; i <= lastModY; i++) {
|
||||
if ((aaleft[i] > pixelRight) || (aaright[i] < pixelLeft)) {
|
||||
continue;
|
||||
}
|
||||
// does this need a +1 ?
|
||||
amt += ((aaright[i] < pixelRight ? aaright[i] : pixelRight) -
|
||||
(aaleft[i] > pixelLeft ? aaleft[i] : pixelLeft));
|
||||
}
|
||||
amt <<= 2;
|
||||
return (amt == 256) ? 255 : amt;
|
||||
}
|
||||
|
||||
|
||||
private void incrementalizeY(float p1[], float p2[],
|
||||
float p[], float dp[], int y) {
|
||||
float delta = p2[TY] - p1[TY];
|
||||
if (delta == 0) delta = 1;
|
||||
float fraction = y + 0.5f - p1[TY];
|
||||
|
||||
if (interpX) {
|
||||
dp[TX] = (p2[TX] - p1[TX]) / delta;
|
||||
p[TX] = p1[TX] + dp[TX] * fraction;
|
||||
}
|
||||
|
||||
if (interpARGB) {
|
||||
dp[R] = (p2[R] - p1[R]) / delta;
|
||||
dp[G] = (p2[G] - p1[G]) / delta;
|
||||
dp[B] = (p2[B] - p1[B]) / delta;
|
||||
dp[A] = (p2[A] - p1[A]) / delta;
|
||||
p[R] = p1[R] + dp[R] * fraction;
|
||||
p[G] = p1[G] + dp[G] * fraction;
|
||||
p[B] = p1[B] + dp[B] * fraction;
|
||||
p[A] = p1[A] + dp[A] * fraction;
|
||||
}
|
||||
|
||||
if (interpUV) {
|
||||
dp[U] = (p2[U] - p1[U]) / delta;
|
||||
dp[V] = (p2[V] - p1[V]) / delta;
|
||||
|
||||
p[U] = p1[U] + dp[U] * fraction;
|
||||
p[V] = p1[V] + dp[V] * fraction;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void incrementalizeX(float p1[], float p2[],
|
||||
float p[], float dp[], int x) {
|
||||
float delta = p2[TX] - p1[TX];
|
||||
if (delta == 0) delta = 1;
|
||||
float fraction = x + 0.5f - p1[TX];
|
||||
if (smooth) {
|
||||
delta /= SUBXRES;
|
||||
fraction /= SUBXRES;
|
||||
}
|
||||
|
||||
if (interpX) {
|
||||
dp[TX] = (p2[TX] - p1[TX]) / delta;
|
||||
p[TX] = p1[TX] + dp[TX] * fraction;
|
||||
}
|
||||
|
||||
if (interpARGB) {
|
||||
dp[R] = (p2[R] - p1[R]) / delta;
|
||||
dp[G] = (p2[G] - p1[G]) / delta;
|
||||
dp[B] = (p2[B] - p1[B]) / delta;
|
||||
dp[A] = (p2[A] - p1[A]) / delta;
|
||||
p[R] = p1[R] + dp[R] * fraction;
|
||||
p[G] = p1[G] + dp[G] * fraction;
|
||||
p[B] = p1[B] + dp[B] * fraction;
|
||||
p[A] = p1[A] + dp[A] * fraction;
|
||||
}
|
||||
|
||||
if (interpUV) {
|
||||
dp[U] = (p2[U] - p1[U]) / delta;
|
||||
dp[V] = (p2[V] - p1[V]) / delta;
|
||||
|
||||
p[U] = p1[U] + dp[U] * fraction;
|
||||
p[V] = p1[V] + dp[V] * fraction;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void increment(float p[], float dp[]) {
|
||||
if (interpX) p[TX] += dp[TX];
|
||||
|
||||
if (interpARGB) {
|
||||
p[R] += dp[R];
|
||||
p[G] += dp[G];
|
||||
p[B] += dp[B];
|
||||
p[A] += dp[A];
|
||||
}
|
||||
|
||||
if (interpUV) {
|
||||
p[U] += dp[U];
|
||||
p[V] += dp[V];
|
||||
}
|
||||
}
|
||||
}
|
842
core/src/processing/core/PShape.java
Normal file
842
core/src/processing/core/PShape.java
Normal file
@ -0,0 +1,842 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2006-08 Ben Fry and Casey Reas
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.core;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
|
||||
/**
|
||||
* In-progress class to handle shape data, currently to be considered of
|
||||
* alpha or beta quality. Major structural work may be performed on this class
|
||||
* after the release of Processing 1.0. Such changes may include:
|
||||
*
|
||||
* <ul>
|
||||
* <li> addition of proper accessors to read shape vertex and coloring data
|
||||
* (this is the second most important part of having a PShape class after all).
|
||||
* <li> a means of creating PShape objects ala beginShape() and endShape().
|
||||
* <li> load(), update(), and cache methods ala PImage, so that shapes can
|
||||
* have renderer-specific optimizations, such as vertex arrays in OpenGL.
|
||||
* <li> splitting this class into multiple classes to handle different
|
||||
* varieties of shape data (primitives vs collections of vertices vs paths)
|
||||
* <li> change of package declaration, for instance moving the code into
|
||||
* package processing.shape (if the code grows too much).
|
||||
* </ul>
|
||||
*
|
||||
* <p>For the time being, this class and its shape() and loadShape() friends in
|
||||
* PApplet exist as placeholders for more exciting things to come. If you'd
|
||||
* like to work with this class, make a subclass (see how PShapeSVG works)
|
||||
* and you can play with its internal methods all you like.</p>
|
||||
*
|
||||
* <p>Library developers are encouraged to create PShape objects when loading
|
||||
* shape data, so that they can eventually hook into the bounty that will be
|
||||
* the PShape interface, and the ease of loadShape() and shape().</p>
|
||||
*/
|
||||
public class PShape implements PConstants {
|
||||
|
||||
protected String name;
|
||||
protected HashMap<String,PShape> nameTable;
|
||||
|
||||
/** Generic, only draws its child objects. */
|
||||
static public final int GROUP = 0;
|
||||
/** A line, ellipse, arc, image, etc. */
|
||||
static public final int PRIMITIVE = 1;
|
||||
/** A series of vertex, curveVertex, and bezierVertex calls. */
|
||||
static public final int PATH = 2;
|
||||
/** Collections of vertices created with beginShape(). */
|
||||
static public final int GEOMETRY = 3;
|
||||
/** The shape type, one of GROUP, PRIMITIVE, PATH, or GEOMETRY. */
|
||||
protected int family;
|
||||
|
||||
/** ELLIPSE, LINE, QUAD; TRIANGLE_FAN, QUAD_STRIP; etc. */
|
||||
protected int kind;
|
||||
|
||||
protected PMatrix matrix;
|
||||
|
||||
/** Texture or image data associated with this shape. */
|
||||
protected PImage image;
|
||||
|
||||
// boundary box of this shape
|
||||
//protected float x;
|
||||
//protected float y;
|
||||
//protected float width;
|
||||
//protected float height;
|
||||
public float width;
|
||||
public float height;
|
||||
|
||||
// set to false if the object is hidden in the layers palette
|
||||
protected boolean visible = true;
|
||||
|
||||
protected boolean stroke;
|
||||
protected int strokeColor;
|
||||
protected float strokeWeight; // default is 1
|
||||
protected int strokeCap;
|
||||
protected int strokeJoin;
|
||||
|
||||
protected boolean fill;
|
||||
protected int fillColor;
|
||||
|
||||
/** Temporary toggle for whether styles should be honored. */
|
||||
protected boolean style = true;
|
||||
|
||||
/** For primitive shapes in particular, parms like x/y/w/h or x1/y1/x2/y2. */
|
||||
protected float[] params;
|
||||
|
||||
protected int vertexCount;
|
||||
/**
|
||||
* When drawing POLYGON shapes, the second param is an array of length
|
||||
* VERTEX_FIELD_COUNT. When drawing PATH shapes, the second param has only
|
||||
* two variables.
|
||||
*/
|
||||
protected float[][] vertices;
|
||||
|
||||
static public final int VERTEX = 0;
|
||||
static public final int BEZIER_VERTEX = 1;
|
||||
static public final int CURVE_VERTEX = 2;
|
||||
static public final int BREAK = 3;
|
||||
/** Array of VERTEX, BEZIER_VERTEX, and CURVE_VERTEXT calls. */
|
||||
protected int vertexCodeCount;
|
||||
protected int[] vertexCodes;
|
||||
/** True if this is a closed path. */
|
||||
protected boolean close;
|
||||
|
||||
// should this be called vertices (consistent with PGraphics internals)
|
||||
// or does that hurt flexibility?
|
||||
|
||||
protected PShape parent;
|
||||
protected int childCount;
|
||||
protected PShape[] children;
|
||||
|
||||
// POINTS, LINES, xLINE_STRIP, xLINE_LOOP
|
||||
// TRIANGLES, TRIANGLE_STRIP, TRIANGLE_FAN
|
||||
// QUADS, QUAD_STRIP
|
||||
// xPOLYGON
|
||||
// static final int PATH = 1; // POLYGON, LINE_LOOP, LINE_STRIP
|
||||
// static final int GROUP = 2;
|
||||
|
||||
// how to handle rectmode/ellipsemode?
|
||||
// are they bitshifted into the constant?
|
||||
// CORNER, CORNERS, CENTER, (CENTER_RADIUS?)
|
||||
// static final int RECT = 3; // could just be QUAD, but would be x1/y1/x2/y2
|
||||
// static final int ELLIPSE = 4;
|
||||
//
|
||||
// static final int VERTEX = 7;
|
||||
// static final int CURVE = 5;
|
||||
// static final int BEZIER = 6;
|
||||
|
||||
|
||||
// fill and stroke functions will need a pointer to the parent
|
||||
// PGraphics object.. may need some kind of createShape() fxn
|
||||
// or maybe the values are stored until draw() is called?
|
||||
|
||||
// attaching images is very tricky.. it's a different type of data
|
||||
|
||||
// material parameters will be thrown out,
|
||||
// except those currently supported (kinds of lights)
|
||||
|
||||
// pivot point for transformations
|
||||
// public float px;
|
||||
// public float py;
|
||||
|
||||
|
||||
public PShape() {
|
||||
this.family = GROUP;
|
||||
}
|
||||
|
||||
|
||||
public PShape(int family) {
|
||||
this.family = family;
|
||||
}
|
||||
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
public boolean isVisible() {
|
||||
return visible;
|
||||
}
|
||||
|
||||
|
||||
public void setVisible(boolean visible) {
|
||||
this.visible = visible;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overrides this shape's style information and uses PGraphics styles and
|
||||
* colors. Identical to ignoreStyles(true). Also disables styles for all
|
||||
* child shapes.
|
||||
*/
|
||||
public void disableStyle() {
|
||||
style = false;
|
||||
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
children[i].disableStyle();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Re-enables style information (fill and stroke) set in the shape.
|
||||
*/
|
||||
public void enableStyle() {
|
||||
style = true;
|
||||
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
children[i].enableStyle();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
|
||||
// protected void checkBounds() {
|
||||
// if (width == 0 || height == 0) {
|
||||
// // calculate bounds here (also take kids into account)
|
||||
// width = 1;
|
||||
// height = 1;
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
* Get the width of the drawing area (not necessarily the shape boundary).
|
||||
*/
|
||||
public float getWidth() {
|
||||
//checkBounds();
|
||||
return width;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the height of the drawing area (not necessarily the shape boundary).
|
||||
*/
|
||||
public float getHeight() {
|
||||
//checkBounds();
|
||||
return height;
|
||||
}
|
||||
|
||||
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
|
||||
/*
|
||||
boolean strokeSaved;
|
||||
int strokeColorSaved;
|
||||
float strokeWeightSaved;
|
||||
int strokeCapSaved;
|
||||
int strokeJoinSaved;
|
||||
|
||||
boolean fillSaved;
|
||||
int fillColorSaved;
|
||||
|
||||
int rectModeSaved;
|
||||
int ellipseModeSaved;
|
||||
int shapeModeSaved;
|
||||
*/
|
||||
|
||||
|
||||
protected void pre(PGraphics g) {
|
||||
if (matrix != null) {
|
||||
g.pushMatrix();
|
||||
g.applyMatrix(matrix);
|
||||
}
|
||||
|
||||
/*
|
||||
strokeSaved = g.stroke;
|
||||
strokeColorSaved = g.strokeColor;
|
||||
strokeWeightSaved = g.strokeWeight;
|
||||
strokeCapSaved = g.strokeCap;
|
||||
strokeJoinSaved = g.strokeJoin;
|
||||
|
||||
fillSaved = g.fill;
|
||||
fillColorSaved = g.fillColor;
|
||||
|
||||
rectModeSaved = g.rectMode;
|
||||
ellipseModeSaved = g.ellipseMode;
|
||||
shapeModeSaved = g.shapeMode;
|
||||
*/
|
||||
if (style) {
|
||||
g.pushStyle();
|
||||
styles(g);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void styles(PGraphics g) {
|
||||
// should not be necessary because using only the int version of color
|
||||
//parent.colorMode(PConstants.RGB, 255);
|
||||
|
||||
if (stroke) {
|
||||
g.stroke(strokeColor);
|
||||
g.strokeWeight(strokeWeight);
|
||||
g.strokeCap(strokeCap);
|
||||
g.strokeJoin(strokeJoin);
|
||||
} else {
|
||||
g.noStroke();
|
||||
}
|
||||
|
||||
if (fill) {
|
||||
//System.out.println("filling " + PApplet.hex(fillColor));
|
||||
g.fill(fillColor);
|
||||
} else {
|
||||
g.noFill();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void post(PGraphics g) {
|
||||
// for (int i = 0; i < childCount; i++) {
|
||||
// children[i].draw(g);
|
||||
// }
|
||||
|
||||
/*
|
||||
// TODO this is not sufficient, since not saving fillR et al.
|
||||
g.stroke = strokeSaved;
|
||||
g.strokeColor = strokeColorSaved;
|
||||
g.strokeWeight = strokeWeightSaved;
|
||||
g.strokeCap = strokeCapSaved;
|
||||
g.strokeJoin = strokeJoinSaved;
|
||||
|
||||
g.fill = fillSaved;
|
||||
g.fillColor = fillColorSaved;
|
||||
|
||||
g.ellipseMode = ellipseModeSaved;
|
||||
*/
|
||||
|
||||
if (matrix != null) {
|
||||
g.popMatrix();
|
||||
}
|
||||
|
||||
if (style) {
|
||||
g.popStyle();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called by the following (the shape() command adds the g)
|
||||
* PShape s = loadShapes("blah.svg");
|
||||
* shape(s);
|
||||
*/
|
||||
public void draw(PGraphics g) {
|
||||
if (visible) {
|
||||
pre(g);
|
||||
drawImpl(g);
|
||||
post(g);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Draws the SVG document.
|
||||
*/
|
||||
public void drawImpl(PGraphics g) {
|
||||
//System.out.println("drawing " + family);
|
||||
if (family == GROUP) {
|
||||
drawGroup(g);
|
||||
} else if (family == PRIMITIVE) {
|
||||
drawPrimitive(g);
|
||||
} else if (family == GEOMETRY) {
|
||||
drawGeometry(g);
|
||||
} else if (family == PATH) {
|
||||
drawPath(g);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void drawGroup(PGraphics g) {
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
children[i].draw(g);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void drawPrimitive(PGraphics g) {
|
||||
if (kind == POINT) {
|
||||
g.point(params[0], params[1]);
|
||||
|
||||
} else if (kind == LINE) {
|
||||
if (params.length == 4) { // 2D
|
||||
g.line(params[0], params[1],
|
||||
params[2], params[3]);
|
||||
} else { // 3D
|
||||
g.line(params[0], params[1], params[2],
|
||||
params[3], params[4], params[5]);
|
||||
}
|
||||
|
||||
} else if (kind == TRIANGLE) {
|
||||
g.triangle(params[0], params[1],
|
||||
params[2], params[3],
|
||||
params[4], params[5]);
|
||||
|
||||
} else if (kind == QUAD) {
|
||||
g.quad(params[0], params[1],
|
||||
params[2], params[3],
|
||||
params[4], params[5],
|
||||
params[6], params[7]);
|
||||
|
||||
} else if (kind == RECT) {
|
||||
if (image != null) {
|
||||
g.imageMode(CORNER);
|
||||
g.image(image, params[0], params[1], params[2], params[3]);
|
||||
} else {
|
||||
g.rectMode(CORNER);
|
||||
g.rect(params[0], params[1], params[2], params[3]);
|
||||
}
|
||||
|
||||
} else if (kind == ELLIPSE) {
|
||||
g.ellipseMode(CORNER);
|
||||
g.ellipse(params[0], params[1], params[2], params[3]);
|
||||
|
||||
} else if (kind == ARC) {
|
||||
g.ellipseMode(CORNER);
|
||||
g.arc(params[0], params[1], params[2], params[3], params[4], params[5]);
|
||||
|
||||
} else if (kind == BOX) {
|
||||
if (params.length == 1) {
|
||||
g.box(params[0]);
|
||||
} else {
|
||||
g.box(params[0], params[1], params[2]);
|
||||
}
|
||||
|
||||
} else if (kind == SPHERE) {
|
||||
g.sphere(params[0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void drawGeometry(PGraphics g) {
|
||||
g.beginShape(kind);
|
||||
if (style) {
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
g.vertex(vertices[i]);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
float[] vert = vertices[i];
|
||||
if (vert[PGraphics.Z] == 0) {
|
||||
g.vertex(vert[X], vert[Y]);
|
||||
} else {
|
||||
g.vertex(vert[X], vert[Y], vert[Z]);
|
||||
}
|
||||
}
|
||||
}
|
||||
g.endShape();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
protected void drawPath(PGraphics g) {
|
||||
g.beginShape();
|
||||
for (int j = 0; j < childCount; j++) {
|
||||
if (j > 0) g.breakShape();
|
||||
int count = children[j].vertexCount;
|
||||
float[][] vert = children[j].vertices;
|
||||
int[] code = children[j].vertexCodes;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (style) {
|
||||
if (children[j].fill) {
|
||||
g.fill(vert[i][R], vert[i][G], vert[i][B]);
|
||||
} else {
|
||||
g.noFill();
|
||||
}
|
||||
if (children[j].stroke) {
|
||||
g.stroke(vert[i][R], vert[i][G], vert[i][B]);
|
||||
} else {
|
||||
g.noStroke();
|
||||
}
|
||||
}
|
||||
g.edge(vert[i][EDGE] == 1);
|
||||
|
||||
if (code[i] == VERTEX) {
|
||||
g.vertex(vert[i]);
|
||||
|
||||
} else if (code[i] == BEZIER_VERTEX) {
|
||||
float z0 = vert[i+0][Z];
|
||||
float z1 = vert[i+1][Z];
|
||||
float z2 = vert[i+2][Z];
|
||||
if (z0 == 0 && z1 == 0 && z2 == 0) {
|
||||
g.bezierVertex(vert[i+0][X], vert[i+0][Y], z0,
|
||||
vert[i+1][X], vert[i+1][Y], z1,
|
||||
vert[i+2][X], vert[i+2][Y], z2);
|
||||
} else {
|
||||
g.bezierVertex(vert[i+0][X], vert[i+0][Y],
|
||||
vert[i+1][X], vert[i+1][Y],
|
||||
vert[i+2][X], vert[i+2][Y]);
|
||||
}
|
||||
} else if (code[i] == CURVE_VERTEX) {
|
||||
float z = vert[i][Z];
|
||||
if (z == 0) {
|
||||
g.curveVertex(vert[i][X], vert[i][Y]);
|
||||
} else {
|
||||
g.curveVertex(vert[i][X], vert[i][Y], z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
g.endShape();
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
protected void drawPath(PGraphics g) {
|
||||
// Paths might be empty (go figure)
|
||||
// http://dev.processing.org/bugs/show_bug.cgi?id=982
|
||||
if (vertices == null) return;
|
||||
|
||||
g.beginShape();
|
||||
|
||||
if (vertexCodeCount == 0) { // each point is a simple vertex
|
||||
if (vertices[0].length == 2) { // drawing 2D vertices
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
g.vertex(vertices[i][X], vertices[i][Y]);
|
||||
}
|
||||
} else { // drawing 3D vertices
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
g.vertex(vertices[i][X], vertices[i][Y], vertices[i][Z]);
|
||||
}
|
||||
}
|
||||
|
||||
} else { // coded set of vertices
|
||||
int index = 0;
|
||||
|
||||
if (vertices[0].length == 2) { // drawing a 2D path
|
||||
for (int j = 0; j < vertexCodeCount; j++) {
|
||||
switch (vertexCodes[j]) {
|
||||
|
||||
case VERTEX:
|
||||
g.vertex(vertices[index][X], vertices[index][Y]);
|
||||
index++;
|
||||
break;
|
||||
|
||||
case BEZIER_VERTEX:
|
||||
g.bezierVertex(vertices[index+0][X], vertices[index+0][Y],
|
||||
vertices[index+1][X], vertices[index+1][Y],
|
||||
vertices[index+2][X], vertices[index+2][Y]);
|
||||
index += 3;
|
||||
break;
|
||||
|
||||
case CURVE_VERTEX:
|
||||
g.curveVertex(vertices[index][X], vertices[index][Y]);
|
||||
index++;
|
||||
|
||||
case BREAK:
|
||||
g.breakShape();
|
||||
}
|
||||
}
|
||||
} else { // drawing a 3D path
|
||||
for (int j = 0; j < vertexCodeCount; j++) {
|
||||
switch (vertexCodes[j]) {
|
||||
|
||||
case VERTEX:
|
||||
g.vertex(vertices[index][X], vertices[index][Y], vertices[index][Z]);
|
||||
index++;
|
||||
break;
|
||||
|
||||
case BEZIER_VERTEX:
|
||||
g.bezierVertex(vertices[index+0][X], vertices[index+0][Y], vertices[index+0][Z],
|
||||
vertices[index+1][X], vertices[index+1][Y], vertices[index+1][Z],
|
||||
vertices[index+2][X], vertices[index+2][Y], vertices[index+2][Z]);
|
||||
index += 3;
|
||||
break;
|
||||
|
||||
case CURVE_VERTEX:
|
||||
g.curveVertex(vertices[index][X], vertices[index][Y], vertices[index][Z]);
|
||||
index++;
|
||||
|
||||
case BREAK:
|
||||
g.breakShape();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
g.endShape(close ? CLOSE : OPEN);
|
||||
}
|
||||
|
||||
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
|
||||
public int getChildCount() {
|
||||
return childCount;
|
||||
}
|
||||
|
||||
|
||||
public PShape getChild(int index) {
|
||||
return children[index];
|
||||
}
|
||||
|
||||
|
||||
public PShape getChild(String target) {
|
||||
if (name != null && name.equals(target)) {
|
||||
return this;
|
||||
}
|
||||
if (nameTable != null) {
|
||||
PShape found = nameTable.get(target);
|
||||
if (found != null) return found;
|
||||
}
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
PShape found = children[i].getChild(target);
|
||||
if (found != null) return found;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Same as getChild(name), except that it first walks all the way up the
|
||||
* hierarchy to the farthest parent, so that children can be found anywhere.
|
||||
*/
|
||||
public PShape findChild(String target) {
|
||||
if (parent == null) {
|
||||
return getChild(target);
|
||||
|
||||
} else {
|
||||
return parent.findChild(target);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// can't be just 'add' because that suggests additive geometry
|
||||
public void addChild(PShape who) {
|
||||
if (children == null) {
|
||||
children = new PShape[1];
|
||||
}
|
||||
if (childCount == children.length) {
|
||||
children = (PShape[]) PApplet.expand(children);
|
||||
}
|
||||
children[childCount++] = who;
|
||||
who.parent = this;
|
||||
|
||||
if (who.getName() != null) {
|
||||
addName(who.getName(), who);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a shape to the name lookup table.
|
||||
*/
|
||||
protected void addName(String nom, PShape shape) {
|
||||
if (parent != null) {
|
||||
parent.addName(nom, shape);
|
||||
} else {
|
||||
if (nameTable == null) {
|
||||
nameTable = new HashMap<String,PShape>();
|
||||
}
|
||||
nameTable.put(nom, shape);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// public PShape createGroup() {
|
||||
// PShape group = new PShape();
|
||||
// group.kind = GROUP;
|
||||
// addChild(group);
|
||||
// return group;
|
||||
// }
|
||||
|
||||
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
|
||||
// translate, rotate, scale, apply (no push/pop)
|
||||
// these each call matrix.translate, etc
|
||||
// if matrix is null when one is called,
|
||||
// it is created and set to identity
|
||||
|
||||
|
||||
public void translate(float tx, float ty) {
|
||||
checkMatrix(2);
|
||||
matrix.translate(tx, ty);
|
||||
}
|
||||
|
||||
|
||||
public void translate(float tx, float ty, float tz) {
|
||||
checkMatrix(3);
|
||||
matrix.translate(tx, ty, 0);
|
||||
}
|
||||
|
||||
|
||||
public void rotateX(float angle) {
|
||||
rotate(angle, 1, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
public void rotateY(float angle) {
|
||||
rotate(angle, 0, 1, 0);
|
||||
}
|
||||
|
||||
|
||||
public void rotateZ(float angle) {
|
||||
rotate(angle, 0, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
public void rotate(float angle) {
|
||||
checkMatrix(2); // at least 2...
|
||||
matrix.rotate(angle);
|
||||
}
|
||||
|
||||
|
||||
public void rotate(float angle, float v0, float v1, float v2) {
|
||||
checkMatrix(3);
|
||||
matrix.rotate(angle, v0, v1, v2);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
|
||||
|
||||
public void scale(float s) {
|
||||
checkMatrix(2); // at least 2...
|
||||
matrix.scale(s);
|
||||
}
|
||||
|
||||
|
||||
public void scale(float sx, float sy) {
|
||||
checkMatrix(2);
|
||||
matrix.scale(sx, sy);
|
||||
}
|
||||
|
||||
|
||||
public void scale(float x, float y, float z) {
|
||||
checkMatrix(3);
|
||||
matrix.scale(x, y, z);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
|
||||
|
||||
public void resetMatrix() {
|
||||
checkMatrix(2);
|
||||
matrix.reset();
|
||||
}
|
||||
|
||||
|
||||
public void applyMatrix(PMatrix source) {
|
||||
if (source instanceof PMatrix2D) {
|
||||
applyMatrix((PMatrix2D) source);
|
||||
} else if (source instanceof PMatrix3D) {
|
||||
applyMatrix((PMatrix3D) source);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void applyMatrix(PMatrix2D source) {
|
||||
applyMatrix(source.m00, source.m01, 0, source.m02,
|
||||
source.m10, source.m11, 0, source.m12,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
public void applyMatrix(float n00, float n01, float n02,
|
||||
float n10, float n11, float n12) {
|
||||
checkMatrix(2);
|
||||
matrix.apply(n00, n01, n02, 0,
|
||||
n10, n11, n12, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
public void apply(PMatrix3D source) {
|
||||
applyMatrix(source.m00, source.m01, source.m02, source.m03,
|
||||
source.m10, source.m11, source.m12, source.m13,
|
||||
source.m20, source.m21, source.m22, source.m23,
|
||||
source.m30, source.m31, source.m32, source.m33);
|
||||
}
|
||||
|
||||
|
||||
public void applyMatrix(float n00, float n01, float n02, float n03,
|
||||
float n10, float n11, float n12, float n13,
|
||||
float n20, float n21, float n22, float n23,
|
||||
float n30, float n31, float n32, float n33) {
|
||||
checkMatrix(3);
|
||||
matrix.apply(n00, n01, n02, n03,
|
||||
n10, n11, n12, n13,
|
||||
n20, n21, n22, n23,
|
||||
n30, n31, n32, n33);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* Make sure that the shape's matrix is 1) not null, and 2) has a matrix
|
||||
* that can handle <em>at least</em> the specified number of dimensions.
|
||||
*/
|
||||
protected void checkMatrix(int dimensions) {
|
||||
if (matrix == null) {
|
||||
if (dimensions == 2) {
|
||||
matrix = new PMatrix2D();
|
||||
} else {
|
||||
matrix = new PMatrix3D();
|
||||
}
|
||||
} else if (dimensions == 3 && (matrix instanceof PMatrix2D)) {
|
||||
// time for an upgrayedd for a double dose of my pimpin'
|
||||
matrix = new PMatrix3D(matrix);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
|
||||
/**
|
||||
* Center the shape based on its bounding box. Can't assume
|
||||
* that the bounding box is 0, 0, width, height. Common case will be
|
||||
* opening a letter size document in Illustrator, and drawing something
|
||||
* in the middle, then reading it in as an svg file.
|
||||
* This will also need to flip the y axis (scale(1, -1)) in cases
|
||||
* like Adobe Illustrator where the coordinates start at the bottom.
|
||||
*/
|
||||
// public void center() {
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
* Set the pivot point for all transformations.
|
||||
*/
|
||||
// public void pivot(float x, float y) {
|
||||
// px = x;
|
||||
// py = y;
|
||||
// }
|
||||
|
||||
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
}
|
1469
core/src/processing/core/PShapeSVG.java
Normal file
1469
core/src/processing/core/PShapeSVG.java
Normal file
File diff suppressed because it is too large
Load Diff
968
core/src/processing/core/PSmoothTriangle.java
Normal file
968
core/src/processing/core/PSmoothTriangle.java
Normal file
@ -0,0 +1,968 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2004-08 Ben Fry and Casey Reas
|
||||
Copyright (c) 2001-04 Massachusetts Institute of Technology
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.core;
|
||||
|
||||
|
||||
/**
|
||||
* Smoothed triangle renderer for P3D.
|
||||
*
|
||||
* Based off of the PPolygon class in old versions of Processing.
|
||||
* Name and location of this class will change in a future release.
|
||||
*/
|
||||
public class PSmoothTriangle implements PConstants {
|
||||
|
||||
// really this is "debug" but..
|
||||
private static final boolean EWJORDAN = false;
|
||||
private static final boolean FRY = false;
|
||||
|
||||
// identical to the constants from PGraphics
|
||||
|
||||
static final int X = 0; // transformed xyzw
|
||||
static final int Y = 1; // formerly SX SY SZ
|
||||
static final int Z = 2;
|
||||
|
||||
static final int R = 3; // actual rgb, after lighting
|
||||
static final int G = 4; // fill stored here, transform in place
|
||||
static final int B = 5;
|
||||
static final int A = 6;
|
||||
|
||||
static final int U = 7; // texture
|
||||
static final int V = 8;
|
||||
|
||||
static final int DEFAULT_SIZE = 64; // this is needed for spheres
|
||||
float vertices[][] = new float[DEFAULT_SIZE][PGraphics.VERTEX_FIELD_COUNT];
|
||||
int vertexCount;
|
||||
|
||||
|
||||
// after some fiddling, this seems to produce the best results
|
||||
static final int ZBUFFER_MIN_COVERAGE = 204;
|
||||
|
||||
float r[] = new float[DEFAULT_SIZE]; // storage used by incrementalize
|
||||
float dr[] = new float[DEFAULT_SIZE];
|
||||
float l[] = new float[DEFAULT_SIZE]; // more storage for incrementalize
|
||||
float dl[] = new float[DEFAULT_SIZE];
|
||||
float sp[] = new float[DEFAULT_SIZE]; // temporary storage for scanline
|
||||
float sdp[] = new float[DEFAULT_SIZE];
|
||||
|
||||
// color and xyz are always interpolated
|
||||
boolean interpX;
|
||||
boolean interpZ;
|
||||
boolean interpUV; // is this necessary? could just check timage != null
|
||||
boolean interpARGB;
|
||||
|
||||
int rgba;
|
||||
int r2, g2, b2, a2, a2orig;
|
||||
|
||||
boolean noDepthTest;
|
||||
|
||||
PGraphics3D parent;
|
||||
int pixels[];
|
||||
float[] zbuffer;
|
||||
|
||||
// the parent's width/height,
|
||||
// or if smooth is enabled, parent's w/h scaled
|
||||
// up by the smooth dimension
|
||||
int width, height;
|
||||
int width1, height1;
|
||||
|
||||
PImage timage;
|
||||
int tpixels[];
|
||||
int theight, twidth;
|
||||
int theight1, twidth1;
|
||||
int tformat;
|
||||
|
||||
// temp fix to behave like SMOOTH_IMAGES
|
||||
// TODO ewjordan: can probably remove this variable
|
||||
boolean texture_smooth;
|
||||
|
||||
// for anti-aliasing
|
||||
static final int SUBXRES = 8;
|
||||
static final int SUBXRES1 = 7;
|
||||
static final int SUBYRES = 8;
|
||||
static final int SUBYRES1 = 7;
|
||||
static final int MAX_COVERAGE = SUBXRES * SUBYRES;
|
||||
|
||||
boolean smooth;
|
||||
int firstModY;
|
||||
int lastModY;
|
||||
int lastY;
|
||||
int aaleft[] = new int[SUBYRES];
|
||||
int aaright[] = new int[SUBYRES];
|
||||
int aaleftmin, aarightmin;
|
||||
int aaleftmax, aarightmax;
|
||||
int aaleftfull, aarightfull;
|
||||
|
||||
/* Variables needed for accurate texturing. */
|
||||
//private PMatrix textureMatrix = new PMatrix3D();
|
||||
private float[] camX = new float[3];
|
||||
private float[] camY = new float[3];
|
||||
private float[] camZ = new float[3];
|
||||
private float ax,ay,az;
|
||||
private float bx,by,bz;
|
||||
private float cx,cy,cz;
|
||||
private float nearPlaneWidth, nearPlaneHeight, nearPlaneDepth;
|
||||
//private float newax, newbx, newcx;
|
||||
private float xmult, ymult;
|
||||
|
||||
|
||||
final private int MODYRES(int y) {
|
||||
return (y & SUBYRES1);
|
||||
}
|
||||
|
||||
|
||||
public PSmoothTriangle(PGraphics3D iparent) {
|
||||
parent = iparent;
|
||||
reset(0);
|
||||
}
|
||||
|
||||
|
||||
public void reset(int count) {
|
||||
vertexCount = count;
|
||||
interpX = true;
|
||||
interpZ = true;
|
||||
interpUV = false;
|
||||
interpARGB = true;
|
||||
timage = null;
|
||||
}
|
||||
|
||||
|
||||
public float[] nextVertex() {
|
||||
if (vertexCount == vertices.length) {
|
||||
//parent.message(CHATTER, "re-allocating for " +
|
||||
// (vertexCount*2) + " vertices");
|
||||
float temp[][] = new float[vertexCount<<1][PGraphics.VERTEX_FIELD_COUNT];
|
||||
System.arraycopy(vertices, 0, temp, 0, vertexCount);
|
||||
vertices = temp;
|
||||
|
||||
r = new float[vertices.length];
|
||||
dr = new float[vertices.length];
|
||||
l = new float[vertices.length];
|
||||
dl = new float[vertices.length];
|
||||
sp = new float[vertices.length];
|
||||
sdp = new float[vertices.length];
|
||||
}
|
||||
return vertices[vertexCount++]; // returns v[0], sets vc to 1
|
||||
}
|
||||
|
||||
|
||||
public void texture(PImage image) {
|
||||
this.timage = image;
|
||||
this.tpixels = image.pixels;
|
||||
this.twidth = image.width;
|
||||
this.theight = image.height;
|
||||
this.tformat = image.format;
|
||||
|
||||
twidth1 = twidth - 1;
|
||||
theight1 = theight - 1;
|
||||
interpUV = true;
|
||||
}
|
||||
|
||||
public void render() {
|
||||
if (vertexCount < 3) return;
|
||||
|
||||
smooth = true;//TODO
|
||||
// these may have changed due to a resize()
|
||||
// so they should be refreshed here
|
||||
pixels = parent.pixels;
|
||||
zbuffer = parent.zbuffer;
|
||||
|
||||
noDepthTest = false;//parent.hints[DISABLE_DEPTH_TEST];
|
||||
|
||||
// In 0148+, should always be true if this code is called at all
|
||||
//smooth = parent.smooth;
|
||||
|
||||
// by default, text turns on smooth for the textures
|
||||
// themselves. but this should be shut off if the hint
|
||||
// for DISABLE_TEXT_SMOOTH is set.
|
||||
texture_smooth = true;
|
||||
|
||||
width = smooth ? parent.width*SUBXRES : parent.width;
|
||||
height = smooth ? parent.height*SUBYRES : parent.height;
|
||||
|
||||
width1 = width - 1;
|
||||
height1 = height - 1;
|
||||
|
||||
if (!interpARGB) {
|
||||
r2 = (int) (vertices[0][R] * 255);
|
||||
g2 = (int) (vertices[0][G] * 255);
|
||||
b2 = (int) (vertices[0][B] * 255);
|
||||
a2 = (int) (vertices[0][A] * 255);
|
||||
a2orig = a2; // save an extra copy
|
||||
rgba = 0xff000000 | (r2 << 16) | (g2 << 8) | b2;
|
||||
}
|
||||
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
r[i] = 0; dr[i] = 0; l[i] = 0; dl[i] = 0;
|
||||
}
|
||||
|
||||
if (smooth) {
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
vertices[i][X] *= SUBXRES;
|
||||
vertices[i][Y] *= SUBYRES;
|
||||
}
|
||||
firstModY = -1;
|
||||
}
|
||||
|
||||
// find top vertex (y is zero at top, higher downwards)
|
||||
int topi = 0;
|
||||
float ymin = vertices[0][Y];
|
||||
float ymax = vertices[0][Y]; // fry 031001
|
||||
for (int i = 1; i < vertexCount; i++) {
|
||||
if (vertices[i][Y] < ymin) {
|
||||
ymin = vertices[i][Y];
|
||||
topi = i;
|
||||
}
|
||||
if (vertices[i][Y] > ymax) ymax = vertices[i][Y];
|
||||
}
|
||||
|
||||
// the last row is an exceptional case, because there won't
|
||||
// necessarily be 8 rows of subpixel lines that will force
|
||||
// the final line to render. so instead, the algo keeps track
|
||||
// of the lastY (in subpixel resolution) that will be rendered
|
||||
// and that will force a scanline to happen the same as
|
||||
// every eighth in the other situations
|
||||
//lastY = -1; // fry 031001
|
||||
lastY = (int) (ymax - 0.5f); // global to class bc used by other fxns
|
||||
|
||||
int lefti = topi; // li, index of left vertex
|
||||
int righti = topi; // ri, index of right vertex
|
||||
int y = (int) (ymin + 0.5f); // current scan line
|
||||
int lefty = y - 1; // lower end of left edge
|
||||
int righty = y - 1; // lower end of right edge
|
||||
|
||||
interpX = true;
|
||||
|
||||
int remaining = vertexCount;
|
||||
|
||||
// scan in y, activating new edges on left & right
|
||||
// as scan line passes over new vertices
|
||||
while (remaining > 0) {
|
||||
// advance left edge?
|
||||
while ((lefty <= y) && (remaining > 0)) {
|
||||
remaining--;
|
||||
// step ccw down left side
|
||||
int i = (lefti != 0) ? (lefti-1) : (vertexCount-1);
|
||||
incrementalize_y(vertices[lefti], vertices[i], l, dl, y);
|
||||
lefty = (int) (vertices[i][Y] + 0.5f);
|
||||
lefti = i;
|
||||
}
|
||||
|
||||
// advance right edge?
|
||||
while ((righty <= y) && (remaining > 0)) {
|
||||
remaining--;
|
||||
// step cw down right edge
|
||||
int i = (righti != vertexCount-1) ? (righti + 1) : 0;
|
||||
incrementalize_y(vertices[righti], vertices[i], r, dr, y);
|
||||
righty = (int) (vertices[i][Y] + 0.5f);
|
||||
righti = i;
|
||||
}
|
||||
|
||||
// do scanlines till end of l or r edge
|
||||
while (y < lefty && y < righty) {
|
||||
// this doesn't work because it's not always set here
|
||||
//if (remaining == 0) {
|
||||
//lastY = (lefty < righty) ? lefty-1 : righty-1;
|
||||
//System.out.println("lastY is " + lastY);
|
||||
//}
|
||||
|
||||
if ((y >= 0) && (y < height)) {
|
||||
//try { // hopefully this bug is fixed
|
||||
if (l[X] <= r[X]) scanline(y, l, r);
|
||||
else scanline(y, r, l);
|
||||
//} catch (ArrayIndexOutOfBoundsException e) {
|
||||
//e.printStackTrace();
|
||||
//}
|
||||
}
|
||||
y++;
|
||||
// this increment probably needs to be different
|
||||
// UV and RGB shouldn't be incremented until line is emitted
|
||||
increment(l, dl);
|
||||
increment(r, dr);
|
||||
}
|
||||
}
|
||||
//if (smooth) {
|
||||
//System.out.println("y/lasty/lastmody = " + y + " " + lastY + " " + lastModY);
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
public void unexpand() {
|
||||
if (smooth) {
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
vertices[i][X] /= SUBXRES;
|
||||
vertices[i][Y] /= SUBYRES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void scanline(int y, float l[], float r[]) {
|
||||
//System.out.println("scanline " + y);
|
||||
for (int i = 0; i < vertexCount; i++) { // should be moved later
|
||||
sp[i] = 0; sdp[i] = 0;
|
||||
}
|
||||
|
||||
// this rounding doesn't seem to be relevant with smooth
|
||||
int lx = (int) (l[X] + 0.49999f); // ceil(l[X]-.5);
|
||||
if (lx < 0) lx = 0;
|
||||
int rx = (int) (r[X] - 0.5f);
|
||||
if (rx > width1) rx = width1;
|
||||
|
||||
if (lx > rx) return;
|
||||
|
||||
if (smooth) {
|
||||
int mody = MODYRES(y);
|
||||
|
||||
aaleft[mody] = lx;
|
||||
aaright[mody] = rx;
|
||||
|
||||
if (firstModY == -1) {
|
||||
firstModY = mody;
|
||||
aaleftmin = lx; aaleftmax = lx;
|
||||
aarightmin = rx; aarightmax = rx;
|
||||
|
||||
} else {
|
||||
if (aaleftmin > aaleft[mody]) aaleftmin = aaleft[mody];
|
||||
if (aaleftmax < aaleft[mody]) aaleftmax = aaleft[mody];
|
||||
if (aarightmin > aaright[mody]) aarightmin = aaright[mody];
|
||||
if (aarightmax < aaright[mody]) aarightmax = aaright[mody];
|
||||
}
|
||||
|
||||
lastModY = mody; // moved up here (before the return) 031001
|
||||
// not the eighth (or lastY) line, so not scanning this time
|
||||
if ((mody != SUBYRES1) && (y != lastY)) return;
|
||||
//lastModY = mody; // eeK! this was missing
|
||||
//return;
|
||||
|
||||
//if (y == lastY) {
|
||||
//System.out.println("y is lasty");
|
||||
//}
|
||||
//lastModY = mody;
|
||||
aaleftfull = aaleftmax/SUBXRES + 1;
|
||||
aarightfull = aarightmin/SUBXRES - 1;
|
||||
}
|
||||
|
||||
// this is the setup, based on lx
|
||||
incrementalize_x(l, r, sp, sdp, lx);
|
||||
//System.out.println(l[V] + " " + r[V] + " " +sp[V] + " " +sdp[V]);
|
||||
|
||||
// scan in x, generating pixels
|
||||
// using parent.width to get actual pixel index
|
||||
// rather than scaled by smooth factor
|
||||
int offset = smooth ? parent.width * (y / SUBYRES) : parent.width*y;
|
||||
|
||||
int truelx = 0, truerx = 0;
|
||||
if (smooth) {
|
||||
truelx = lx / SUBXRES;
|
||||
truerx = (rx + SUBXRES1) / SUBXRES;
|
||||
|
||||
lx = aaleftmin / SUBXRES;
|
||||
rx = (aarightmax + SUBXRES1) / SUBXRES;
|
||||
if (lx < 0) lx = 0;
|
||||
if (rx > parent.width1) rx = parent.width1;
|
||||
}
|
||||
|
||||
// System.out.println("P3D interp uv " + interpUV + " " +
|
||||
// vertices[2][U] + " " + vertices[2][V]);
|
||||
|
||||
interpX = false;
|
||||
int tr, tg, tb, ta;
|
||||
//System.out.println("lx: "+lx + "\nrx: "+rx);
|
||||
for (int x = lx; x <= rx; x++) {
|
||||
|
||||
// added == because things on same plane weren't replacing each other
|
||||
// makes for strangeness in 3D [ewj: yup!], but totally necessary for 2D
|
||||
//if (noDepthTest || (sp[Z] < zbuffer[offset+x])) {
|
||||
if (noDepthTest || (sp[Z] <= zbuffer[offset+x])) {
|
||||
//if (true) {
|
||||
|
||||
// map texture based on U, V coords in sp[U] and sp[V]
|
||||
if (interpUV) {
|
||||
int tu = (int)sp[U];
|
||||
int tv = (int)sp[V];
|
||||
|
||||
if (tu > twidth1) tu = twidth1;
|
||||
if (tv > theight1) tv = theight1;
|
||||
if (tu < 0) tu = 0;
|
||||
if (tv < 0) tv = 0;
|
||||
|
||||
int txy = tv*twidth + tu;
|
||||
//System.out.println("tu: "+tu+" ; tv: "+tv+" ; txy: "+txy);
|
||||
float[] uv = new float[2];
|
||||
txy = getTextureIndex(x, y*1.0f/SUBYRES, uv);
|
||||
// txy = getTextureIndex(x* 1.0f/SUBXRES, y*1.0f/SUBYRES, uv);
|
||||
|
||||
tu = (int)uv[0]; tv = (int)uv[1];
|
||||
// if (tu > twidth1) tu = twidth1;
|
||||
// if (tv > theight1) tv = theight1;
|
||||
// if (tu < 0) tu = 0;
|
||||
// if (tv < 0) tv = 0;
|
||||
txy = twidth*tv + tu;
|
||||
// if (EWJORDAN) System.out.println("x/y/txy:"+x + " " + y + " " +txy);
|
||||
//PApplet.println(sp);
|
||||
|
||||
//smooth = true;
|
||||
if (smooth || texture_smooth) {
|
||||
//if (FRY) System.out.println("sp u v = " + sp[U] + " " + sp[V]);
|
||||
//System.out.println("sp u v = " + sp[U] + " " + sp[V]);
|
||||
// tuf1/tvf1 is the amount of coverage for the adjacent
|
||||
// pixel, which is the decimal percentage.
|
||||
// int tuf1 = (int) (255f * (sp[U] - (float)tu));
|
||||
// int tvf1 = (int) (255f * (sp[V] - (float)tv));
|
||||
|
||||
int tuf1 = (int) (255f * (uv[0] - tu));
|
||||
int tvf1 = (int) (255f * (uv[1] - tv));
|
||||
|
||||
// the closer sp[U or V] is to the decimal being zero
|
||||
// the more coverage it should get of the original pixel
|
||||
int tuf = 255 - tuf1;
|
||||
int tvf = 255 - tvf1;
|
||||
|
||||
// this code sucks! filled with bugs and slow as hell!
|
||||
int pixel00 = tpixels[txy];
|
||||
int pixel01 = (tv < theight1) ? tpixels[txy + twidth] : tpixels[txy];
|
||||
int pixel10 = (tu < twidth1) ? tpixels[txy + 1] : tpixels[txy];
|
||||
int pixel11 = ((tv < theight1) && (tu < twidth1)) ? tpixels[txy + twidth + 1] : tpixels[txy];
|
||||
//System.out.println("1: "+pixel00);
|
||||
//check
|
||||
int p00, p01, p10, p11;
|
||||
int px0, px1; //, pxy;
|
||||
|
||||
if (tformat == ALPHA) {
|
||||
px0 = (pixel00*tuf + pixel10*tuf1) >> 8;
|
||||
px1 = (pixel01*tuf + pixel11*tuf1) >> 8;
|
||||
ta = (((px0*tvf + px1*tvf1) >> 8) *
|
||||
(interpARGB ? ((int) (sp[A]*255)) : a2orig)) >> 8;
|
||||
} else if (tformat == ARGB) {
|
||||
p00 = (pixel00 >> 24) & 0xff;
|
||||
p01 = (pixel01 >> 24) & 0xff;
|
||||
p10 = (pixel10 >> 24) & 0xff;
|
||||
p11 = (pixel11 >> 24) & 0xff;
|
||||
|
||||
px0 = (p00*tuf + p10*tuf1) >> 8;
|
||||
px1 = (p01*tuf + p11*tuf1) >> 8;
|
||||
ta = (((px0*tvf + px1*tvf1) >> 8) *
|
||||
(interpARGB ? ((int) (sp[A]*255)) : a2orig)) >> 8;
|
||||
} else { // RGB image, no alpha
|
||||
//ACCTEX: Getting here when smooth is on
|
||||
ta = interpARGB ? ((int) (sp[A]*255)) : a2orig;
|
||||
//System.out.println("4: "+ta + " " +interpARGB + " " + sp[A] + " " + a2orig);
|
||||
//check
|
||||
}
|
||||
|
||||
if ((tformat == RGB) || (tformat == ARGB)) {
|
||||
p00 = (pixel00 >> 16) & 0xff; // red
|
||||
p01 = (pixel01 >> 16) & 0xff;
|
||||
p10 = (pixel10 >> 16) & 0xff;
|
||||
p11 = (pixel11 >> 16) & 0xff;
|
||||
|
||||
px0 = (p00*tuf + p10*tuf1) >> 8;
|
||||
px1 = (p01*tuf + p11*tuf1) >> 8;
|
||||
tr = (((px0*tvf + px1*tvf1) >> 8) * (interpARGB ? ((int) (sp[R]*255)) : r2)) >> 8;
|
||||
|
||||
p00 = (pixel00 >> 8) & 0xff; // green
|
||||
p01 = (pixel01 >> 8) & 0xff;
|
||||
p10 = (pixel10 >> 8) & 0xff;
|
||||
p11 = (pixel11 >> 8) & 0xff;
|
||||
|
||||
px0 = (p00*tuf + p10*tuf1) >> 8;
|
||||
px1 = (p01*tuf + p11*tuf1) >> 8;
|
||||
tg = (((px0*tvf + px1*tvf1) >> 8) * (interpARGB ? ((int) (sp[G]*255)) : g2)) >> 8;
|
||||
|
||||
|
||||
p00 = pixel00 & 0xff; // blue
|
||||
p01 = pixel01 & 0xff;
|
||||
p10 = pixel10 & 0xff;
|
||||
p11 = pixel11 & 0xff;
|
||||
|
||||
px0 = (p00*tuf + p10*tuf1) >> 8;
|
||||
px1 = (p01*tuf + p11*tuf1) >> 8;
|
||||
tb = (((px0*tvf + px1*tvf1) >> 8) * (interpARGB ? ((int) (sp[B]*255)) : b2)) >> 8;
|
||||
//System.out.println("5: "+tr + " " + tg + " " +tb);
|
||||
//check
|
||||
} else { // alpha image, only use current fill color
|
||||
if (interpARGB) {
|
||||
tr = (int) (sp[R] * 255);
|
||||
tg = (int) (sp[G] * 255);
|
||||
tb = (int) (sp[B] * 255);
|
||||
} else {
|
||||
tr = r2;
|
||||
tg = g2;
|
||||
tb = b2;
|
||||
}
|
||||
}
|
||||
|
||||
// get coverage for pixel if smooth
|
||||
// checks smooth again here because of
|
||||
// hints[SMOOTH_IMAGES] used up above
|
||||
int weight = smooth ? coverage(x) : 255;
|
||||
if (weight != 255) ta = (ta*weight) >> 8;
|
||||
//System.out.println(ta);
|
||||
//System.out.println("8");
|
||||
//check
|
||||
} else { // no smooth, just get the pixels
|
||||
int tpixel = tpixels[txy];
|
||||
// TODO i doubt splitting these guys really gets us
|
||||
// all that much speed.. is it worth it?
|
||||
if (tformat == ALPHA) {
|
||||
ta = tpixel;
|
||||
if (interpARGB) {
|
||||
tr = (int) (sp[R]*255);
|
||||
tg = (int) (sp[G]*255);
|
||||
tb = (int) (sp[B]*255);
|
||||
if (sp[A] != 1) {
|
||||
ta = (((int) (sp[A]*255)) * ta) >> 8;
|
||||
}
|
||||
} else {
|
||||
tr = r2;
|
||||
tg = g2;
|
||||
tb = b2;
|
||||
ta = (a2orig * ta) >> 8;
|
||||
}
|
||||
|
||||
} else { // RGB or ARGB
|
||||
ta = (tformat == RGB) ? 255 : (tpixel >> 24) & 0xff;
|
||||
if (interpARGB) {
|
||||
tr = (((int) (sp[R]*255)) * ((tpixel >> 16) & 0xff)) >> 8;
|
||||
tg = (((int) (sp[G]*255)) * ((tpixel >> 8) & 0xff)) >> 8;
|
||||
tb = (((int) (sp[B]*255)) * ((tpixel) & 0xff)) >> 8;
|
||||
ta = (((int) (sp[A]*255)) * ta) >> 8;
|
||||
} else {
|
||||
tr = (r2 * ((tpixel >> 16) & 0xff)) >> 8;
|
||||
tg = (g2 * ((tpixel >> 8) & 0xff)) >> 8;
|
||||
tb = (b2 * ((tpixel) & 0xff)) >> 8;
|
||||
ta = (a2orig * ta) >> 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((ta == 254) || (ta == 255)) { // if (ta & 0xf8) would be good
|
||||
// no need to blend
|
||||
pixels[offset+x] = 0xff000000 | (tr << 16) | (tg << 8) | tb;
|
||||
zbuffer[offset+x] = sp[Z];
|
||||
} else {
|
||||
// blend with pixel on screen
|
||||
int a1 = 255-ta;
|
||||
int r1 = (pixels[offset+x] >> 16) & 0xff;
|
||||
int g1 = (pixels[offset+x] >> 8) & 0xff;
|
||||
int b1 = (pixels[offset+x]) & 0xff;
|
||||
|
||||
|
||||
pixels[offset+x] =
|
||||
0xff000000 |
|
||||
(((tr*ta + r1*a1) >> 8) << 16) |
|
||||
((tg*ta + g1*a1) & 0xff00) |
|
||||
((tb*ta + b1*a1) >> 8);
|
||||
|
||||
//System.out.println("17");
|
||||
//check
|
||||
if (ta > ZBUFFER_MIN_COVERAGE) zbuffer[offset+x] = sp[Z];
|
||||
}
|
||||
|
||||
//System.out.println("18");
|
||||
//check
|
||||
} else { // no image applied
|
||||
int weight = smooth ? coverage(x) : 255;
|
||||
|
||||
if (interpARGB) {
|
||||
r2 = (int) (sp[R] * 255);
|
||||
g2 = (int) (sp[G] * 255);
|
||||
b2 = (int) (sp[B] * 255);
|
||||
if (sp[A] != 1) weight = (weight * ((int) (sp[A] * 255))) >> 8;
|
||||
if (weight == 255) {
|
||||
rgba = 0xff000000 | (r2 << 16) | (g2 << 8) | b2;
|
||||
}
|
||||
} else {
|
||||
if (a2orig != 255) weight = (weight * a2orig) >> 8;
|
||||
}
|
||||
|
||||
if (weight == 255) {
|
||||
// no blend, no aa, just the rgba
|
||||
pixels[offset+x] = rgba;
|
||||
zbuffer[offset+x] = sp[Z];
|
||||
|
||||
} else {
|
||||
int r1 = (pixels[offset+x] >> 16) & 0xff;
|
||||
int g1 = (pixels[offset+x] >> 8) & 0xff;
|
||||
int b1 = (pixels[offset+x]) & 0xff;
|
||||
a2 = weight;
|
||||
|
||||
int a1 = 255 - a2;
|
||||
pixels[offset+x] = (0xff000000 |
|
||||
((r1*a1 + r2*a2) >> 8) << 16 |
|
||||
// use & instead of >> and << below
|
||||
((g1*a1 + g2*a2) >> 8) << 8 |
|
||||
((b1*a1 + b2*a2) >> 8));
|
||||
|
||||
if (a2 > ZBUFFER_MIN_COVERAGE) zbuffer[offset+x] = sp[Z];
|
||||
}
|
||||
}
|
||||
}
|
||||
// if smooth enabled, don't increment values
|
||||
// for the pixel in the stretch out version
|
||||
// of the scanline used to get smooth edges.
|
||||
if (!smooth || ((x >= truelx) && (x <= truerx))) {
|
||||
//if (!smooth)
|
||||
increment(sp, sdp);
|
||||
}
|
||||
}
|
||||
firstModY = -1;
|
||||
interpX = true;
|
||||
}
|
||||
|
||||
|
||||
// x is in screen, not huge 8x coordinates
|
||||
private int coverage(int x) {
|
||||
if ((x >= aaleftfull) && (x <= aarightfull) &&
|
||||
// important since not all SUBYRES lines may have been covered
|
||||
(firstModY == 0) && (lastModY == SUBYRES1)) {
|
||||
return 255;
|
||||
}
|
||||
|
||||
int pixelLeft = x*SUBXRES; // huh?
|
||||
int pixelRight = pixelLeft + 8;
|
||||
|
||||
int amt = 0;
|
||||
for (int i = firstModY; i <= lastModY; i++) {
|
||||
if ((aaleft[i] > pixelRight) || (aaright[i] < pixelLeft)) {
|
||||
continue;
|
||||
}
|
||||
// does this need a +1 ?
|
||||
amt += ((aaright[i] < pixelRight ? aaright[i] : pixelRight) -
|
||||
(aaleft[i] > pixelLeft ? aaleft[i] : pixelLeft));
|
||||
}
|
||||
amt <<= 2;
|
||||
return (amt == 256) ? 255 : amt;
|
||||
}
|
||||
|
||||
|
||||
private void incrementalize_y(float p1[], float p2[],
|
||||
float p[], float dp[], int y) {
|
||||
float delta = p2[Y] - p1[Y];
|
||||
if (delta == 0) delta = 1;
|
||||
float fraction = y + 0.5f - p1[Y];
|
||||
|
||||
if (interpX) {
|
||||
dp[X] = (p2[X] - p1[X]) / delta;
|
||||
p[X] = p1[X] + dp[X] * fraction;
|
||||
}
|
||||
if (interpZ) {
|
||||
dp[Z] = (p2[Z] - p1[Z]) / delta;
|
||||
p[Z] = p1[Z] + dp[Z] * fraction;
|
||||
}
|
||||
|
||||
if (interpARGB) {
|
||||
dp[R] = (p2[R] - p1[R]) / delta;
|
||||
dp[G] = (p2[G] - p1[G]) / delta;
|
||||
dp[B] = (p2[B] - p1[B]) / delta;
|
||||
dp[A] = (p2[A] - p1[A]) / delta;
|
||||
p[R] = p1[R] + dp[R] * fraction;
|
||||
p[G] = p1[G] + dp[G] * fraction;
|
||||
p[B] = p1[B] + dp[B] * fraction;
|
||||
p[A] = p1[A] + dp[A] * fraction;
|
||||
}
|
||||
|
||||
if (interpUV) {
|
||||
dp[U] = (p2[U] - p1[U]) / delta;
|
||||
dp[V] = (p2[V] - p1[V]) / delta;
|
||||
|
||||
//if (smooth) {
|
||||
//p[U] = p1[U]; //+ dp[U] * fraction;
|
||||
//p[V] = p1[V]; //+ dp[V] * fraction;
|
||||
|
||||
//} else {
|
||||
p[U] = p1[U] + dp[U] * fraction;
|
||||
p[V] = p1[V] + dp[V] * fraction;
|
||||
//}
|
||||
if (FRY) System.out.println("inc y p[U] p[V] = " + p[U] + " " + p[V]);
|
||||
}
|
||||
}
|
||||
|
||||
//incrementalize_x(l, r, sp, sdp, lx);
|
||||
private void incrementalize_x(float p1[], float p2[],
|
||||
float p[], float dp[], int x) {
|
||||
float delta = p2[X] - p1[X];
|
||||
if (delta == 0) delta = 1;
|
||||
float fraction = x + 0.5f - p1[X];
|
||||
if (smooth) {
|
||||
delta /= SUBXRES;
|
||||
fraction /= SUBXRES;
|
||||
}
|
||||
|
||||
if (interpX) {
|
||||
dp[X] = (p2[X] - p1[X]) / delta;
|
||||
p[X] = p1[X] + dp[X] * fraction;
|
||||
}
|
||||
if (interpZ) {
|
||||
dp[Z] = (p2[Z] - p1[Z]) / delta;
|
||||
p[Z] = p1[Z] + dp[Z] * fraction;
|
||||
//System.out.println(p2[Z]+" " +p1[Z]+" " +dp[Z]);
|
||||
}
|
||||
|
||||
if (interpARGB) {
|
||||
dp[R] = (p2[R] - p1[R]) / delta;
|
||||
dp[G] = (p2[G] - p1[G]) / delta;
|
||||
dp[B] = (p2[B] - p1[B]) / delta;
|
||||
dp[A] = (p2[A] - p1[A]) / delta;
|
||||
p[R] = p1[R] + dp[R] * fraction;
|
||||
p[G] = p1[G] + dp[G] * fraction;
|
||||
p[B] = p1[B] + dp[B] * fraction;
|
||||
p[A] = p1[A] + dp[A] * fraction;
|
||||
}
|
||||
|
||||
if (interpUV) {
|
||||
if (FRY) System.out.println("delta, frac = " + delta + ", " + fraction);
|
||||
dp[U] = (p2[U] - p1[U]) / delta;
|
||||
dp[V] = (p2[V] - p1[V]) / delta;
|
||||
|
||||
//if (smooth) {
|
||||
//p[U] = p1[U];
|
||||
// offset for the damage that will be done by the
|
||||
// 8 consecutive calls to scanline
|
||||
// agh.. this won't work b/c not always 8 calls before render
|
||||
// maybe lastModY - firstModY + 1 instead?
|
||||
if (FRY) System.out.println("before inc x p[V] = " + p[V] + " " + p1[V] + " " + p2[V]);
|
||||
//p[V] = p1[V] - SUBXRES1 * fraction;
|
||||
|
||||
//} else {
|
||||
p[U] = p1[U] + dp[U] * fraction;
|
||||
p[V] = p1[V] + dp[V] * fraction;
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
private void increment(float p[], float dp[]) {
|
||||
if (interpX) p[X] += dp[X];
|
||||
if (interpZ) p[Z] += dp[Z];
|
||||
|
||||
if (interpARGB) {
|
||||
p[R] += dp[R];
|
||||
p[G] += dp[G];
|
||||
p[B] += dp[B];
|
||||
p[A] += dp[A];
|
||||
}
|
||||
|
||||
if (interpUV) {
|
||||
if (FRY) System.out.println("increment() " + p[V] + " " + dp[V]);
|
||||
p[U] += dp[U];
|
||||
p[V] += dp[V];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pass camera-space coordinates for the triangle.
|
||||
* Needed to render if hint(ENABLE_ACCURATE_TEXTURES) enabled.
|
||||
* Generally this will not need to be called manually,
|
||||
* currently called from PGraphics3D.render_triangles()
|
||||
*/
|
||||
public void setCamVertices(float x0, float y0, float z0,
|
||||
float x1, float y1, float z1,
|
||||
float x2, float y2, float z2) {
|
||||
camX[0] = x0;
|
||||
camX[1] = x1;
|
||||
camX[2] = x2;
|
||||
|
||||
camY[0] = y0;
|
||||
camY[1] = y1;
|
||||
camY[2] = y2;
|
||||
|
||||
camZ[0] = z0;
|
||||
camZ[1] = z1;
|
||||
camZ[2] = z2;
|
||||
}
|
||||
|
||||
public void setVertices(float x0, float y0, float z0,
|
||||
float x1, float y1, float z1,
|
||||
float x2, float y2, float z2) {
|
||||
vertices[0][X] = x0;
|
||||
vertices[1][X] = x1;
|
||||
vertices[2][X] = x2;
|
||||
|
||||
vertices[0][Y] = y0;
|
||||
vertices[1][Y] = y1;
|
||||
vertices[2][Y] = y2;
|
||||
|
||||
vertices[0][Z] = z0;
|
||||
vertices[1][Z] = z1;
|
||||
vertices[2][Z] = z2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Precompute a bunch of variables needed to perform
|
||||
* texture mapping.
|
||||
* @return True unless texture mapping is degenerate
|
||||
*/
|
||||
boolean precomputeAccurateTexturing() {
|
||||
int o0 = 0;
|
||||
int o1 = 1;
|
||||
int o2 = 2;
|
||||
|
||||
PMatrix3D myMatrix = new PMatrix3D(vertices[o0][U], vertices[o0][V], 1, 0,
|
||||
vertices[o1][U], vertices[o1][V], 1, 0,
|
||||
vertices[o2][U], vertices[o2][V], 1, 0,
|
||||
0, 0, 0, 1);
|
||||
|
||||
// A 3x3 inversion would be more efficient here,
|
||||
// given that the fourth r/c are unity
|
||||
boolean invertSuccess = myMatrix.invert();// = myMatrix.invert();
|
||||
|
||||
// If the matrix inversion had trouble, let the caller know.
|
||||
// Note that this does not catch everything that could go wrong
|
||||
// here, like if the renderer is in ortho() mode (which really
|
||||
// must be caught in PGraphics3D instead of here).
|
||||
if (!invertSuccess) return false;
|
||||
|
||||
float m00, m01, m02, m10, m11, m12, m20, m21, m22;
|
||||
m00 = myMatrix.m00*camX[o0]+myMatrix.m01*camX[o1]+myMatrix.m02*camX[o2];
|
||||
m01 = myMatrix.m10*camX[o0]+myMatrix.m11*camX[o1]+myMatrix.m12*camX[o2];
|
||||
m02 = myMatrix.m20*camX[o0]+myMatrix.m21*camX[o1]+myMatrix.m22*camX[o2];
|
||||
m10 = myMatrix.m00*camY[o0]+myMatrix.m01*camY[o1]+myMatrix.m02*camY[o2];
|
||||
m11 = myMatrix.m10*camY[o0]+myMatrix.m11*camY[o1]+myMatrix.m12*camY[o2];
|
||||
m12 = myMatrix.m20*camY[o0]+myMatrix.m21*camY[o1]+myMatrix.m22*camY[o2];
|
||||
m20 = -(myMatrix.m00*camZ[o0]+myMatrix.m01*camZ[o1]+myMatrix.m02*camZ[o2]);
|
||||
m21 = -(myMatrix.m10*camZ[o0]+myMatrix.m11*camZ[o1]+myMatrix.m12*camZ[o2]);
|
||||
m22 = -(myMatrix.m20*camZ[o0]+myMatrix.m21*camZ[o1]+myMatrix.m22*camZ[o2]);
|
||||
|
||||
float px = m02;
|
||||
float py = m12;
|
||||
float pz = m22;
|
||||
|
||||
float TEX_WIDTH = this.twidth;
|
||||
float TEX_HEIGHT = this.theight;
|
||||
|
||||
float resultT0x = m00*TEX_WIDTH+m02;
|
||||
float resultT0y = m10*TEX_WIDTH+m12;
|
||||
float resultT0z = m20*TEX_WIDTH+m22;
|
||||
float result0Tx = m01*TEX_HEIGHT+m02;
|
||||
float result0Ty = m11*TEX_HEIGHT+m12;
|
||||
float result0Tz = m21*TEX_HEIGHT+m22;
|
||||
float mx = resultT0x-m02;
|
||||
float my = resultT0y-m12;
|
||||
float mz = resultT0z-m22;
|
||||
float nx = result0Tx-m02;
|
||||
float ny = result0Ty-m12;
|
||||
float nz = result0Tz-m22;
|
||||
|
||||
//avec = p x n
|
||||
ax = (py*nz-pz*ny)*TEX_WIDTH; //F_TEX_WIDTH/HEIGHT?
|
||||
ay = (pz*nx-px*nz)*TEX_WIDTH;
|
||||
az = (px*ny-py*nx)*TEX_WIDTH;
|
||||
//bvec = m x p
|
||||
bx = (my*pz-mz*py)*TEX_HEIGHT;
|
||||
by = (mz*px-mx*pz)*TEX_HEIGHT;
|
||||
bz = (mx*py-my*px)*TEX_HEIGHT;
|
||||
//cvec = n x m
|
||||
cx = ny*mz-nz*my;
|
||||
cy = nz*mx-nx*mz;
|
||||
cz = nx*my-ny*mx;
|
||||
|
||||
//System.out.println("a/b/c: "+ax+" " + ay + " " + az + " " + bx + " " + by + " " + bz + " " + cx + " " + cy + " " + cz);
|
||||
|
||||
nearPlaneWidth = (parent.rightScreen-parent.leftScreen);
|
||||
nearPlaneHeight = (parent.topScreen-parent.bottomScreen);
|
||||
nearPlaneDepth = parent.nearPlane;
|
||||
|
||||
// one pixel width in nearPlane coordinates
|
||||
xmult = nearPlaneWidth / parent.width;
|
||||
ymult = nearPlaneHeight / parent.height;
|
||||
// Extra scalings to map screen plane units to pixel units
|
||||
// newax = ax*xmult;
|
||||
// newbx = bx*xmult;
|
||||
// newcx = cx*xmult;
|
||||
|
||||
|
||||
// System.out.println("nearplane: "+ nearPlaneWidth + " " + nearPlaneHeight + " " + nearPlaneDepth);
|
||||
// System.out.println("mults: "+ xmult + " " + ymult);
|
||||
// System.out.println("news: "+ newax + " " + newbx + " " + newcx);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the texture map location based on the current screen
|
||||
* coordinates. Assumes precomputeAccurateTexturing() has
|
||||
* been called already for this texture mapping.
|
||||
* @param sx
|
||||
* @param sy
|
||||
* @return
|
||||
*/
|
||||
private int getTextureIndex(float sx, float sy, float[] uv) {
|
||||
if (EWJORDAN) System.out.println("Getting texel at "+sx + ", "+sy);
|
||||
//System.out.println("Screen: "+ sx + " " + sy);
|
||||
sx = xmult*(sx-(parent.width/2.0f) +.5f);//+.5f)
|
||||
sy = ymult*(sy-(parent.height/2.0f)+.5f);//+.5f)
|
||||
//sx /= SUBXRES;
|
||||
//sy /= SUBYRES;
|
||||
float sz = nearPlaneDepth;
|
||||
float a = sx * ax + sy * ay + sz * az;
|
||||
float b = sx * bx + sy * by + sz * bz;
|
||||
float c = sx * cx + sy * cy + sz * cz;
|
||||
int u = (int)(a / c);
|
||||
int v = (int)(b / c);
|
||||
uv[0] = a / c;
|
||||
uv[1] = b / c;
|
||||
if (uv[0] < 0) {
|
||||
uv[0] = u = 0;
|
||||
}
|
||||
if (uv[1] < 0) {
|
||||
uv[1] = v = 0;
|
||||
}
|
||||
if (uv[0] >= twidth) {
|
||||
uv[0] = twidth-1;
|
||||
u = twidth-1;
|
||||
}
|
||||
if (uv[1] >= theight) {
|
||||
uv[1] = theight-1;
|
||||
v = theight-1;
|
||||
}
|
||||
int result = v*twidth + u;
|
||||
//System.out.println("a/b/c: "+a + " " + b + " " + c);
|
||||
//System.out.println("cx/y/z: "+cx + " " + cy + " " + cz);
|
||||
//if (result < 0) result = 0;
|
||||
//if (result >= timage.pixels.length-2) result = timage.pixels.length - 2;
|
||||
if (EWJORDAN) System.out.println("Got texel "+result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public void setIntensities(float ar, float ag, float ab, float aa,
|
||||
float br, float bg, float bb, float ba,
|
||||
float cr, float cg, float cb, float ca) {
|
||||
vertices[0][R] = ar;
|
||||
vertices[0][G] = ag;
|
||||
vertices[0][B] = ab;
|
||||
vertices[0][A] = aa;
|
||||
vertices[1][R] = br;
|
||||
vertices[1][G] = bg;
|
||||
vertices[1][B] = bb;
|
||||
vertices[1][A] = ba;
|
||||
vertices[2][R] = cr;
|
||||
vertices[2][G] = cg;
|
||||
vertices[2][B] = cb;
|
||||
vertices[2][A] = ca;
|
||||
}
|
||||
}
|
61
core/src/processing/core/PStyle.java
Normal file
61
core/src/processing/core/PStyle.java
Normal file
@ -0,0 +1,61 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2008 Ben Fry and Casey Reas
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.core;
|
||||
|
||||
|
||||
public class PStyle implements PConstants {
|
||||
public int imageMode;
|
||||
public int rectMode;
|
||||
public int ellipseMode;
|
||||
public int shapeMode;
|
||||
|
||||
public int colorMode;
|
||||
public float colorModeX;
|
||||
public float colorModeY;
|
||||
public float colorModeZ;
|
||||
public float colorModeA;
|
||||
|
||||
public boolean tint;
|
||||
public int tintColor;
|
||||
public boolean fill;
|
||||
public int fillColor;
|
||||
public boolean stroke;
|
||||
public int strokeColor;
|
||||
public float strokeWeight;
|
||||
public int strokeCap;
|
||||
public int strokeJoin;
|
||||
|
||||
// TODO these fellas are inconsistent, and may need to go elsewhere
|
||||
public float ambientR, ambientG, ambientB;
|
||||
public float specularR, specularG, specularB;
|
||||
public float emissiveR, emissiveG, emissiveB;
|
||||
public float shininess;
|
||||
|
||||
public PFont textFont;
|
||||
public int textAlign;
|
||||
public int textAlignY;
|
||||
public int textMode;
|
||||
public float textSize;
|
||||
public float textLeading;
|
||||
}
|
3850
core/src/processing/core/PTriangle.java
Normal file
3850
core/src/processing/core/PTriangle.java
Normal file
File diff suppressed because it is too large
Load Diff
559
core/src/processing/core/PVector.java
Normal file
559
core/src/processing/core/PVector.java
Normal file
@ -0,0 +1,559 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 200X Dan Shiffman
|
||||
Copyright (c) 2008 Ben Fry and Casey Reas
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.core;
|
||||
|
||||
/**
|
||||
* A class to describe a two or three dimensional vector.
|
||||
* <p>
|
||||
* The result of all functions are applied to the vector itself, with the
|
||||
* exception of cross(), which returns a new PVector (or writes to a specified
|
||||
* 'target' PVector). That is, add() will add the contents of one vector to
|
||||
* this one. Using add() with additional parameters allows you to put the
|
||||
* result into a new PVector. Functions that act on multiple vectors also
|
||||
* include static versions. Because creating new objects can be computationally
|
||||
* expensive, most functions include an optional 'target' PVector, so that a
|
||||
* new PVector object is not created with each operation.
|
||||
* <p>
|
||||
* Initially based on the Vector3D class by <a href="http://www.shiffman.net">Dan Shiffman</a>.
|
||||
*/
|
||||
public class PVector {
|
||||
|
||||
/** The x component of the vector. */
|
||||
public float x;
|
||||
|
||||
/** The y component of the vector. */
|
||||
public float y;
|
||||
|
||||
/** The z component of the vector. */
|
||||
public float z;
|
||||
|
||||
/** Array so that this can be temporarily used in an array context */
|
||||
protected float[] array;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for an empty vector: x, y, and z are set to 0.
|
||||
*/
|
||||
public PVector() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for a 3D vector.
|
||||
*
|
||||
* @param x the x coordinate.
|
||||
* @param y the y coordinate.
|
||||
* @param z the y coordinate.
|
||||
*/
|
||||
public PVector(float x, float y, float z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for a 2D vector: z coordinate is set to 0.
|
||||
*
|
||||
* @param x the x coordinate.
|
||||
* @param y the y coordinate.
|
||||
*/
|
||||
public PVector(float x, float y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set x, y, and z coordinates.
|
||||
*
|
||||
* @param x the x coordinate.
|
||||
* @param y the y coordinate.
|
||||
* @param z the z coordinate.
|
||||
*/
|
||||
public void set(float x, float y, float z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set x, y, and z coordinates from a Vector3D object.
|
||||
*
|
||||
* @param v the PVector object to be copied
|
||||
*/
|
||||
public void set(PVector v) {
|
||||
x = v.x;
|
||||
y = v.y;
|
||||
z = v.z;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the x, y (and maybe z) coordinates using a float[] array as the source.
|
||||
* @param source array to copy from
|
||||
*/
|
||||
public void set(float[] source) {
|
||||
if (source.length >= 2) {
|
||||
x = source[0];
|
||||
y = source[1];
|
||||
}
|
||||
if (source.length >= 3) {
|
||||
z = source[2];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a copy of this vector.
|
||||
*/
|
||||
public PVector get() {
|
||||
return new PVector(x, y, z);
|
||||
}
|
||||
|
||||
|
||||
public float[] get(float[] target) {
|
||||
if (target == null) {
|
||||
return new float[] { x, y, z };
|
||||
}
|
||||
if (target.length >= 2) {
|
||||
target[0] = x;
|
||||
target[1] = y;
|
||||
}
|
||||
if (target.length >= 3) {
|
||||
target[2] = z;
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculate the magnitude (length) of the vector
|
||||
* @return the magnitude of the vector
|
||||
*/
|
||||
public float mag() {
|
||||
return (float) Math.sqrt(x*x + y*y + z*z);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a vector to this vector
|
||||
* @param v the vector to be added
|
||||
*/
|
||||
public void add(PVector v) {
|
||||
x += v.x;
|
||||
y += v.y;
|
||||
z += v.z;
|
||||
}
|
||||
|
||||
|
||||
public void add(float x, float y, float z) {
|
||||
this.x += x;
|
||||
this.y += y;
|
||||
this.z += z;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add two vectors
|
||||
* @param v1 a vector
|
||||
* @param v2 another vector
|
||||
* @return a new vector that is the sum of v1 and v2
|
||||
*/
|
||||
static public PVector add(PVector v1, PVector v2) {
|
||||
return add(v1, v2, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add two vectors into a target vector
|
||||
* @param v1 a vector
|
||||
* @param v2 another vector
|
||||
* @param target the target vector (if null, a new vector will be created)
|
||||
* @return a new vector that is the sum of v1 and v2
|
||||
*/
|
||||
static public PVector add(PVector v1, PVector v2, PVector target) {
|
||||
if (target == null) {
|
||||
target = new PVector(v1.x + v2.x,v1.y + v2.y, v1.z + v2.z);
|
||||
} else {
|
||||
target.set(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Subtract a vector from this vector
|
||||
* @param v the vector to be subtracted
|
||||
*/
|
||||
public void sub(PVector v) {
|
||||
x -= v.x;
|
||||
y -= v.y;
|
||||
z -= v.z;
|
||||
}
|
||||
|
||||
|
||||
public void sub(float x, float y, float z) {
|
||||
this.x -= x;
|
||||
this.y -= y;
|
||||
this.z -= z;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Subtract one vector from another
|
||||
* @param v1 a vector
|
||||
* @param v2 another vector
|
||||
* @return a new vector that is v1 - v2
|
||||
*/
|
||||
static public PVector sub(PVector v1, PVector v2) {
|
||||
return sub(v1, v2, null);
|
||||
}
|
||||
|
||||
|
||||
static public PVector sub(PVector v1, PVector v2, PVector target) {
|
||||
if (target == null) {
|
||||
target = new PVector(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
|
||||
} else {
|
||||
target.set(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Multiply this vector by a scalar
|
||||
* @param n the value to multiply by
|
||||
*/
|
||||
public void mult(float n) {
|
||||
x *= n;
|
||||
y *= n;
|
||||
z *= n;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Multiply a vector by a scalar
|
||||
* @param v a vector
|
||||
* @param n scalar
|
||||
* @return a new vector that is v1 * n
|
||||
*/
|
||||
static public PVector mult(PVector v, float n) {
|
||||
return mult(v, n, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Multiply a vector by a scalar, and write the result into a target PVector.
|
||||
* @param v a vector
|
||||
* @param n scalar
|
||||
* @param target PVector to store the result
|
||||
* @return the target vector, now set to v1 * n
|
||||
*/
|
||||
static public PVector mult(PVector v, float n, PVector target) {
|
||||
if (target == null) {
|
||||
target = new PVector(v.x*n, v.y*n, v.z*n);
|
||||
} else {
|
||||
target.set(v.x*n, v.y*n, v.z*n);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Multiply each element of one vector by the elements of another vector.
|
||||
* @param v the vector to multiply by
|
||||
*/
|
||||
public void mult(PVector v) {
|
||||
x *= v.x;
|
||||
y *= v.y;
|
||||
z *= v.z;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Multiply each element of one vector by the individual elements of another
|
||||
* vector, and return the result as a new PVector.
|
||||
*/
|
||||
static public PVector mult(PVector v1, PVector v2) {
|
||||
return mult(v1, v2, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Multiply each element of one vector by the individual elements of another
|
||||
* vector, and write the result into a target vector.
|
||||
* @param v1 the first vector
|
||||
* @param v2 the second vector
|
||||
* @param target PVector to store the result
|
||||
*/
|
||||
static public PVector mult(PVector v1, PVector v2, PVector target) {
|
||||
if (target == null) {
|
||||
target = new PVector(v1.x*v2.x, v1.y*v2.y, v1.z*v2.z);
|
||||
} else {
|
||||
target.set(v1.x*v2.x, v1.y*v2.y, v1.z*v2.z);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Divide this vector by a scalar
|
||||
* @param n the value to divide by
|
||||
*/
|
||||
public void div(float n) {
|
||||
x /= n;
|
||||
y /= n;
|
||||
z /= n;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Divide a vector by a scalar and return the result in a new vector.
|
||||
* @param v a vector
|
||||
* @param n scalar
|
||||
* @return a new vector that is v1 / n
|
||||
*/
|
||||
static public PVector div(PVector v, float n) {
|
||||
return div(v, n, null);
|
||||
}
|
||||
|
||||
|
||||
static public PVector div(PVector v, float n, PVector target) {
|
||||
if (target == null) {
|
||||
target = new PVector(v.x/n, v.y/n, v.z/n);
|
||||
} else {
|
||||
target.set(v.x/n, v.y/n, v.z/n);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Divide each element of one vector by the elements of another vector.
|
||||
*/
|
||||
public void div(PVector v) {
|
||||
x /= v.x;
|
||||
y /= v.y;
|
||||
z /= v.z;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Multiply each element of one vector by the individual elements of another
|
||||
* vector, and return the result as a new PVector.
|
||||
*/
|
||||
static public PVector div(PVector v1, PVector v2) {
|
||||
return div(v1, v2, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Divide each element of one vector by the individual elements of another
|
||||
* vector, and write the result into a target vector.
|
||||
* @param v1 the first vector
|
||||
* @param v2 the second vector
|
||||
* @param target PVector to store the result
|
||||
*/
|
||||
static public PVector div(PVector v1, PVector v2, PVector target) {
|
||||
if (target == null) {
|
||||
target = new PVector(v1.x/v2.x, v1.y/v2.y, v1.z/v2.z);
|
||||
} else {
|
||||
target.set(v1.x/v2.x, v1.y/v2.y, v1.z/v2.z);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculate the Euclidean distance between two points (considering a point as a vector object)
|
||||
* @param v another vector
|
||||
* @return the Euclidean distance between
|
||||
*/
|
||||
public float dist(PVector v) {
|
||||
float dx = x - v.x;
|
||||
float dy = y - v.y;
|
||||
float dz = z - v.z;
|
||||
return (float) Math.sqrt(dx*dx + dy*dy + dz*dz);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculate the Euclidean distance between two points (considering a point as a vector object)
|
||||
* @param v1 a vector
|
||||
* @param v2 another vector
|
||||
* @return the Euclidean distance between v1 and v2
|
||||
*/
|
||||
static public float dist(PVector v1, PVector v2) {
|
||||
float dx = v1.x - v2.x;
|
||||
float dy = v1.y - v2.y;
|
||||
float dz = v1.z - v2.z;
|
||||
return (float) Math.sqrt(dx*dx + dy*dy + dz*dz);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculate the dot product with another vector
|
||||
* @return the dot product
|
||||
*/
|
||||
public float dot(PVector v) {
|
||||
return x*v.x + y*v.y + z*v.z;
|
||||
}
|
||||
|
||||
|
||||
public float dot(float x, float y, float z) {
|
||||
return this.x*x + this.y*y + this.z*z;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a vector composed of the cross product between this and another.
|
||||
*/
|
||||
public PVector cross(PVector v) {
|
||||
return cross(v, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Perform cross product between this and another vector, and store the
|
||||
* result in 'target'. If target is null, a new vector is created.
|
||||
*/
|
||||
public PVector cross(PVector v, PVector target) {
|
||||
float crossX = y * v.z - v.y * z;
|
||||
float crossY = z * v.x - v.z * x;
|
||||
float crossZ = x * v.y - v.x * y;
|
||||
|
||||
if (target == null) {
|
||||
target = new PVector(crossX, crossY, crossZ);
|
||||
} else {
|
||||
target.set(crossX, crossY, crossZ);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
static public PVector cross(PVector v1, PVector v2, PVector target) {
|
||||
float crossX = v1.y * v2.z - v2.y * v1.z;
|
||||
float crossY = v1.z * v2.x - v2.z * v1.x;
|
||||
float crossZ = v1.x * v2.y - v2.x * v1.y;
|
||||
|
||||
if (target == null) {
|
||||
target = new PVector(crossX, crossY, crossZ);
|
||||
} else {
|
||||
target.set(crossX, crossY, crossZ);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Normalize the vector to length 1 (make it a unit vector)
|
||||
*/
|
||||
public void normalize() {
|
||||
float m = mag();
|
||||
if (m != 0 && m != 1) {
|
||||
div(m);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Normalize this vector, storing the result in another vector.
|
||||
* @param target Set to null to create a new vector
|
||||
* @return a new vector (if target was null), or target
|
||||
*/
|
||||
public PVector normalize(PVector target) {
|
||||
if (target == null) {
|
||||
target = new PVector();
|
||||
}
|
||||
float m = mag();
|
||||
if (m > 0) {
|
||||
target.set(x/m, y/m, z/m);
|
||||
} else {
|
||||
target.set(x, y, z);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Limit the magnitude of this vector
|
||||
* @param max the maximum length to limit this vector
|
||||
*/
|
||||
public void limit(float max) {
|
||||
if (mag() > max) {
|
||||
normalize();
|
||||
mult(max);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculate the angle of rotation for this vector (only 2D vectors)
|
||||
* @return the angle of rotation
|
||||
*/
|
||||
public float heading2D() {
|
||||
float angle = (float) Math.atan2(-y, x);
|
||||
return -1*angle;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculate the angle between two vectors, using the dot product
|
||||
* @param v1 a vector
|
||||
* @param v2 another vector
|
||||
* @return the angle between the vectors
|
||||
*/
|
||||
static public float angleBetween(PVector v1, PVector v2) {
|
||||
float dot = v1.dot(v2);
|
||||
float theta = (float) Math.acos(dot / (v1.mag() * v2.mag()));
|
||||
return theta;
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
return "[ " + x + ", " + y + ", " + z + " ]";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a representation of this vector as a float array. This is only for
|
||||
* temporary use. If used in any other fashion, the contents should be copied
|
||||
* by using the get() command to copy into your own array.
|
||||
*/
|
||||
public float[] array() {
|
||||
if (array == null) {
|
||||
array = new float[3];
|
||||
}
|
||||
array[0] = x;
|
||||
array[1] = y;
|
||||
array[2] = z;
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
|
193
core/src/processing/xml/CDATAReader.java
Normal file
193
core/src/processing/xml/CDATAReader.java
Normal file
@ -0,0 +1,193 @@
|
||||
/* CDATAReader.java NanoXML/Java
|
||||
*
|
||||
* $Revision: 1.3 $
|
||||
* $Date: 2002/01/04 21:03:28 $
|
||||
* $Name: RELEASE_2_2_1 $
|
||||
*
|
||||
* This file is part of NanoXML 2 for Java.
|
||||
* Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from the
|
||||
* use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
package processing.xml;
|
||||
|
||||
|
||||
import java.io.Reader;
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* This reader reads data from another reader until the end of a CDATA section
|
||||
* (]]>) has been encountered.
|
||||
*
|
||||
* @author Marc De Scheemaecker
|
||||
* @version $Name: RELEASE_2_2_1 $, $Revision: 1.3 $
|
||||
*/
|
||||
class CDATAReader
|
||||
extends Reader
|
||||
{
|
||||
|
||||
/**
|
||||
* The encapsulated reader.
|
||||
*/
|
||||
private StdXMLReader reader;
|
||||
|
||||
|
||||
/**
|
||||
* Saved char.
|
||||
*/
|
||||
private char savedChar;
|
||||
|
||||
|
||||
/**
|
||||
* True if the end of the stream has been reached.
|
||||
*/
|
||||
private boolean atEndOfData;
|
||||
|
||||
|
||||
/**
|
||||
* Creates the reader.
|
||||
*
|
||||
* @param reader the encapsulated reader
|
||||
*/
|
||||
CDATAReader(StdXMLReader reader)
|
||||
{
|
||||
this.reader = reader;
|
||||
this.savedChar = 0;
|
||||
this.atEndOfData = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cleans up the object when it's destroyed.
|
||||
*/
|
||||
protected void finalize()
|
||||
throws Throwable
|
||||
{
|
||||
this.reader = null;
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads a block of data.
|
||||
*
|
||||
* @param buffer where to put the read data
|
||||
* @param offset first position in buffer to put the data
|
||||
* @param size maximum number of chars to read
|
||||
*
|
||||
* @return the number of chars read, or -1 if at EOF
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
* if an error occurred reading the data
|
||||
*/
|
||||
public int read(char[] buffer,
|
||||
int offset,
|
||||
int size)
|
||||
throws IOException
|
||||
{
|
||||
int charsRead = 0;
|
||||
|
||||
if (this.atEndOfData) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((offset + size) > buffer.length) {
|
||||
size = buffer.length - offset;
|
||||
}
|
||||
|
||||
while (charsRead < size) {
|
||||
char ch = this.savedChar;
|
||||
|
||||
if (ch == 0) {
|
||||
ch = this.reader.read();
|
||||
} else {
|
||||
this.savedChar = 0;
|
||||
}
|
||||
|
||||
if (ch == ']') {
|
||||
char ch2 = this.reader.read();
|
||||
|
||||
if (ch2 == ']') {
|
||||
char ch3 = this.reader.read();
|
||||
|
||||
if (ch3 == '>') {
|
||||
this.atEndOfData = true;
|
||||
break;
|
||||
}
|
||||
|
||||
this.savedChar = ch2;
|
||||
this.reader.unread(ch3);
|
||||
} else {
|
||||
this.reader.unread(ch2);
|
||||
}
|
||||
}
|
||||
buffer[charsRead] = ch;
|
||||
charsRead++;
|
||||
}
|
||||
|
||||
if (charsRead == 0) {
|
||||
charsRead = -1;
|
||||
}
|
||||
|
||||
return charsRead;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Skips remaining data and closes the stream.
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
* if an error occurred reading the data
|
||||
*/
|
||||
public void close()
|
||||
throws IOException
|
||||
{
|
||||
while (! this.atEndOfData) {
|
||||
char ch = this.savedChar;
|
||||
|
||||
if (ch == 0) {
|
||||
ch = this.reader.read();
|
||||
} else {
|
||||
this.savedChar = 0;
|
||||
}
|
||||
|
||||
if (ch == ']') {
|
||||
char ch2 = this.reader.read();
|
||||
|
||||
if (ch2 == ']') {
|
||||
char ch3 = this.reader.read();
|
||||
|
||||
if (ch3 == '>') {
|
||||
break;
|
||||
}
|
||||
|
||||
this.savedChar = ch2;
|
||||
this.reader.unread(ch3);
|
||||
} else {
|
||||
this.reader.unread(ch2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.atEndOfData = true;
|
||||
}
|
||||
|
||||
}
|
212
core/src/processing/xml/ContentReader.java
Normal file
212
core/src/processing/xml/ContentReader.java
Normal file
@ -0,0 +1,212 @@
|
||||
/* ContentReader.java NanoXML/Java
|
||||
*
|
||||
* $Revision: 1.4 $
|
||||
* $Date: 2002/01/04 21:03:28 $
|
||||
* $Name: RELEASE_2_2_1 $
|
||||
*
|
||||
* This file is part of NanoXML 2 for Java.
|
||||
* Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from the
|
||||
* use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
package processing.xml;
|
||||
|
||||
|
||||
import java.io.Reader;
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* This reader reads data from another reader until a new element has
|
||||
* been encountered.
|
||||
*
|
||||
* @author Marc De Scheemaecker
|
||||
* @version $Name: RELEASE_2_2_1 $, $Revision: 1.4 $
|
||||
*/
|
||||
class ContentReader
|
||||
extends Reader
|
||||
{
|
||||
|
||||
/**
|
||||
* The encapsulated reader.
|
||||
*/
|
||||
private StdXMLReader reader;
|
||||
|
||||
|
||||
/**
|
||||
* Buffer.
|
||||
*/
|
||||
private String buffer;
|
||||
|
||||
|
||||
/**
|
||||
* Pointer into the buffer.
|
||||
*/
|
||||
private int bufferIndex;
|
||||
|
||||
|
||||
/**
|
||||
* The entity resolver.
|
||||
*/
|
||||
private XMLEntityResolver resolver;
|
||||
|
||||
|
||||
/**
|
||||
* Creates the reader.
|
||||
*
|
||||
* @param reader the encapsulated reader
|
||||
* @param resolver the entity resolver
|
||||
* @param buffer data that has already been read from <code>reader</code>
|
||||
*/
|
||||
ContentReader(StdXMLReader reader,
|
||||
XMLEntityResolver resolver,
|
||||
String buffer)
|
||||
{
|
||||
this.reader = reader;
|
||||
this.resolver = resolver;
|
||||
this.buffer = buffer;
|
||||
this.bufferIndex = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cleans up the object when it's destroyed.
|
||||
*/
|
||||
protected void finalize()
|
||||
throws Throwable
|
||||
{
|
||||
this.reader = null;
|
||||
this.resolver = null;
|
||||
this.buffer = null;
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads a block of data.
|
||||
*
|
||||
* @param outputBuffer where to put the read data
|
||||
* @param offset first position in buffer to put the data
|
||||
* @param size maximum number of chars to read
|
||||
*
|
||||
* @return the number of chars read, or -1 if at EOF
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
* if an error occurred reading the data
|
||||
*/
|
||||
public int read(char[] outputBuffer,
|
||||
int offset,
|
||||
int size)
|
||||
throws IOException
|
||||
{
|
||||
try {
|
||||
int charsRead = 0;
|
||||
int bufferLength = this.buffer.length();
|
||||
|
||||
if ((offset + size) > outputBuffer.length) {
|
||||
size = outputBuffer.length - offset;
|
||||
}
|
||||
|
||||
while (charsRead < size) {
|
||||
String str = "";
|
||||
char ch;
|
||||
|
||||
if (this.bufferIndex >= bufferLength) {
|
||||
str = XMLUtil.read(this.reader, '&');
|
||||
ch = str.charAt(0);
|
||||
} else {
|
||||
ch = this.buffer.charAt(this.bufferIndex);
|
||||
this.bufferIndex++;
|
||||
outputBuffer[charsRead] = ch;
|
||||
charsRead++;
|
||||
continue; // don't interprete chars in the buffer
|
||||
}
|
||||
|
||||
if (ch == '<') {
|
||||
this.reader.unread(ch);
|
||||
break;
|
||||
}
|
||||
|
||||
if ((ch == '&') && (str.length() > 1)) {
|
||||
if (str.charAt(1) == '#') {
|
||||
ch = XMLUtil.processCharLiteral(str);
|
||||
} else {
|
||||
XMLUtil.processEntity(str, this.reader, this.resolver);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
outputBuffer[charsRead] = ch;
|
||||
charsRead++;
|
||||
}
|
||||
|
||||
if (charsRead == 0) {
|
||||
charsRead = -1;
|
||||
}
|
||||
|
||||
return charsRead;
|
||||
} catch (XMLParseException e) {
|
||||
throw new IOException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Skips remaining data and closes the stream.
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
* if an error occurred reading the data
|
||||
*/
|
||||
public void close()
|
||||
throws IOException
|
||||
{
|
||||
try {
|
||||
int bufferLength = this.buffer.length();
|
||||
|
||||
for (;;) {
|
||||
String str = "";
|
||||
char ch;
|
||||
|
||||
if (this.bufferIndex >= bufferLength) {
|
||||
str = XMLUtil.read(this.reader, '&');
|
||||
ch = str.charAt(0);
|
||||
} else {
|
||||
ch = this.buffer.charAt(this.bufferIndex);
|
||||
this.bufferIndex++;
|
||||
continue; // don't interprete chars in the buffer
|
||||
}
|
||||
|
||||
if (ch == '<') {
|
||||
this.reader.unread(ch);
|
||||
break;
|
||||
}
|
||||
|
||||
if ((ch == '&') && (str.length() > 1)) {
|
||||
if (str.charAt(1) != '#') {
|
||||
XMLUtil.processEntity(str, this.reader, this.resolver);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (XMLParseException e) {
|
||||
throw new IOException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
157
core/src/processing/xml/PIReader.java
Normal file
157
core/src/processing/xml/PIReader.java
Normal file
@ -0,0 +1,157 @@
|
||||
/* PIReader.java NanoXML/Java
|
||||
*
|
||||
* $Revision: 1.3 $
|
||||
* $Date: 2002/01/04 21:03:28 $
|
||||
* $Name: RELEASE_2_2_1 $
|
||||
*
|
||||
* This file is part of NanoXML 2 for Java.
|
||||
* Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from the
|
||||
* use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
package processing.xml;
|
||||
|
||||
|
||||
import java.io.Reader;
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* This reader reads data from another reader until the end of a processing
|
||||
* instruction (?>) has been encountered.
|
||||
*
|
||||
* @author Marc De Scheemaecker
|
||||
* @version $Name: RELEASE_2_2_1 $, $Revision: 1.3 $
|
||||
*/
|
||||
class PIReader
|
||||
extends Reader
|
||||
{
|
||||
|
||||
/**
|
||||
* The encapsulated reader.
|
||||
*/
|
||||
private StdXMLReader reader;
|
||||
|
||||
|
||||
/**
|
||||
* True if the end of the stream has been reached.
|
||||
*/
|
||||
private boolean atEndOfData;
|
||||
|
||||
|
||||
/**
|
||||
* Creates the reader.
|
||||
*
|
||||
* @param reader the encapsulated reader
|
||||
*/
|
||||
PIReader(StdXMLReader reader)
|
||||
{
|
||||
this.reader = reader;
|
||||
this.atEndOfData = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cleans up the object when it's destroyed.
|
||||
*/
|
||||
protected void finalize()
|
||||
throws Throwable
|
||||
{
|
||||
this.reader = null;
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads a block of data.
|
||||
*
|
||||
* @param buffer where to put the read data
|
||||
* @param offset first position in buffer to put the data
|
||||
* @param size maximum number of chars to read
|
||||
*
|
||||
* @return the number of chars read, or -1 if at EOF
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
* if an error occurred reading the data
|
||||
*/
|
||||
public int read(char[] buffer,
|
||||
int offset,
|
||||
int size)
|
||||
throws IOException
|
||||
{
|
||||
if (this.atEndOfData) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int charsRead = 0;
|
||||
|
||||
if ((offset + size) > buffer.length) {
|
||||
size = buffer.length - offset;
|
||||
}
|
||||
|
||||
while (charsRead < size) {
|
||||
char ch = this.reader.read();
|
||||
|
||||
if (ch == '?') {
|
||||
char ch2 = this.reader.read();
|
||||
|
||||
if (ch2 == '>') {
|
||||
this.atEndOfData = true;
|
||||
break;
|
||||
}
|
||||
|
||||
this.reader.unread(ch2);
|
||||
}
|
||||
|
||||
buffer[charsRead] = ch;
|
||||
charsRead++;
|
||||
}
|
||||
|
||||
if (charsRead == 0) {
|
||||
charsRead = -1;
|
||||
}
|
||||
|
||||
return charsRead;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Skips remaining data and closes the stream.
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
* if an error occurred reading the data
|
||||
*/
|
||||
public void close()
|
||||
throws IOException
|
||||
{
|
||||
while (! this.atEndOfData) {
|
||||
char ch = this.reader.read();
|
||||
|
||||
if (ch == '?') {
|
||||
char ch2 = this.reader.read();
|
||||
|
||||
if (ch2 == '>') {
|
||||
this.atEndOfData = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
356
core/src/processing/xml/StdXMLBuilder.java
Normal file
356
core/src/processing/xml/StdXMLBuilder.java
Normal file
@ -0,0 +1,356 @@
|
||||
/* StdXMLBuilder.java NanoXML/Java
|
||||
*
|
||||
* $Revision: 1.3 $
|
||||
* $Date: 2002/01/04 21:03:28 $
|
||||
* $Name: RELEASE_2_2_1 $
|
||||
*
|
||||
* This file is part of NanoXML 2 for Java.
|
||||
* Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from the
|
||||
* use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
package processing.xml;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.util.Stack;
|
||||
|
||||
|
||||
/**
|
||||
* StdXMLBuilder is a concrete implementation of IXMLBuilder which creates a
|
||||
* tree of IXMLElement from an XML data source.
|
||||
*
|
||||
* @see processing.xml.XMLElement
|
||||
*
|
||||
* @author Marc De Scheemaecker
|
||||
* @version $Name: RELEASE_2_2_1 $, $Revision: 1.3 $
|
||||
*/
|
||||
public class StdXMLBuilder
|
||||
{
|
||||
|
||||
/**
|
||||
* This stack contains the current element and its parents.
|
||||
*/
|
||||
private Stack<XMLElement> stack;
|
||||
|
||||
|
||||
/**
|
||||
* The root element of the parsed XML tree.
|
||||
*/
|
||||
private XMLElement root;
|
||||
|
||||
private XMLElement parent;
|
||||
|
||||
/**
|
||||
* Prototype element for creating the tree.
|
||||
*/
|
||||
//private XMLElement prototype;
|
||||
|
||||
|
||||
/**
|
||||
* Creates the builder.
|
||||
*/
|
||||
public StdXMLBuilder()
|
||||
{
|
||||
this.stack = null;
|
||||
this.root = null;
|
||||
//this(new XMLElement());
|
||||
}
|
||||
|
||||
|
||||
public StdXMLBuilder(XMLElement parent)
|
||||
{
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates the builder.
|
||||
*
|
||||
* @param prototype the prototype to use when building the tree.
|
||||
*/
|
||||
// public StdXMLBuilder(XMLElement prototype)
|
||||
// {
|
||||
// this.stack = null;
|
||||
// this.root = null;
|
||||
// this.prototype = prototype;
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
* Cleans up the object when it's destroyed.
|
||||
*/
|
||||
protected void finalize()
|
||||
throws Throwable
|
||||
{
|
||||
//this.prototype = null;
|
||||
this.root = null;
|
||||
this.stack.clear();
|
||||
this.stack = null;
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method is called before the parser starts processing its input.
|
||||
*
|
||||
* @param systemID the system ID of the XML data source.
|
||||
* @param lineNr the line on which the parsing starts.
|
||||
*/
|
||||
public void startBuilding(String systemID,
|
||||
int lineNr)
|
||||
{
|
||||
this.stack = new Stack<XMLElement>();
|
||||
this.root = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method is called when a processing instruction is encountered.
|
||||
* PIs with target "xml" are handled by the parser.
|
||||
*
|
||||
* @param target the PI target.
|
||||
* @param reader to read the data from the PI.
|
||||
*/
|
||||
public void newProcessingInstruction(String target,
|
||||
Reader reader)
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method is called when a new XML element is encountered.
|
||||
*
|
||||
* @see #endElement
|
||||
*
|
||||
* @param name the name of the element.
|
||||
* @param nsPrefix the prefix used to identify the namespace. If no
|
||||
* namespace has been specified, this parameter is null.
|
||||
* @param nsURI the URI associated with the namespace. If no
|
||||
* namespace has been specified, or no URI is
|
||||
* associated with nsPrefix, this parameter is null.
|
||||
* @param systemID the system ID of the XML data source.
|
||||
* @param lineNr the line in the source where the element starts.
|
||||
*/
|
||||
public void startElement(String name,
|
||||
String nsPrefix,
|
||||
String nsURI,
|
||||
String systemID,
|
||||
int lineNr)
|
||||
{
|
||||
String fullName = name;
|
||||
|
||||
if (nsPrefix != null) {
|
||||
fullName = nsPrefix + ':' + name;
|
||||
}
|
||||
|
||||
//XMLElement elt = this.prototype.createElement(fullName, nsURI,
|
||||
// systemID, lineNr);
|
||||
|
||||
// XMLElement elt = new XMLElement(fullName, nsURI, systemID, lineNr);
|
||||
//
|
||||
// if (this.stack.empty()) {
|
||||
// this.root = elt;
|
||||
// } else {
|
||||
// XMLElement top = (XMLElement) this.stack.peek();
|
||||
// top.addChild(elt);
|
||||
// }
|
||||
// stack.push(elt);
|
||||
|
||||
if (this.stack.empty()) {
|
||||
//System.out.println("setting root");
|
||||
parent.set(fullName, nsURI, systemID, lineNr);
|
||||
stack.push(parent);
|
||||
root = parent;
|
||||
} else {
|
||||
XMLElement top = (XMLElement) this.stack.peek();
|
||||
//System.out.println("stack has " + top.getName());
|
||||
XMLElement elt = new XMLElement(fullName, nsURI, systemID, lineNr);
|
||||
top.addChild(elt);
|
||||
stack.push(elt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method is called when the attributes of an XML element have been
|
||||
* processed.
|
||||
*
|
||||
* @see #startElement
|
||||
* @see #addAttribute
|
||||
*
|
||||
* @param name the name of the element.
|
||||
* @param nsPrefix the prefix used to identify the namespace. If no
|
||||
* namespace has been specified, this parameter is null.
|
||||
* @param nsURI the URI associated with the namespace. If no
|
||||
* namespace has been specified, or no URI is
|
||||
* associated with nsPrefix, this parameter is null.
|
||||
*/
|
||||
public void elementAttributesProcessed(String name,
|
||||
String nsPrefix,
|
||||
String nsURI)
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method is called when the end of an XML elemnt is encountered.
|
||||
*
|
||||
* @see #startElement
|
||||
*
|
||||
* @param name the name of the element.
|
||||
* @param nsPrefix the prefix used to identify the namespace. If no
|
||||
* namespace has been specified, this parameter is null.
|
||||
* @param nsURI the URI associated with the namespace. If no
|
||||
* namespace has been specified, or no URI is
|
||||
* associated with nsPrefix, this parameter is null.
|
||||
*/
|
||||
public void endElement(String name,
|
||||
String nsPrefix,
|
||||
String nsURI)
|
||||
{
|
||||
XMLElement elt = (XMLElement) this.stack.pop();
|
||||
|
||||
if (elt.getChildCount() == 1) {
|
||||
XMLElement child = elt.getChildAtIndex(0);
|
||||
|
||||
if (child.getLocalName() == null) {
|
||||
elt.setContent(child.getContent());
|
||||
elt.removeChildAtIndex(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method is called when a new attribute of an XML element is
|
||||
* encountered.
|
||||
*
|
||||
* @param key the key (name) of the attribute.
|
||||
* @param nsPrefix the prefix used to identify the namespace. If no
|
||||
* namespace has been specified, this parameter is null.
|
||||
* @param nsURI the URI associated with the namespace. If no
|
||||
* namespace has been specified, or no URI is
|
||||
* associated with nsPrefix, this parameter is null.
|
||||
* @param value the value of the attribute.
|
||||
* @param type the type of the attribute. If no type is known,
|
||||
* "CDATA" is returned.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
* If an exception occurred while processing the event.
|
||||
*/
|
||||
public void addAttribute(String key,
|
||||
String nsPrefix,
|
||||
String nsURI,
|
||||
String value,
|
||||
String type)
|
||||
throws Exception
|
||||
{
|
||||
String fullName = key;
|
||||
|
||||
if (nsPrefix != null) {
|
||||
fullName = nsPrefix + ':' + key;
|
||||
}
|
||||
|
||||
XMLElement top = (XMLElement) this.stack.peek();
|
||||
|
||||
if (top.hasAttribute(fullName)) {
|
||||
throw new XMLParseException(top.getSystemID(),
|
||||
top.getLineNr(),
|
||||
"Duplicate attribute: " + key);
|
||||
}
|
||||
|
||||
if (nsPrefix != null) {
|
||||
top.setAttribute(fullName, nsURI, value);
|
||||
} else {
|
||||
top.setAttribute(fullName, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method is called when a PCDATA element is encountered. A Java
|
||||
* reader is supplied from which you can read the data. The reader will
|
||||
* only read the data of the element. You don't need to check for
|
||||
* boundaries. If you don't read the full element, the rest of the data
|
||||
* is skipped. You also don't have to care about entities; they are
|
||||
* resolved by the parser.
|
||||
*
|
||||
* @param reader the Java reader from which you can retrieve the data.
|
||||
* @param systemID the system ID of the XML data source.
|
||||
* @param lineNr the line in the source where the element starts.
|
||||
*/
|
||||
public void addPCData(Reader reader,
|
||||
String systemID,
|
||||
int lineNr)
|
||||
{
|
||||
int bufSize = 2048;
|
||||
int sizeRead = 0;
|
||||
StringBuffer str = new StringBuffer(bufSize);
|
||||
char[] buf = new char[bufSize];
|
||||
|
||||
for (;;) {
|
||||
if (sizeRead >= bufSize) {
|
||||
bufSize *= 2;
|
||||
str.ensureCapacity(bufSize);
|
||||
}
|
||||
|
||||
int size;
|
||||
|
||||
try {
|
||||
size = reader.read(buf);
|
||||
} catch (IOException e) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (size < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
str.append(buf, 0, size);
|
||||
sizeRead += size;
|
||||
}
|
||||
|
||||
//XMLElement elt = this.prototype.createElement(null, systemID, lineNr);
|
||||
XMLElement elt = new XMLElement(null, null, systemID, lineNr);
|
||||
elt.setContent(str.toString());
|
||||
|
||||
if (! this.stack.empty()) {
|
||||
XMLElement top = (XMLElement) this.stack.peek();
|
||||
top.addChild(elt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the result of the building process. This method is called just
|
||||
* before the <I>parse</I> method of StdXMLParser returns.
|
||||
*
|
||||
* @return the result of the building process.
|
||||
*/
|
||||
public Object getResult()
|
||||
{
|
||||
return this.root;
|
||||
}
|
||||
|
||||
}
|
684
core/src/processing/xml/StdXMLParser.java
Normal file
684
core/src/processing/xml/StdXMLParser.java
Normal file
@ -0,0 +1,684 @@
|
||||
/* StdXMLParser.java NanoXML/Java
|
||||
*
|
||||
* $Revision: 1.5 $
|
||||
* $Date: 2002/03/24 11:37:00 $
|
||||
* $Name: RELEASE_2_2_1 $
|
||||
*
|
||||
* This file is part of NanoXML 2 for Java.
|
||||
* Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from the
|
||||
* use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
package processing.xml;
|
||||
|
||||
|
||||
import java.io.Reader;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Properties;
|
||||
import java.util.Vector;
|
||||
|
||||
|
||||
/**
|
||||
* StdXMLParser is the core parser of NanoXML.
|
||||
*
|
||||
* @author Marc De Scheemaecker
|
||||
* @version $Name: RELEASE_2_2_1 $, $Revision: 1.5 $
|
||||
*/
|
||||
public class StdXMLParser {
|
||||
|
||||
/**
|
||||
* The builder which creates the logical structure of the XML data.
|
||||
*/
|
||||
private StdXMLBuilder builder;
|
||||
|
||||
|
||||
/**
|
||||
* The reader from which the parser retrieves its data.
|
||||
*/
|
||||
private StdXMLReader reader;
|
||||
|
||||
|
||||
/**
|
||||
* The entity resolver.
|
||||
*/
|
||||
private XMLEntityResolver entityResolver;
|
||||
|
||||
|
||||
/**
|
||||
* The validator that will process entity references and validate the XML
|
||||
* data.
|
||||
*/
|
||||
private XMLValidator validator;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new parser.
|
||||
*/
|
||||
public StdXMLParser()
|
||||
{
|
||||
this.builder = null;
|
||||
this.validator = null;
|
||||
this.reader = null;
|
||||
this.entityResolver = new XMLEntityResolver();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cleans up the object when it's destroyed.
|
||||
*/
|
||||
protected void finalize()
|
||||
throws Throwable
|
||||
{
|
||||
this.builder = null;
|
||||
this.reader = null;
|
||||
this.entityResolver = null;
|
||||
this.validator = null;
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the builder which creates the logical structure of the XML data.
|
||||
*
|
||||
* @param builder the non-null builder
|
||||
*/
|
||||
public void setBuilder(StdXMLBuilder builder)
|
||||
{
|
||||
this.builder = builder;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the builder which creates the logical structure of the XML data.
|
||||
*
|
||||
* @return the builder
|
||||
*/
|
||||
public StdXMLBuilder getBuilder()
|
||||
{
|
||||
return this.builder;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the validator that validates the XML data.
|
||||
*
|
||||
* @param validator the non-null validator
|
||||
*/
|
||||
public void setValidator(XMLValidator validator)
|
||||
{
|
||||
this.validator = validator;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the validator that validates the XML data.
|
||||
*
|
||||
* @return the validator
|
||||
*/
|
||||
public XMLValidator getValidator()
|
||||
{
|
||||
return this.validator;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the entity resolver.
|
||||
*
|
||||
* @param resolver the non-null resolver
|
||||
*/
|
||||
public void setResolver(XMLEntityResolver resolver)
|
||||
{
|
||||
this.entityResolver = resolver;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the entity resolver.
|
||||
*
|
||||
* @return the non-null resolver
|
||||
*/
|
||||
public XMLEntityResolver getResolver()
|
||||
{
|
||||
return this.entityResolver;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the reader from which the parser retrieves its data.
|
||||
*
|
||||
* @param reader the reader
|
||||
*/
|
||||
public void setReader(StdXMLReader reader)
|
||||
{
|
||||
this.reader = reader;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the reader from which the parser retrieves its data.
|
||||
*
|
||||
* @return the reader
|
||||
*/
|
||||
public StdXMLReader getReader()
|
||||
{
|
||||
return this.reader;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parses the data and lets the builder create the logical data structure.
|
||||
*
|
||||
* @return the logical structure built by the builder
|
||||
*
|
||||
* @throws net.n3.nanoxml.XMLException
|
||||
* if an error occurred reading or parsing the data
|
||||
*/
|
||||
public Object parse()
|
||||
throws XMLException
|
||||
{
|
||||
try {
|
||||
this.builder.startBuilding(this.reader.getSystemID(),
|
||||
this.reader.getLineNr());
|
||||
this.scanData();
|
||||
return this.builder.getResult();
|
||||
} catch (XMLException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new XMLException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scans the XML data for elements.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
* if something went wrong
|
||||
*/
|
||||
protected void scanData() throws Exception {
|
||||
while ((! this.reader.atEOF()) && (this.builder.getResult() == null)) {
|
||||
String str = XMLUtil.read(this.reader, '&');
|
||||
char ch = str.charAt(0);
|
||||
if (ch == '&') {
|
||||
XMLUtil.processEntity(str, this.reader, this.entityResolver);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (ch) {
|
||||
case '<':
|
||||
this.scanSomeTag(false, // don't allow CDATA
|
||||
null, // no default namespace
|
||||
new Properties());
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
case '\n':
|
||||
// skip whitespace
|
||||
break;
|
||||
|
||||
default:
|
||||
XMLUtil.errorInvalidInput(reader.getSystemID(),
|
||||
reader.getLineNr(),
|
||||
"`" + ch + "' (0x"
|
||||
+ Integer.toHexString((int) ch)
|
||||
+ ')');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scans an XML tag.
|
||||
*
|
||||
* @param allowCDATA true if CDATA sections are allowed at this point
|
||||
* @param defaultNamespace the default namespace URI (or null)
|
||||
* @param namespaces list of defined namespaces
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
* if something went wrong
|
||||
*/
|
||||
protected void scanSomeTag(boolean allowCDATA,
|
||||
String defaultNamespace,
|
||||
Properties namespaces)
|
||||
throws Exception
|
||||
{
|
||||
String str = XMLUtil.read(this.reader, '&');
|
||||
char ch = str.charAt(0);
|
||||
|
||||
if (ch == '&') {
|
||||
XMLUtil.errorUnexpectedEntity(reader.getSystemID(),
|
||||
reader.getLineNr(),
|
||||
str);
|
||||
}
|
||||
|
||||
switch (ch) {
|
||||
case '?':
|
||||
this.processPI();
|
||||
break;
|
||||
|
||||
case '!':
|
||||
this.processSpecialTag(allowCDATA);
|
||||
break;
|
||||
|
||||
default:
|
||||
this.reader.unread(ch);
|
||||
this.processElement(defaultNamespace, namespaces);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes a "processing instruction".
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
* if something went wrong
|
||||
*/
|
||||
protected void processPI()
|
||||
throws Exception
|
||||
{
|
||||
XMLUtil.skipWhitespace(this.reader, null);
|
||||
String target = XMLUtil.scanIdentifier(this.reader);
|
||||
XMLUtil.skipWhitespace(this.reader, null);
|
||||
Reader r = new PIReader(this.reader);
|
||||
|
||||
if (!target.equalsIgnoreCase("xml")) {
|
||||
this.builder.newProcessingInstruction(target, r);
|
||||
}
|
||||
|
||||
r.close();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes a tag that starts with a bang (<!...>).
|
||||
*
|
||||
* @param allowCDATA true if CDATA sections are allowed at this point
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
* if something went wrong
|
||||
*/
|
||||
protected void processSpecialTag(boolean allowCDATA)
|
||||
throws Exception
|
||||
{
|
||||
String str = XMLUtil.read(this.reader, '&');
|
||||
char ch = str.charAt(0);
|
||||
|
||||
if (ch == '&') {
|
||||
XMLUtil.errorUnexpectedEntity(reader.getSystemID(),
|
||||
reader.getLineNr(),
|
||||
str);
|
||||
}
|
||||
|
||||
switch (ch) {
|
||||
case '[':
|
||||
if (allowCDATA) {
|
||||
this.processCDATA();
|
||||
} else {
|
||||
XMLUtil.errorUnexpectedCDATA(reader.getSystemID(),
|
||||
reader.getLineNr());
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
case 'D':
|
||||
this.processDocType();
|
||||
return;
|
||||
|
||||
case '-':
|
||||
XMLUtil.skipComment(this.reader);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes a CDATA section.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
* if something went wrong
|
||||
*/
|
||||
protected void processCDATA() throws Exception {
|
||||
if (! XMLUtil.checkLiteral(this.reader, "CDATA[")) {
|
||||
XMLUtil.errorExpectedInput(reader.getSystemID(),
|
||||
reader.getLineNr(),
|
||||
"<![[CDATA[");
|
||||
}
|
||||
|
||||
this.validator.PCDataAdded(this.reader.getSystemID(),
|
||||
this.reader.getLineNr());
|
||||
Reader r = new CDATAReader(this.reader);
|
||||
this.builder.addPCData(r, this.reader.getSystemID(),
|
||||
this.reader.getLineNr());
|
||||
r.close();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes a document type declaration.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
* if an error occurred reading or parsing the data
|
||||
*/
|
||||
protected void processDocType() throws Exception {
|
||||
if (! XMLUtil.checkLiteral(this.reader, "OCTYPE")) {
|
||||
XMLUtil.errorExpectedInput(reader.getSystemID(),
|
||||
reader.getLineNr(),
|
||||
"<!DOCTYPE");
|
||||
return;
|
||||
}
|
||||
|
||||
XMLUtil.skipWhitespace(this.reader, null);
|
||||
String systemID = null;
|
||||
StringBuffer publicID = new StringBuffer();
|
||||
/*String rootElement =*/ XMLUtil.scanIdentifier(this.reader);
|
||||
//System.out.println("rootElement is " + rootElement);
|
||||
XMLUtil.skipWhitespace(this.reader, null);
|
||||
char ch = this.reader.read();
|
||||
|
||||
if (ch == 'P') {
|
||||
systemID = XMLUtil.scanPublicID(publicID, reader);
|
||||
XMLUtil.skipWhitespace(this.reader, null);
|
||||
ch = this.reader.read();
|
||||
} else if (ch == 'S') {
|
||||
systemID = XMLUtil.scanSystemID(reader);
|
||||
XMLUtil.skipWhitespace(this.reader, null);
|
||||
ch = this.reader.read();
|
||||
}
|
||||
|
||||
if (ch == '[') {
|
||||
this.validator.parseDTD(publicID.toString(),
|
||||
this.reader,
|
||||
this.entityResolver,
|
||||
false);
|
||||
XMLUtil.skipWhitespace(this.reader, null);
|
||||
ch = this.reader.read();
|
||||
}
|
||||
|
||||
if (ch != '>') {
|
||||
XMLUtil.errorExpectedInput(reader.getSystemID(),
|
||||
reader.getLineNr(),
|
||||
"`>'");
|
||||
}
|
||||
|
||||
// TODO DTD checking is currently disabled, because it breaks
|
||||
// applications that don't have access to a net connection
|
||||
// (since it insists on going and checking out the DTD).
|
||||
if (false) {
|
||||
if (systemID != null) {
|
||||
Reader r = this.reader.openStream(publicID.toString(), systemID);
|
||||
this.reader.startNewStream(r);
|
||||
this.reader.setSystemID(systemID);
|
||||
this.reader.setPublicID(publicID.toString());
|
||||
this.validator.parseDTD(publicID.toString(),
|
||||
this.reader,
|
||||
this.entityResolver,
|
||||
true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes a regular element.
|
||||
*
|
||||
* @param defaultNamespace the default namespace URI (or null)
|
||||
* @param namespaces list of defined namespaces
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
* if something went wrong
|
||||
*/
|
||||
protected void processElement(String defaultNamespace,
|
||||
Properties namespaces)
|
||||
throws Exception
|
||||
{
|
||||
String fullName = XMLUtil.scanIdentifier(this.reader);
|
||||
String name = fullName;
|
||||
XMLUtil.skipWhitespace(this.reader, null);
|
||||
String prefix = null;
|
||||
int colonIndex = name.indexOf(':');
|
||||
|
||||
if (colonIndex > 0) {
|
||||
prefix = name.substring(0, colonIndex);
|
||||
name = name.substring(colonIndex + 1);
|
||||
}
|
||||
|
||||
Vector<String> attrNames = new Vector<String>();
|
||||
Vector<String> attrValues = new Vector<String>();
|
||||
Vector<String> attrTypes = new Vector<String>();
|
||||
|
||||
this.validator.elementStarted(fullName,
|
||||
this.reader.getSystemID(),
|
||||
this.reader.getLineNr());
|
||||
char ch;
|
||||
|
||||
for (;;) {
|
||||
ch = this.reader.read();
|
||||
|
||||
if ((ch == '/') || (ch == '>')) {
|
||||
break;
|
||||
}
|
||||
|
||||
this.reader.unread(ch);
|
||||
this.processAttribute(attrNames, attrValues, attrTypes);
|
||||
XMLUtil.skipWhitespace(this.reader, null);
|
||||
}
|
||||
|
||||
Properties extraAttributes = new Properties();
|
||||
this.validator.elementAttributesProcessed(fullName,
|
||||
extraAttributes,
|
||||
this.reader.getSystemID(),
|
||||
this.reader.getLineNr());
|
||||
Enumeration<?> en = extraAttributes.keys();
|
||||
|
||||
while (en.hasMoreElements()) {
|
||||
String key = (String) en.nextElement();
|
||||
String value = extraAttributes.getProperty(key);
|
||||
attrNames.addElement(key);
|
||||
attrValues.addElement(value);
|
||||
attrTypes.addElement("CDATA");
|
||||
}
|
||||
|
||||
for (int i = 0; i < attrNames.size(); i++) {
|
||||
String key = (String) attrNames.elementAt(i);
|
||||
String value = (String) attrValues.elementAt(i);
|
||||
//String type = (String) attrTypes.elementAt(i);
|
||||
|
||||
if (key.equals("xmlns")) {
|
||||
defaultNamespace = value;
|
||||
} else if (key.startsWith("xmlns:")) {
|
||||
namespaces.put(key.substring(6), value);
|
||||
}
|
||||
}
|
||||
|
||||
if (prefix == null) {
|
||||
this.builder.startElement(name, prefix, defaultNamespace,
|
||||
this.reader.getSystemID(),
|
||||
this.reader.getLineNr());
|
||||
} else {
|
||||
this.builder.startElement(name, prefix,
|
||||
namespaces.getProperty(prefix),
|
||||
this.reader.getSystemID(),
|
||||
this.reader.getLineNr());
|
||||
}
|
||||
|
||||
for (int i = 0; i < attrNames.size(); i++) {
|
||||
String key = (String) attrNames.elementAt(i);
|
||||
|
||||
if (key.startsWith("xmlns")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String value = (String) attrValues.elementAt(i);
|
||||
String type = (String) attrTypes.elementAt(i);
|
||||
colonIndex = key.indexOf(':');
|
||||
|
||||
if (colonIndex > 0) {
|
||||
String attPrefix = key.substring(0, colonIndex);
|
||||
key = key.substring(colonIndex + 1);
|
||||
this.builder.addAttribute(key, attPrefix,
|
||||
namespaces.getProperty(attPrefix),
|
||||
value, type);
|
||||
} else {
|
||||
this.builder.addAttribute(key, null, null, value, type);
|
||||
}
|
||||
}
|
||||
|
||||
if (prefix == null) {
|
||||
this.builder.elementAttributesProcessed(name, prefix,
|
||||
defaultNamespace);
|
||||
} else {
|
||||
this.builder.elementAttributesProcessed(name, prefix,
|
||||
namespaces
|
||||
.getProperty(prefix));
|
||||
}
|
||||
|
||||
if (ch == '/') {
|
||||
if (this.reader.read() != '>') {
|
||||
XMLUtil.errorExpectedInput(reader.getSystemID(),
|
||||
reader.getLineNr(),
|
||||
"`>'");
|
||||
}
|
||||
|
||||
this.validator.elementEnded(name,
|
||||
this.reader.getSystemID(),
|
||||
this.reader.getLineNr());
|
||||
|
||||
if (prefix == null) {
|
||||
this.builder.endElement(name, prefix, defaultNamespace);
|
||||
} else {
|
||||
this.builder.endElement(name, prefix,
|
||||
namespaces.getProperty(prefix));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
StringBuffer buffer = new StringBuffer(16);
|
||||
|
||||
for (;;) {
|
||||
buffer.setLength(0);
|
||||
String str;
|
||||
|
||||
for (;;) {
|
||||
XMLUtil.skipWhitespace(this.reader, buffer);
|
||||
str = XMLUtil.read(this.reader, '&');
|
||||
|
||||
if ((str.charAt(0) == '&') && (str.charAt(1) != '#')) {
|
||||
XMLUtil.processEntity(str, this.reader,
|
||||
this.entityResolver);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (str.charAt(0) == '<') {
|
||||
str = XMLUtil.read(this.reader, '\0');
|
||||
|
||||
if (str.charAt(0) == '/') {
|
||||
XMLUtil.skipWhitespace(this.reader, null);
|
||||
str = XMLUtil.scanIdentifier(this.reader);
|
||||
|
||||
if (! str.equals(fullName)) {
|
||||
XMLUtil.errorWrongClosingTag(reader.getSystemID(),
|
||||
reader.getLineNr(),
|
||||
name, str);
|
||||
}
|
||||
|
||||
XMLUtil.skipWhitespace(this.reader, null);
|
||||
|
||||
if (this.reader.read() != '>') {
|
||||
XMLUtil.errorClosingTagNotEmpty(reader.getSystemID(),
|
||||
reader.getLineNr());
|
||||
}
|
||||
|
||||
this.validator.elementEnded(fullName,
|
||||
this.reader.getSystemID(),
|
||||
this.reader.getLineNr());
|
||||
if (prefix == null) {
|
||||
this.builder.endElement(name, prefix, defaultNamespace);
|
||||
} else {
|
||||
this.builder.endElement(name, prefix,
|
||||
namespaces.getProperty(prefix));
|
||||
}
|
||||
break;
|
||||
} else { // <[^/]
|
||||
this.reader.unread(str.charAt(0));
|
||||
this.scanSomeTag(true, //CDATA allowed
|
||||
defaultNamespace,
|
||||
(Properties) namespaces.clone());
|
||||
}
|
||||
} else { // [^<]
|
||||
if (str.charAt(0) == '&') {
|
||||
ch = XMLUtil.processCharLiteral(str);
|
||||
buffer.append(ch);
|
||||
} else {
|
||||
reader.unread(str.charAt(0));
|
||||
}
|
||||
this.validator.PCDataAdded(this.reader.getSystemID(),
|
||||
this.reader.getLineNr());
|
||||
Reader r = new ContentReader(this.reader,
|
||||
this.entityResolver,
|
||||
buffer.toString());
|
||||
this.builder.addPCData(r, this.reader.getSystemID(),
|
||||
this.reader.getLineNr());
|
||||
r.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes an attribute of an element.
|
||||
*
|
||||
* @param attrNames contains the names of the attributes.
|
||||
* @param attrValues contains the values of the attributes.
|
||||
* @param attrTypes contains the types of the attributes.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
* if something went wrong
|
||||
*/
|
||||
protected void processAttribute(Vector<String> attrNames,
|
||||
Vector<String> attrValues,
|
||||
Vector<String> attrTypes)
|
||||
throws Exception
|
||||
{
|
||||
String key = XMLUtil.scanIdentifier(this.reader);
|
||||
XMLUtil.skipWhitespace(this.reader, null);
|
||||
|
||||
if (! XMLUtil.read(this.reader, '&').equals("=")) {
|
||||
XMLUtil.errorExpectedInput(reader.getSystemID(),
|
||||
reader.getLineNr(),
|
||||
"`='");
|
||||
}
|
||||
|
||||
XMLUtil.skipWhitespace(this.reader, null);
|
||||
String value = XMLUtil.scanString(this.reader, '&',
|
||||
this.entityResolver);
|
||||
attrNames.addElement(key);
|
||||
attrValues.addElement(value);
|
||||
attrTypes.addElement("CDATA");
|
||||
this.validator.attributeAdded(key, value,
|
||||
this.reader.getSystemID(),
|
||||
this.reader.getLineNr());
|
||||
}
|
||||
|
||||
}
|
626
core/src/processing/xml/StdXMLReader.java
Normal file
626
core/src/processing/xml/StdXMLReader.java
Normal file
@ -0,0 +1,626 @@
|
||||
/* StdXMLReader.java NanoXML/Java
|
||||
*
|
||||
* $Revision: 1.4 $
|
||||
* $Date: 2002/01/04 21:03:28 $
|
||||
* $Name: RELEASE_2_2_1 $
|
||||
*
|
||||
* This file is part of NanoXML 2 for Java.
|
||||
* Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from the
|
||||
* use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
package processing.xml;
|
||||
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.IOException;
|
||||
//import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.LineNumberReader;
|
||||
import java.io.PushbackReader;
|
||||
import java.io.PushbackInputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Stack;
|
||||
|
||||
|
||||
/**
|
||||
* StdXMLReader reads the data to be parsed.
|
||||
*
|
||||
* @author Marc De Scheemaecker
|
||||
* @version $Name: RELEASE_2_2_1 $, $Revision: 1.4 $
|
||||
*/
|
||||
public class StdXMLReader
|
||||
{
|
||||
|
||||
/**
|
||||
* A stacked reader.
|
||||
*
|
||||
* @author Marc De Scheemaecker
|
||||
* @version $Name: RELEASE_2_2_1 $, $Revision: 1.4 $
|
||||
*/
|
||||
private class StackedReader
|
||||
{
|
||||
|
||||
PushbackReader pbReader;
|
||||
|
||||
LineNumberReader lineReader;
|
||||
|
||||
URL systemId;
|
||||
|
||||
String publicId;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The stack of readers.
|
||||
*/
|
||||
private Stack<StackedReader> readers;
|
||||
|
||||
|
||||
/**
|
||||
* The current push-back reader.
|
||||
*/
|
||||
private StackedReader currentReader;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new reader using a string as input.
|
||||
*
|
||||
* @param str the string containing the XML data
|
||||
*/
|
||||
public static StdXMLReader stringReader(String str)
|
||||
{
|
||||
return new StdXMLReader(new StringReader(str));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new reader using a file as input.
|
||||
*
|
||||
* @param filename the name of the file containing the XML data
|
||||
*
|
||||
* @throws java.io.FileNotFoundException
|
||||
* if the file could not be found
|
||||
* @throws java.io.IOException
|
||||
* if an I/O error occurred
|
||||
*/
|
||||
public static StdXMLReader fileReader(String filename)
|
||||
throws FileNotFoundException,
|
||||
IOException
|
||||
{
|
||||
StdXMLReader r = new StdXMLReader(new FileInputStream(filename));
|
||||
r.setSystemID(filename);
|
||||
|
||||
for (int i = 0; i < r.readers.size(); i++) {
|
||||
StackedReader sr = (StackedReader) r.readers.elementAt(i);
|
||||
sr.systemId = r.currentReader.systemId;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the reader from a system and public ID.
|
||||
*
|
||||
* @param publicID the public ID which may be null.
|
||||
* @param systemID the non-null system ID.
|
||||
*
|
||||
* @throws MalformedURLException
|
||||
* if the system ID does not contain a valid URL
|
||||
* @throws FileNotFoundException
|
||||
* if the system ID refers to a local file which does not exist
|
||||
* @throws IOException
|
||||
* if an error occurred opening the stream
|
||||
*/
|
||||
public StdXMLReader(String publicID,
|
||||
String systemID)
|
||||
throws MalformedURLException,
|
||||
FileNotFoundException,
|
||||
IOException
|
||||
{
|
||||
URL systemIDasURL = null;
|
||||
|
||||
try {
|
||||
systemIDasURL = new URL(systemID);
|
||||
} catch (MalformedURLException e) {
|
||||
systemID = "file:" + systemID;
|
||||
|
||||
try {
|
||||
systemIDasURL = new URL(systemID);
|
||||
} catch (MalformedURLException e2) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
this.currentReader = new StackedReader();
|
||||
this.readers = new Stack<StackedReader>();
|
||||
Reader reader = this.openStream(publicID, systemIDasURL.toString());
|
||||
this.currentReader.lineReader = new LineNumberReader(reader);
|
||||
this.currentReader.pbReader
|
||||
= new PushbackReader(this.currentReader.lineReader, 2);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the XML reader.
|
||||
*
|
||||
* @param reader the input for the XML data.
|
||||
*/
|
||||
public StdXMLReader(Reader reader)
|
||||
{
|
||||
this.currentReader = new StackedReader();
|
||||
this.readers = new Stack<StackedReader>();
|
||||
this.currentReader.lineReader = new LineNumberReader(reader);
|
||||
this.currentReader.pbReader
|
||||
= new PushbackReader(this.currentReader.lineReader, 2);
|
||||
this.currentReader.publicId = "";
|
||||
|
||||
try {
|
||||
this.currentReader.systemId = new URL("file:.");
|
||||
} catch (MalformedURLException e) {
|
||||
// never happens
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cleans up the object when it's destroyed.
|
||||
*/
|
||||
protected void finalize()
|
||||
throws Throwable
|
||||
{
|
||||
this.currentReader.lineReader = null;
|
||||
this.currentReader.pbReader = null;
|
||||
this.currentReader.systemId = null;
|
||||
this.currentReader.publicId = null;
|
||||
this.currentReader = null;
|
||||
this.readers.clear();
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scans the encoding from an <?xml...?> tag.
|
||||
*
|
||||
* @param str the first tag in the XML data.
|
||||
*
|
||||
* @return the encoding, or null if no encoding has been specified.
|
||||
*/
|
||||
protected String getEncoding(String str)
|
||||
{
|
||||
if (! str.startsWith("<?xml")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int index = 5;
|
||||
|
||||
while (index < str.length()) {
|
||||
StringBuffer key = new StringBuffer();
|
||||
|
||||
while ((index < str.length()) && (str.charAt(index) <= ' ')) {
|
||||
index++;
|
||||
}
|
||||
|
||||
while ((index < str.length())
|
||||
&& (str.charAt(index) >= 'a')
|
||||
&& (str.charAt(index) <= 'z')) {
|
||||
key.append(str.charAt(index));
|
||||
index++;
|
||||
}
|
||||
|
||||
while ((index < str.length()) && (str.charAt(index) <= ' ')) {
|
||||
index++;
|
||||
}
|
||||
|
||||
if ((index >= str.length()) || (str.charAt(index) != '=')) {
|
||||
break;
|
||||
}
|
||||
|
||||
while ((index < str.length()) && (str.charAt(index) != '\'')
|
||||
&& (str.charAt(index) != '"')) {
|
||||
index++;
|
||||
}
|
||||
|
||||
if (index >= str.length()) {
|
||||
break;
|
||||
}
|
||||
|
||||
char delimiter = str.charAt(index);
|
||||
index++;
|
||||
int index2 = str.indexOf(delimiter, index);
|
||||
|
||||
if (index2 < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (key.toString().equals("encoding")) {
|
||||
return str.substring(index, index2);
|
||||
}
|
||||
|
||||
index = index2 + 1;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts a stream to a reader while detecting the encoding.
|
||||
*
|
||||
* @param stream the input for the XML data.
|
||||
* @param charsRead buffer where to put characters that have been read
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
* if an I/O error occurred
|
||||
*/
|
||||
protected Reader stream2reader(InputStream stream,
|
||||
StringBuffer charsRead)
|
||||
throws IOException
|
||||
{
|
||||
PushbackInputStream pbstream = new PushbackInputStream(stream);
|
||||
int b = pbstream.read();
|
||||
|
||||
switch (b) {
|
||||
case 0x00:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
pbstream.unread(b);
|
||||
return new InputStreamReader(pbstream, "UTF-16");
|
||||
|
||||
case 0xEF:
|
||||
for (int i = 0; i < 2; i++) {
|
||||
pbstream.read();
|
||||
}
|
||||
|
||||
return new InputStreamReader(pbstream, "UTF-8");
|
||||
|
||||
case 0x3C:
|
||||
b = pbstream.read();
|
||||
charsRead.append('<');
|
||||
|
||||
while ((b > 0) && (b != 0x3E)) {
|
||||
charsRead.append((char) b);
|
||||
b = pbstream.read();
|
||||
}
|
||||
|
||||
if (b > 0) {
|
||||
charsRead.append((char) b);
|
||||
}
|
||||
|
||||
String encoding = this.getEncoding(charsRead.toString());
|
||||
|
||||
if (encoding == null) {
|
||||
return new InputStreamReader(pbstream, "UTF-8");
|
||||
}
|
||||
|
||||
charsRead.setLength(0);
|
||||
|
||||
try {
|
||||
return new InputStreamReader(pbstream, encoding);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
return new InputStreamReader(pbstream, "UTF-8");
|
||||
}
|
||||
|
||||
default:
|
||||
charsRead.append((char) b);
|
||||
return new InputStreamReader(pbstream, "UTF-8");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the XML reader.
|
||||
*
|
||||
* @param stream the input for the XML data.
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
* if an I/O error occurred
|
||||
*/
|
||||
public StdXMLReader(InputStream stream)
|
||||
throws IOException
|
||||
{
|
||||
// unused?
|
||||
//PushbackInputStream pbstream = new PushbackInputStream(stream);
|
||||
StringBuffer charsRead = new StringBuffer();
|
||||
Reader reader = this.stream2reader(stream, charsRead);
|
||||
this.currentReader = new StackedReader();
|
||||
this.readers = new Stack<StackedReader>();
|
||||
this.currentReader.lineReader = new LineNumberReader(reader);
|
||||
this.currentReader.pbReader
|
||||
= new PushbackReader(this.currentReader.lineReader, 2);
|
||||
this.currentReader.publicId = "";
|
||||
|
||||
try {
|
||||
this.currentReader.systemId = new URL("file:.");
|
||||
} catch (MalformedURLException e) {
|
||||
// never happens
|
||||
}
|
||||
|
||||
this.startNewStream(new StringReader(charsRead.toString()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads a character.
|
||||
*
|
||||
* @return the character
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
* if no character could be read
|
||||
*/
|
||||
public char read()
|
||||
throws IOException
|
||||
{
|
||||
int ch = this.currentReader.pbReader.read();
|
||||
|
||||
while (ch < 0) {
|
||||
if (this.readers.empty()) {
|
||||
throw new IOException("Unexpected EOF");
|
||||
}
|
||||
|
||||
this.currentReader.pbReader.close();
|
||||
this.currentReader = (StackedReader) this.readers.pop();
|
||||
ch = this.currentReader.pbReader.read();
|
||||
}
|
||||
|
||||
return (char) ch;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the current stream has no more characters left to be
|
||||
* read.
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
* if an I/O error occurred
|
||||
*/
|
||||
public boolean atEOFOfCurrentStream()
|
||||
throws IOException
|
||||
{
|
||||
int ch = this.currentReader.pbReader.read();
|
||||
|
||||
if (ch < 0) {
|
||||
return true;
|
||||
} else {
|
||||
this.currentReader.pbReader.unread(ch);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if there are no more characters left to be read.
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
* if an I/O error occurred
|
||||
*/
|
||||
public boolean atEOF()
|
||||
throws IOException
|
||||
{
|
||||
int ch = this.currentReader.pbReader.read();
|
||||
|
||||
while (ch < 0) {
|
||||
if (this.readers.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
this.currentReader.pbReader.close();
|
||||
this.currentReader = (StackedReader) this.readers.pop();
|
||||
ch = this.currentReader.pbReader.read();
|
||||
}
|
||||
|
||||
this.currentReader.pbReader.unread(ch);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pushes the last character read back to the stream.
|
||||
*
|
||||
* @param ch the character to push back.
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
* if an I/O error occurred
|
||||
*/
|
||||
public void unread(char ch)
|
||||
throws IOException
|
||||
{
|
||||
this.currentReader.pbReader.unread(ch);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Opens a stream from a public and system ID.
|
||||
*
|
||||
* @param publicID the public ID, which may be null
|
||||
* @param systemID the system ID, which is never null
|
||||
*
|
||||
* @throws java.net.MalformedURLException
|
||||
* if the system ID does not contain a valid URL
|
||||
* @throws java.io.FileNotFoundException
|
||||
* if the system ID refers to a local file which does not exist
|
||||
* @throws java.io.IOException
|
||||
* if an error occurred opening the stream
|
||||
*/
|
||||
public Reader openStream(String publicID,
|
||||
String systemID)
|
||||
throws MalformedURLException,
|
||||
FileNotFoundException,
|
||||
IOException
|
||||
{
|
||||
URL url = new URL(this.currentReader.systemId, systemID);
|
||||
|
||||
if (url.getRef() != null) {
|
||||
String ref = url.getRef();
|
||||
|
||||
if (url.getFile().length() > 0) {
|
||||
url = new URL(url.getProtocol(), url.getHost(), url.getPort(),
|
||||
url.getFile());
|
||||
url = new URL("jar:" + url + '!' + ref);
|
||||
} else {
|
||||
url = StdXMLReader.class.getResource(ref);
|
||||
}
|
||||
}
|
||||
|
||||
this.currentReader.publicId = publicID;
|
||||
this.currentReader.systemId = url;
|
||||
StringBuffer charsRead = new StringBuffer();
|
||||
Reader reader = this.stream2reader(url.openStream(), charsRead);
|
||||
|
||||
if (charsRead.length() == 0) {
|
||||
return reader;
|
||||
}
|
||||
|
||||
String charsReadStr = charsRead.toString();
|
||||
PushbackReader pbreader = new PushbackReader(reader,
|
||||
charsReadStr.length());
|
||||
|
||||
for (int i = charsReadStr.length() - 1; i >= 0; i--) {
|
||||
pbreader.unread(charsReadStr.charAt(i));
|
||||
}
|
||||
|
||||
return pbreader;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Starts a new stream from a Java reader. The new stream is used
|
||||
* temporary to read data from. If that stream is exhausted, control
|
||||
* returns to the parent stream.
|
||||
*
|
||||
* @param reader the non-null reader to read the new data from
|
||||
*/
|
||||
public void startNewStream(Reader reader)
|
||||
{
|
||||
this.startNewStream(reader, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Starts a new stream from a Java reader. The new stream is used
|
||||
* temporary to read data from. If that stream is exhausted, control
|
||||
* returns to the parent stream.
|
||||
*
|
||||
* @param reader the non-null reader to read the new data from
|
||||
* @param isInternalEntity true if the reader is produced by resolving
|
||||
* an internal entity
|
||||
*/
|
||||
public void startNewStream(Reader reader,
|
||||
boolean isInternalEntity)
|
||||
{
|
||||
StackedReader oldReader = this.currentReader;
|
||||
this.readers.push(this.currentReader);
|
||||
this.currentReader = new StackedReader();
|
||||
|
||||
if (isInternalEntity) {
|
||||
this.currentReader.lineReader = null;
|
||||
this.currentReader.pbReader = new PushbackReader(reader, 2);
|
||||
} else {
|
||||
this.currentReader.lineReader = new LineNumberReader(reader);
|
||||
this.currentReader.pbReader
|
||||
= new PushbackReader(this.currentReader.lineReader, 2);
|
||||
}
|
||||
|
||||
this.currentReader.systemId = oldReader.systemId;
|
||||
this.currentReader.publicId = oldReader.publicId;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the current "level" of the stream on the stack of streams.
|
||||
*/
|
||||
public int getStreamLevel()
|
||||
{
|
||||
return this.readers.size();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the line number of the data in the current stream.
|
||||
*/
|
||||
public int getLineNr()
|
||||
{
|
||||
if (this.currentReader.lineReader == null) {
|
||||
StackedReader sr = (StackedReader) this.readers.peek();
|
||||
|
||||
if (sr.lineReader == null) {
|
||||
return 0;
|
||||
} else {
|
||||
return sr.lineReader.getLineNumber() + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return this.currentReader.lineReader.getLineNumber() + 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the system ID of the current stream.
|
||||
*
|
||||
* @param systemID the system ID
|
||||
*
|
||||
* @throws java.net.MalformedURLException
|
||||
* if the system ID does not contain a valid URL
|
||||
*/
|
||||
public void setSystemID(String systemID)
|
||||
throws MalformedURLException
|
||||
{
|
||||
this.currentReader.systemId = new URL(this.currentReader.systemId,
|
||||
systemID);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the public ID of the current stream.
|
||||
*
|
||||
* @param publicID the public ID
|
||||
*/
|
||||
public void setPublicID(String publicID)
|
||||
{
|
||||
this.currentReader.publicId = publicID;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the current system ID.
|
||||
*/
|
||||
public String getSystemID()
|
||||
{
|
||||
return this.currentReader.systemId.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the current public ID.
|
||||
*/
|
||||
public String getPublicID()
|
||||
{
|
||||
return this.currentReader.publicId;
|
||||
}
|
||||
|
||||
}
|
153
core/src/processing/xml/XMLAttribute.java
Normal file
153
core/src/processing/xml/XMLAttribute.java
Normal file
@ -0,0 +1,153 @@
|
||||
/* XMLAttribute.java NanoXML/Java
|
||||
*
|
||||
* $Revision: 1.4 $
|
||||
* $Date: 2002/01/04 21:03:29 $
|
||||
* $Name: RELEASE_2_2_1 $
|
||||
*
|
||||
* This file is part of NanoXML 2 for Java.
|
||||
* Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from the
|
||||
* use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
package processing.xml;
|
||||
|
||||
|
||||
/**
|
||||
* An attribute in an XML element. This is an internal class.
|
||||
*
|
||||
* @see net.n3.nanoxml.XMLElement
|
||||
*
|
||||
* @author Marc De Scheemaecker
|
||||
* @version $Name: RELEASE_2_2_1 $, $Revision: 1.4 $
|
||||
*/
|
||||
class XMLAttribute
|
||||
{
|
||||
|
||||
/**
|
||||
* The full name of the attribute.
|
||||
*/
|
||||
private String fullName;
|
||||
|
||||
|
||||
/**
|
||||
* The short name of the attribute.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
|
||||
/**
|
||||
* The namespace URI of the attribute.
|
||||
*/
|
||||
private String namespace;
|
||||
|
||||
|
||||
/**
|
||||
* The value of the attribute.
|
||||
*/
|
||||
private String value;
|
||||
|
||||
|
||||
/**
|
||||
* The type of the attribute.
|
||||
*/
|
||||
private String type;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new attribute.
|
||||
*
|
||||
* @param fullName the non-null full name
|
||||
* @param name the non-null short name
|
||||
* @param namespace the namespace URI, which may be null
|
||||
* @param value the value of the attribute
|
||||
* @param type the type of the attribute
|
||||
*/
|
||||
XMLAttribute(String fullName,
|
||||
String name,
|
||||
String namespace,
|
||||
String value,
|
||||
String type)
|
||||
{
|
||||
this.fullName = fullName;
|
||||
this.name = name;
|
||||
this.namespace = namespace;
|
||||
this.value = value;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the full name of the attribute.
|
||||
*/
|
||||
String getFullName()
|
||||
{
|
||||
return this.fullName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the short name of the attribute.
|
||||
*/
|
||||
String getName()
|
||||
{
|
||||
return this.name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the namespace of the attribute.
|
||||
*/
|
||||
String getNamespace()
|
||||
{
|
||||
return this.namespace;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the value of the attribute.
|
||||
*/
|
||||
String getValue()
|
||||
{
|
||||
return this.value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the value of the attribute.
|
||||
*
|
||||
* @param value the new value.
|
||||
*/
|
||||
void setValue(String value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the type of the attribute.
|
||||
*
|
||||
* @param type the new type.
|
||||
*/
|
||||
String getType()
|
||||
{
|
||||
return this.type;
|
||||
}
|
||||
|
||||
}
|
1353
core/src/processing/xml/XMLElement.java
Normal file
1353
core/src/processing/xml/XMLElement.java
Normal file
File diff suppressed because it is too large
Load Diff
173
core/src/processing/xml/XMLEntityResolver.java
Normal file
173
core/src/processing/xml/XMLEntityResolver.java
Normal file
@ -0,0 +1,173 @@
|
||||
/* XMLEntityResolver.java NanoXML/Java
|
||||
*
|
||||
* $Revision: 1.4 $
|
||||
* $Date: 2002/01/04 21:03:29 $
|
||||
* $Name: RELEASE_2_2_1 $
|
||||
*
|
||||
* This file is part of NanoXML 2 for Java.
|
||||
* Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from the
|
||||
* use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
package processing.xml;
|
||||
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
|
||||
|
||||
/**
|
||||
* An XMLEntityResolver resolves entities.
|
||||
*
|
||||
* @author Marc De Scheemaecker
|
||||
* @version $Name: RELEASE_2_2_1 $, $Revision: 1.4 $
|
||||
*/
|
||||
public class XMLEntityResolver
|
||||
{
|
||||
|
||||
/**
|
||||
* The entities.
|
||||
*/
|
||||
private Hashtable<String, Object> entities;
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the resolver.
|
||||
*/
|
||||
public XMLEntityResolver()
|
||||
{
|
||||
this.entities = new Hashtable<String, Object>();
|
||||
this.entities.put("amp", "&");
|
||||
this.entities.put("quot", """);
|
||||
this.entities.put("apos", "'");
|
||||
this.entities.put("lt", "<");
|
||||
this.entities.put("gt", ">");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cleans up the object when it's destroyed.
|
||||
*/
|
||||
protected void finalize()
|
||||
throws Throwable
|
||||
{
|
||||
this.entities.clear();
|
||||
this.entities = null;
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds an internal entity.
|
||||
*
|
||||
* @param name the name of the entity.
|
||||
* @param value the value of the entity.
|
||||
*/
|
||||
public void addInternalEntity(String name,
|
||||
String value)
|
||||
{
|
||||
if (! this.entities.containsKey(name)) {
|
||||
this.entities.put(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds an external entity.
|
||||
*
|
||||
* @param name the name of the entity.
|
||||
* @param publicID the public ID of the entity, which may be null.
|
||||
* @param systemID the system ID of the entity.
|
||||
*/
|
||||
public void addExternalEntity(String name,
|
||||
String publicID,
|
||||
String systemID)
|
||||
{
|
||||
if (! this.entities.containsKey(name)) {
|
||||
this.entities.put(name, new String[] { publicID, systemID } );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a Java reader containing the value of an entity.
|
||||
*
|
||||
* @param xmlReader the current XML reader
|
||||
* @param name the name of the entity.
|
||||
*
|
||||
* @return the reader, or null if the entity could not be resolved.
|
||||
*/
|
||||
public Reader getEntity(StdXMLReader xmlReader,
|
||||
String name)
|
||||
throws XMLParseException
|
||||
{
|
||||
Object obj = this.entities.get(name);
|
||||
|
||||
if (obj == null) {
|
||||
return null;
|
||||
} else if (obj instanceof java.lang.String) {
|
||||
return new StringReader((String)obj);
|
||||
} else {
|
||||
String[] id = (String[]) obj;
|
||||
return this.openExternalEntity(xmlReader, id[0], id[1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if an entity is external.
|
||||
*
|
||||
* @param name the name of the entity.
|
||||
*/
|
||||
public boolean isExternalEntity(String name)
|
||||
{
|
||||
Object obj = this.entities.get(name);
|
||||
return ! (obj instanceof java.lang.String);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Opens an external entity.
|
||||
*
|
||||
* @param xmlReader the current XML reader
|
||||
* @param publicID the public ID, which may be null
|
||||
* @param systemID the system ID
|
||||
*
|
||||
* @return the reader, or null if the reader could not be created/opened
|
||||
*/
|
||||
protected Reader openExternalEntity(StdXMLReader xmlReader,
|
||||
String publicID,
|
||||
String systemID)
|
||||
throws XMLParseException
|
||||
{
|
||||
String parentSystemID = xmlReader.getSystemID();
|
||||
|
||||
try {
|
||||
return xmlReader.openStream(publicID, systemID);
|
||||
} catch (Exception e) {
|
||||
throw new XMLParseException(parentSystemID,
|
||||
xmlReader.getLineNr(),
|
||||
"Could not open external entity "
|
||||
+ "at system ID: " + systemID);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
286
core/src/processing/xml/XMLException.java
Normal file
286
core/src/processing/xml/XMLException.java
Normal file
@ -0,0 +1,286 @@
|
||||
/* XMLException.java NanoXML/Java
|
||||
*
|
||||
* $Revision: 1.4 $
|
||||
* $Date: 2002/01/04 21:03:29 $
|
||||
* $Name: RELEASE_2_2_1 $
|
||||
*
|
||||
* This file is part of NanoXML 2 for Java.
|
||||
* Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from the
|
||||
* use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
package processing.xml;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
|
||||
/**
|
||||
* An XMLException is thrown when an exception occurred while processing the
|
||||
* XML data.
|
||||
*
|
||||
* @author Marc De Scheemaecker
|
||||
* @version $Name: RELEASE_2_2_1 $, $Revision: 1.4 $
|
||||
*/
|
||||
public class XMLException
|
||||
extends Exception
|
||||
{
|
||||
|
||||
/**
|
||||
* The message of the exception.
|
||||
*/
|
||||
private String msg;
|
||||
|
||||
|
||||
/**
|
||||
* The system ID of the XML data where the exception occurred.
|
||||
*/
|
||||
private String systemID;
|
||||
|
||||
|
||||
/**
|
||||
* The line number in the XML data where the exception occurred.
|
||||
*/
|
||||
private int lineNr;
|
||||
|
||||
|
||||
/**
|
||||
* Encapsulated exception.
|
||||
*/
|
||||
private Exception encapsulatedException;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new exception.
|
||||
*
|
||||
* @param msg the message of the exception.
|
||||
*/
|
||||
public XMLException(String msg)
|
||||
{
|
||||
this(null, -1, null, msg, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new exception.
|
||||
*
|
||||
* @param e the encapsulated exception.
|
||||
*/
|
||||
public XMLException(Exception e)
|
||||
{
|
||||
this(null, -1, e, "Nested Exception", false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new exception.
|
||||
*
|
||||
* @param systemID the system ID of the XML data where the exception
|
||||
* occurred
|
||||
* @param lineNr the line number in the XML data where the exception
|
||||
* occurred.
|
||||
* @param e the encapsulated exception.
|
||||
*/
|
||||
public XMLException(String systemID,
|
||||
int lineNr,
|
||||
Exception e)
|
||||
{
|
||||
this(systemID, lineNr, e, "Nested Exception", true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new exception.
|
||||
*
|
||||
* @param systemID the system ID of the XML data where the exception
|
||||
* occurred
|
||||
* @param lineNr the line number in the XML data where the exception
|
||||
* occurred.
|
||||
* @param msg the message of the exception.
|
||||
*/
|
||||
public XMLException(String systemID,
|
||||
int lineNr,
|
||||
String msg)
|
||||
{
|
||||
this(systemID, lineNr, null, msg, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new exception.
|
||||
*
|
||||
* @param systemID the system ID from where the data came
|
||||
* @param lineNr the line number in the XML data where the exception
|
||||
* occurred.
|
||||
* @param e the encapsulated exception.
|
||||
* @param msg the message of the exception.
|
||||
* @param reportParams true if the systemID, lineNr and e params need to be
|
||||
* appended to the message
|
||||
*/
|
||||
public XMLException(String systemID,
|
||||
int lineNr,
|
||||
Exception e,
|
||||
String msg,
|
||||
boolean reportParams)
|
||||
{
|
||||
super(XMLException.buildMessage(systemID, lineNr, e, msg,
|
||||
reportParams));
|
||||
this.systemID = systemID;
|
||||
this.lineNr = lineNr;
|
||||
this.encapsulatedException = e;
|
||||
this.msg = XMLException.buildMessage(systemID, lineNr, e, msg,
|
||||
reportParams);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Builds the exception message
|
||||
*
|
||||
* @param systemID the system ID from where the data came
|
||||
* @param lineNr the line number in the XML data where the exception
|
||||
* occurred.
|
||||
* @param e the encapsulated exception.
|
||||
* @param msg the message of the exception.
|
||||
* @param reportParams true if the systemID, lineNr and e params need to be
|
||||
* appended to the message
|
||||
*/
|
||||
private static String buildMessage(String systemID,
|
||||
int lineNr,
|
||||
Exception e,
|
||||
String msg,
|
||||
boolean reportParams)
|
||||
{
|
||||
String str = msg;
|
||||
|
||||
if (reportParams) {
|
||||
if (systemID != null) {
|
||||
str += ", SystemID='" + systemID + "'";
|
||||
}
|
||||
|
||||
if (lineNr >= 0) {
|
||||
str += ", Line=" + lineNr;
|
||||
}
|
||||
|
||||
if (e != null) {
|
||||
str += ", Exception: " + e;
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cleans up the object when it's destroyed.
|
||||
*/
|
||||
protected void finalize()
|
||||
throws Throwable
|
||||
{
|
||||
this.systemID = null;
|
||||
this.encapsulatedException = null;
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the system ID of the XML data where the exception occurred.
|
||||
* If there is no system ID known, null is returned.
|
||||
*/
|
||||
public String getSystemID()
|
||||
{
|
||||
return this.systemID;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the line number in the XML data where the exception occurred.
|
||||
* If there is no line number known, -1 is returned.
|
||||
*/
|
||||
public int getLineNr()
|
||||
{
|
||||
return this.lineNr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the encapsulated exception, or null if no exception is
|
||||
* encapsulated.
|
||||
*/
|
||||
public Exception getException()
|
||||
{
|
||||
return this.encapsulatedException;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Dumps the exception stack to a print writer.
|
||||
*
|
||||
* @param writer the print writer
|
||||
*/
|
||||
public void printStackTrace(PrintWriter writer)
|
||||
{
|
||||
super.printStackTrace(writer);
|
||||
|
||||
if (this.encapsulatedException != null) {
|
||||
writer.println("*** Nested Exception:");
|
||||
this.encapsulatedException.printStackTrace(writer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Dumps the exception stack to an output stream.
|
||||
*
|
||||
* @param stream the output stream
|
||||
*/
|
||||
public void printStackTrace(PrintStream stream)
|
||||
{
|
||||
super.printStackTrace(stream);
|
||||
|
||||
if (this.encapsulatedException != null) {
|
||||
stream.println("*** Nested Exception:");
|
||||
this.encapsulatedException.printStackTrace(stream);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Dumps the exception stack to System.err.
|
||||
*/
|
||||
public void printStackTrace()
|
||||
{
|
||||
super.printStackTrace();
|
||||
|
||||
if (this.encapsulatedException != null) {
|
||||
System.err.println("*** Nested Exception:");
|
||||
this.encapsulatedException.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a string representation of the exception.
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
return this.msg;
|
||||
}
|
||||
|
||||
}
|
69
core/src/processing/xml/XMLParseException.java
Normal file
69
core/src/processing/xml/XMLParseException.java
Normal file
@ -0,0 +1,69 @@
|
||||
/* XMLParseException.java NanoXML/Java
|
||||
*
|
||||
* $Revision: 1.3 $
|
||||
* $Date: 2002/01/04 21:03:29 $
|
||||
* $Name: RELEASE_2_2_1 $
|
||||
*
|
||||
* This file is part of NanoXML 2 for Java.
|
||||
* Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from the
|
||||
* use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
package processing.xml;
|
||||
|
||||
|
||||
/**
|
||||
* An XMLParseException is thrown when the XML passed to the XML parser is not
|
||||
* well-formed.
|
||||
*
|
||||
* @author Marc De Scheemaecker
|
||||
* @version $Name: RELEASE_2_2_1 $, $Revision: 1.3 $
|
||||
*/
|
||||
public class XMLParseException
|
||||
extends XMLException
|
||||
{
|
||||
|
||||
/**
|
||||
* Creates a new exception.
|
||||
*
|
||||
* @param msg the message of the exception.
|
||||
*/
|
||||
public XMLParseException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new exception.
|
||||
*
|
||||
* @param systemID the system ID from where the data came
|
||||
* @param lineNr the line number in the XML data where the exception
|
||||
* occurred.
|
||||
* @param msg the message of the exception.
|
||||
*/
|
||||
public XMLParseException(String systemID,
|
||||
int lineNr,
|
||||
String msg)
|
||||
{
|
||||
super(systemID, lineNr, null, msg, true);
|
||||
}
|
||||
|
||||
}
|
758
core/src/processing/xml/XMLUtil.java
Normal file
758
core/src/processing/xml/XMLUtil.java
Normal file
@ -0,0 +1,758 @@
|
||||
/* XMLUtil.java NanoXML/Java
|
||||
*
|
||||
* $Revision: 1.5 $
|
||||
* $Date: 2002/02/03 21:19:38 $
|
||||
* $Name: RELEASE_2_2_1 $
|
||||
*
|
||||
* This file is part of NanoXML 2 for Java.
|
||||
* Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from the
|
||||
* use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
package processing.xml;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
|
||||
|
||||
/**
|
||||
* Utility methods for NanoXML.
|
||||
*
|
||||
* @author Marc De Scheemaecker
|
||||
* @version $Name: RELEASE_2_2_1 $, $Revision: 1.5 $
|
||||
*/
|
||||
class XMLUtil
|
||||
{
|
||||
|
||||
/**
|
||||
* Skips the remainder of a comment.
|
||||
* It is assumed that <!- is already read.
|
||||
*
|
||||
* @param reader the reader
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
* if an error occurred reading the data
|
||||
*/
|
||||
static void skipComment(StdXMLReader reader)
|
||||
throws IOException,
|
||||
XMLParseException
|
||||
{
|
||||
if (reader.read() != '-') {
|
||||
XMLUtil.errorExpectedInput(reader.getSystemID(),
|
||||
reader.getLineNr(),
|
||||
"<!--");
|
||||
}
|
||||
|
||||
int dashesRead = 0;
|
||||
|
||||
for (;;) {
|
||||
char ch = reader.read();
|
||||
|
||||
switch (ch) {
|
||||
case '-':
|
||||
dashesRead++;
|
||||
break;
|
||||
|
||||
case '>':
|
||||
if (dashesRead == 2) {
|
||||
return;
|
||||
}
|
||||
dashesRead = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
dashesRead = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Skips the remainder of the current XML tag.
|
||||
*
|
||||
* @param reader the reader
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
* if an error occurred reading the data
|
||||
*/
|
||||
static void skipTag(StdXMLReader reader)
|
||||
throws IOException,
|
||||
XMLParseException
|
||||
{
|
||||
int level = 1;
|
||||
|
||||
while (level > 0) {
|
||||
char ch = reader.read();
|
||||
|
||||
switch (ch) {
|
||||
case '<':
|
||||
++level;
|
||||
break;
|
||||
|
||||
case '>':
|
||||
--level;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scans a public ID.
|
||||
*
|
||||
* @param publicID will contain the public ID
|
||||
* @param reader the reader
|
||||
*
|
||||
* @return the system ID
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
* if an error occurred reading the data
|
||||
*/
|
||||
static String scanPublicID(StringBuffer publicID,
|
||||
StdXMLReader reader)
|
||||
throws IOException,
|
||||
XMLParseException
|
||||
{
|
||||
if (! XMLUtil.checkLiteral(reader, "UBLIC")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
XMLUtil.skipWhitespace(reader, null);
|
||||
publicID.append(XMLUtil.scanString(reader, '\0', null));
|
||||
XMLUtil.skipWhitespace(reader, null);
|
||||
return XMLUtil.scanString(reader, '\0', null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scans a system ID.
|
||||
*
|
||||
* @param reader the reader
|
||||
*
|
||||
* @return the system ID
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
* if an error occurred reading the data
|
||||
*/
|
||||
static String scanSystemID(StdXMLReader reader)
|
||||
throws IOException,
|
||||
XMLParseException
|
||||
{
|
||||
if (! XMLUtil.checkLiteral(reader, "YSTEM")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
XMLUtil.skipWhitespace(reader, null);
|
||||
return XMLUtil.scanString(reader, '\0', null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves an identifier from the data.
|
||||
*
|
||||
* @param reader the reader
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
* if an error occurred reading the data
|
||||
*/
|
||||
static String scanIdentifier(StdXMLReader reader)
|
||||
throws IOException,
|
||||
XMLParseException
|
||||
{
|
||||
StringBuffer result = new StringBuffer();
|
||||
|
||||
for (;;) {
|
||||
char ch = reader.read();
|
||||
|
||||
if ((ch == '_') || (ch == ':') || (ch == '-') || (ch == '.')
|
||||
|| ((ch >= 'a') && (ch <= 'z'))
|
||||
|| ((ch >= 'A') && (ch <= 'Z'))
|
||||
|| ((ch >= '0') && (ch <= '9')) || (ch > '\u007E')) {
|
||||
result.append(ch);
|
||||
} else {
|
||||
reader.unread(ch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves a delimited string from the data.
|
||||
*
|
||||
* @param reader the reader
|
||||
* @param entityChar the escape character (& or %)
|
||||
* @param entityResolver the entity resolver
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
* if an error occurred reading the data
|
||||
*/
|
||||
static String scanString(StdXMLReader reader,
|
||||
char entityChar,
|
||||
XMLEntityResolver entityResolver)
|
||||
throws IOException,
|
||||
XMLParseException
|
||||
{
|
||||
StringBuffer result = new StringBuffer();
|
||||
int startingLevel = reader.getStreamLevel();
|
||||
char delim = reader.read();
|
||||
|
||||
if ((delim != '\'') && (delim != '"')) {
|
||||
XMLUtil.errorExpectedInput(reader.getSystemID(),
|
||||
reader.getLineNr(),
|
||||
"delimited string");
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
String str = XMLUtil.read(reader, entityChar);
|
||||
char ch = str.charAt(0);
|
||||
|
||||
if (ch == entityChar) {
|
||||
if (str.charAt(1) == '#') {
|
||||
result.append(XMLUtil.processCharLiteral(str));
|
||||
} else {
|
||||
XMLUtil.processEntity(str, reader, entityResolver);
|
||||
}
|
||||
} else if (ch == '&') {
|
||||
reader.unread(ch);
|
||||
str = XMLUtil.read(reader, '&');
|
||||
if (str.charAt(1) == '#') {
|
||||
result.append(XMLUtil.processCharLiteral(str));
|
||||
} else {
|
||||
result.append(str);
|
||||
}
|
||||
} else if (reader.getStreamLevel() == startingLevel) {
|
||||
if (ch == delim) {
|
||||
break;
|
||||
} else if ((ch == 9) || (ch == 10) || (ch == 13)) {
|
||||
result.append(' ');
|
||||
} else {
|
||||
result.append(ch);
|
||||
}
|
||||
} else {
|
||||
result.append(ch);
|
||||
}
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes an entity.
|
||||
*
|
||||
* @param entity the entity
|
||||
* @param reader the reader
|
||||
* @param entityResolver the entity resolver
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
* if an error occurred reading the data
|
||||
*/
|
||||
static void processEntity(String entity,
|
||||
StdXMLReader reader,
|
||||
XMLEntityResolver entityResolver)
|
||||
throws IOException,
|
||||
XMLParseException
|
||||
{
|
||||
entity = entity.substring(1, entity.length() - 1);
|
||||
Reader entityReader = entityResolver.getEntity(reader, entity);
|
||||
|
||||
if (entityReader == null) {
|
||||
XMLUtil.errorInvalidEntity(reader.getSystemID(),
|
||||
reader.getLineNr(),
|
||||
entity);
|
||||
}
|
||||
|
||||
boolean externalEntity = entityResolver.isExternalEntity(entity);
|
||||
reader.startNewStream(entityReader, !externalEntity);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes a character literal.
|
||||
*
|
||||
* @param entity the entity
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
* if an error occurred reading the data
|
||||
*/
|
||||
static char processCharLiteral(String entity)
|
||||
throws IOException,
|
||||
XMLParseException
|
||||
{
|
||||
if (entity.charAt(2) == 'x') {
|
||||
entity = entity.substring(3, entity.length() - 1);
|
||||
return (char) Integer.parseInt(entity, 16);
|
||||
} else {
|
||||
entity = entity.substring(2, entity.length() - 1);
|
||||
return (char) Integer.parseInt(entity, 10);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Skips whitespace from the reader.
|
||||
*
|
||||
* @param reader the reader
|
||||
* @param buffer where to put the whitespace; null if the
|
||||
* whitespace does not have to be stored.
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
* if an error occurred reading the data
|
||||
*/
|
||||
static void skipWhitespace(StdXMLReader reader,
|
||||
StringBuffer buffer)
|
||||
throws IOException
|
||||
{
|
||||
char ch;
|
||||
|
||||
if (buffer == null) {
|
||||
do {
|
||||
ch = reader.read();
|
||||
} while ((ch == ' ') || (ch == '\t') || (ch == '\n'));
|
||||
} else {
|
||||
for (;;) {
|
||||
ch = reader.read();
|
||||
|
||||
if ((ch != ' ') && (ch != '\t') && (ch != '\n')) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (ch == '\n') {
|
||||
buffer.append('\n');
|
||||
} else {
|
||||
buffer.append(' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reader.unread(ch);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads a character from the reader.
|
||||
*
|
||||
* @param reader the reader
|
||||
* @param entityChar the escape character (& or %) used to indicate
|
||||
* an entity
|
||||
*
|
||||
* @return the character, or an entity expression (like e.g. &lt;)
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
* if an error occurred reading the data
|
||||
*/
|
||||
static String read(StdXMLReader reader,
|
||||
char entityChar) throws IOException, XMLParseException {
|
||||
char ch = reader.read();
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append(ch);
|
||||
|
||||
if (ch == entityChar) {
|
||||
while (ch != ';') {
|
||||
ch = reader.read();
|
||||
buf.append(ch);
|
||||
}
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads a character from the reader disallowing entities.
|
||||
*
|
||||
* @param reader the reader
|
||||
* @param entityChar the escape character (& or %) used to indicate
|
||||
* an entity
|
||||
*/
|
||||
static char readChar(StdXMLReader reader,
|
||||
char entityChar) throws IOException, XMLParseException {
|
||||
String str = XMLUtil.read(reader, entityChar);
|
||||
char ch = str.charAt(0);
|
||||
|
||||
if (ch == entityChar) {
|
||||
XMLUtil.errorUnexpectedEntity(reader.getSystemID(),
|
||||
reader.getLineNr(),
|
||||
str);
|
||||
}
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the data starts with <I>literal</I>.
|
||||
* Enough chars are read to determine this result.
|
||||
*
|
||||
* @param reader the reader
|
||||
* @param literal the literal to check
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
* if an error occurred reading the data
|
||||
*/
|
||||
static boolean checkLiteral(StdXMLReader reader,
|
||||
String literal)
|
||||
throws IOException,
|
||||
XMLParseException
|
||||
{
|
||||
for (int i = 0; i < literal.length(); i++) {
|
||||
if (reader.read() != literal.charAt(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Throws an XMLParseException to indicate that an expected string is not
|
||||
* encountered.
|
||||
*
|
||||
* @param systemID the system ID of the data source
|
||||
* @param lineNr the line number in the data source
|
||||
* @param expectedString the string that is expected
|
||||
*/
|
||||
static void errorExpectedInput(String systemID,
|
||||
int lineNr,
|
||||
String expectedString)
|
||||
throws XMLParseException
|
||||
{
|
||||
throw new XMLParseException(systemID, lineNr,
|
||||
"Expected: " + expectedString);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Throws an XMLParseException to indicate that an entity could not be
|
||||
* resolved.
|
||||
*
|
||||
* @param systemID the system ID of the data source
|
||||
* @param lineNr the line number in the data source
|
||||
* @param entity the name of the entity
|
||||
*/
|
||||
static void errorInvalidEntity(String systemID,
|
||||
int lineNr,
|
||||
String entity)
|
||||
throws XMLParseException
|
||||
{
|
||||
throw new XMLParseException(systemID, lineNr,
|
||||
"Invalid entity: `&" + entity + ";'");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Throws an XMLParseException to indicate that an entity reference is
|
||||
* unexpected at this point.
|
||||
*
|
||||
* @param systemID the system ID of the data source
|
||||
* @param lineNr the line number in the data source
|
||||
* @param entity the name of the entity
|
||||
*/
|
||||
static void errorUnexpectedEntity(String systemID,
|
||||
int lineNr,
|
||||
String entity)
|
||||
throws XMLParseException
|
||||
{
|
||||
throw new XMLParseException(systemID, lineNr,
|
||||
"No entity reference is expected here ("
|
||||
+ entity + ")");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Throws an XMLParseException to indicate that a CDATA section is
|
||||
* unexpected at this point.
|
||||
*
|
||||
* @param systemID the system ID of the data source
|
||||
* @param lineNr the line number in the data source
|
||||
*/
|
||||
static void errorUnexpectedCDATA(String systemID,
|
||||
int lineNr)
|
||||
throws XMLParseException
|
||||
{
|
||||
throw new XMLParseException(systemID, lineNr,
|
||||
"No CDATA section is expected here");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Throws an XMLParseException to indicate that a string is not expected
|
||||
* at this point.
|
||||
*
|
||||
* @param systemID the system ID of the data source
|
||||
* @param lineNr the line number in the data source
|
||||
* @param unexpectedString the string that is unexpected
|
||||
*/
|
||||
static void errorInvalidInput(String systemID,
|
||||
int lineNr,
|
||||
String unexpectedString)
|
||||
throws XMLParseException
|
||||
{
|
||||
throw new XMLParseException(systemID, lineNr,
|
||||
"Invalid input: " + unexpectedString);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Throws an XMLParseException to indicate that the closing tag of an
|
||||
* element does not match the opening tag.
|
||||
*
|
||||
* @param systemID the system ID of the data source
|
||||
* @param lineNr the line number in the data source
|
||||
* @param expectedName the name of the opening tag
|
||||
* @param wrongName the name of the closing tag
|
||||
*/
|
||||
static void errorWrongClosingTag(String systemID,
|
||||
int lineNr,
|
||||
String expectedName,
|
||||
String wrongName)
|
||||
throws XMLParseException
|
||||
{
|
||||
throw new XMLParseException(systemID, lineNr,
|
||||
"Closing tag does not match opening tag: `"
|
||||
+ wrongName + "' != `" + expectedName
|
||||
+ "'");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Throws an XMLParseException to indicate that extra data is encountered
|
||||
* in a closing tag.
|
||||
*
|
||||
* @param systemID the system ID of the data source
|
||||
* @param lineNr the line number in the data source
|
||||
*/
|
||||
static void errorClosingTagNotEmpty(String systemID,
|
||||
int lineNr)
|
||||
throws XMLParseException
|
||||
{
|
||||
throw new XMLParseException(systemID, lineNr,
|
||||
"Closing tag must be empty");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Throws an XMLValidationException to indicate that an element is missing.
|
||||
*
|
||||
* @param systemID the system ID of the data source
|
||||
* @param lineNr the line number in the data source
|
||||
* @param parentElementName the name of the parent element
|
||||
* @param missingElementName the name of the missing element
|
||||
*/
|
||||
static void errorMissingElement(String systemID,
|
||||
int lineNr,
|
||||
String parentElementName,
|
||||
String missingElementName)
|
||||
throws XMLValidationException
|
||||
{
|
||||
throw new XMLValidationException(
|
||||
XMLValidationException.MISSING_ELEMENT,
|
||||
systemID, lineNr,
|
||||
missingElementName,
|
||||
/*attributeName*/ null,
|
||||
/*attributeValue*/ null,
|
||||
"Element " + parentElementName
|
||||
+ " expects to have a " + missingElementName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Throws an XMLValidationException to indicate that an element is
|
||||
* unexpected.
|
||||
*
|
||||
* @param systemID the system ID of the data source
|
||||
* @param lineNr the line number in the data source
|
||||
* @param parentElementName the name of the parent element
|
||||
* @param unexpectedElementName the name of the unexpected element
|
||||
*/
|
||||
static void errorUnexpectedElement(String systemID,
|
||||
int lineNr,
|
||||
String parentElementName,
|
||||
String unexpectedElementName)
|
||||
throws XMLValidationException
|
||||
{
|
||||
throw new XMLValidationException(
|
||||
XMLValidationException.UNEXPECTED_ELEMENT,
|
||||
systemID, lineNr,
|
||||
unexpectedElementName,
|
||||
/*attributeName*/ null,
|
||||
/*attributeValue*/ null,
|
||||
"Unexpected " + unexpectedElementName + " in a "
|
||||
+ parentElementName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Throws an XMLValidationException to indicate that an attribute is
|
||||
* missing.
|
||||
*
|
||||
* @param systemID the system ID of the data source
|
||||
* @param lineNr the line number in the data source
|
||||
* @param elementName the name of the element
|
||||
* @param attributeName the name of the missing attribute
|
||||
*/
|
||||
static void errorMissingAttribute(String systemID,
|
||||
int lineNr,
|
||||
String elementName,
|
||||
String attributeName)
|
||||
throws XMLValidationException
|
||||
{
|
||||
throw new XMLValidationException(
|
||||
XMLValidationException.MISSING_ATTRIBUTE,
|
||||
systemID, lineNr,
|
||||
elementName,
|
||||
attributeName,
|
||||
/*attributeValue*/ null,
|
||||
"Element " + elementName + " expects an attribute named "
|
||||
+ attributeName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Throws an XMLValidationException to indicate that an attribute is
|
||||
* unexpected.
|
||||
*
|
||||
* @param systemID the system ID of the data source
|
||||
* @param lineNr the line number in the data source
|
||||
* @param elementName the name of the element
|
||||
* @param attributeName the name of the unexpected attribute
|
||||
*/
|
||||
static void errorUnexpectedAttribute(String systemID,
|
||||
int lineNr,
|
||||
String elementName,
|
||||
String attributeName)
|
||||
throws XMLValidationException
|
||||
{
|
||||
throw new XMLValidationException(
|
||||
XMLValidationException.UNEXPECTED_ATTRIBUTE,
|
||||
systemID, lineNr,
|
||||
elementName,
|
||||
attributeName,
|
||||
/*attributeValue*/ null,
|
||||
"Element " + elementName + " did not expect an attribute "
|
||||
+ "named " + attributeName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Throws an XMLValidationException to indicate that an attribute has an
|
||||
* invalid value.
|
||||
*
|
||||
* @param systemID the system ID of the data source
|
||||
* @param lineNr the line number in the data source
|
||||
* @param elementName the name of the element
|
||||
* @param attributeName the name of the attribute
|
||||
* @param attributeValue the value of that attribute
|
||||
*/
|
||||
static void errorInvalidAttributeValue(String systemID,
|
||||
int lineNr,
|
||||
String elementName,
|
||||
String attributeName,
|
||||
String attributeValue)
|
||||
throws XMLValidationException
|
||||
{
|
||||
throw new XMLValidationException(
|
||||
XMLValidationException.ATTRIBUTE_WITH_INVALID_VALUE,
|
||||
systemID, lineNr,
|
||||
elementName,
|
||||
attributeName,
|
||||
attributeValue,
|
||||
"Invalid value for attribute " + attributeName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Throws an XMLValidationException to indicate that a #PCDATA element was
|
||||
* missing.
|
||||
*
|
||||
* @param systemID the system ID of the data source
|
||||
* @param lineNr the line number in the data source
|
||||
* @param parentElementName the name of the parent element
|
||||
*/
|
||||
static void errorMissingPCData(String systemID,
|
||||
int lineNr,
|
||||
String parentElementName)
|
||||
throws XMLValidationException
|
||||
{
|
||||
throw new XMLValidationException(
|
||||
XMLValidationException.MISSING_PCDATA,
|
||||
systemID, lineNr,
|
||||
/*elementName*/ null,
|
||||
/*attributeName*/ null,
|
||||
/*attributeValue*/ null,
|
||||
"Missing #PCDATA in element " + parentElementName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Throws an XMLValidationException to indicate that a #PCDATA element was
|
||||
* unexpected.
|
||||
*
|
||||
* @param systemID the system ID of the data source
|
||||
* @param lineNr the line number in the data source
|
||||
* @param parentElementName the name of the parent element
|
||||
*/
|
||||
static void errorUnexpectedPCData(String systemID,
|
||||
int lineNr,
|
||||
String parentElementName)
|
||||
throws XMLValidationException
|
||||
{
|
||||
throw new XMLValidationException(
|
||||
XMLValidationException.UNEXPECTED_PCDATA,
|
||||
systemID, lineNr,
|
||||
/*elementName*/ null,
|
||||
/*attributeName*/ null,
|
||||
/*attributeValue*/ null,
|
||||
"Unexpected #PCDATA in element " + parentElementName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Throws an XMLValidationException.
|
||||
*
|
||||
* @param systemID the system ID of the data source
|
||||
* @param lineNr the line number in the data source
|
||||
* @param message the error message
|
||||
* @param elementName the name of the element
|
||||
* @param attributeName the name of the attribute
|
||||
* @param attributeValue the value of that attribute
|
||||
*/
|
||||
static void validationError(String systemID,
|
||||
int lineNr,
|
||||
String message,
|
||||
String elementName,
|
||||
String attributeName,
|
||||
String attributeValue)
|
||||
throws XMLValidationException
|
||||
{
|
||||
throw new XMLValidationException(XMLValidationException.MISC_ERROR,
|
||||
systemID, lineNr,
|
||||
elementName,
|
||||
attributeName,
|
||||
attributeValue,
|
||||
message);
|
||||
}
|
||||
|
||||
}
|
190
core/src/processing/xml/XMLValidationException.java
Normal file
190
core/src/processing/xml/XMLValidationException.java
Normal file
@ -0,0 +1,190 @@
|
||||
/* XMLValidationException.java NanoXML/Java
|
||||
*
|
||||
* $Revision: 1.3 $
|
||||
* $Date: 2002/01/04 21:03:29 $
|
||||
* $Name: RELEASE_2_2_1 $
|
||||
*
|
||||
* This file is part of NanoXML 2 for Java.
|
||||
* Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from the
|
||||
* use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
package processing.xml;
|
||||
|
||||
|
||||
/**
|
||||
* An XMLValidationException is thrown when the XML passed to the XML parser is
|
||||
* well-formed but not valid.
|
||||
*
|
||||
* @author Marc De Scheemaecker
|
||||
* @version $Name: RELEASE_2_2_1 $, $Revision: 1.3 $
|
||||
*/
|
||||
public class XMLValidationException
|
||||
extends XMLException
|
||||
{
|
||||
|
||||
/**
|
||||
* An element was missing.
|
||||
*/
|
||||
public static final int MISSING_ELEMENT = 1;
|
||||
|
||||
|
||||
/**
|
||||
* An unexpected element was encountered.
|
||||
*/
|
||||
public static final int UNEXPECTED_ELEMENT = 2;
|
||||
|
||||
|
||||
/**
|
||||
* An attribute was missing.
|
||||
*/
|
||||
public static final int MISSING_ATTRIBUTE = 3;
|
||||
|
||||
|
||||
/**
|
||||
* An unexpected attribute was encountered.
|
||||
*/
|
||||
public static final int UNEXPECTED_ATTRIBUTE = 4;
|
||||
|
||||
|
||||
/**
|
||||
* An attribute has an invalid value.
|
||||
*/
|
||||
public static final int ATTRIBUTE_WITH_INVALID_VALUE = 5;
|
||||
|
||||
|
||||
/**
|
||||
* A PCDATA element was missing.
|
||||
*/
|
||||
public static final int MISSING_PCDATA = 6;
|
||||
|
||||
|
||||
/**
|
||||
* An unexpected PCDATA element was encountered.
|
||||
*/
|
||||
public static final int UNEXPECTED_PCDATA = 7;
|
||||
|
||||
|
||||
/**
|
||||
* Another error than those specified in this class was encountered.
|
||||
*/
|
||||
public static final int MISC_ERROR = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Which error occurred.
|
||||
*/
|
||||
//private int errorType;
|
||||
|
||||
|
||||
/**
|
||||
* The name of the element where the exception occurred.
|
||||
*/
|
||||
private String elementName;
|
||||
|
||||
|
||||
/**
|
||||
* The name of the attribute where the exception occurred.
|
||||
*/
|
||||
private String attributeName;
|
||||
|
||||
|
||||
/**
|
||||
* The value of the attribute where the exception occurred.
|
||||
*/
|
||||
private String attributeValue;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new exception.
|
||||
*
|
||||
* @param errorType the type of validity error
|
||||
* @param systemID the system ID from where the data came
|
||||
* @param lineNr the line number in the XML data where the
|
||||
* exception occurred.
|
||||
* @param elementName the name of the offending element
|
||||
* @param attributeName the name of the offending attribute
|
||||
* @param attributeValue the value of the offending attribute
|
||||
* @param msg the message of the exception.
|
||||
*/
|
||||
public XMLValidationException(int errorType,
|
||||
String systemID,
|
||||
int lineNr,
|
||||
String elementName,
|
||||
String attributeName,
|
||||
String attributeValue,
|
||||
String msg)
|
||||
{
|
||||
super(systemID, lineNr, null,
|
||||
msg + ((elementName == null) ? "" : (", element=" + elementName))
|
||||
+ ((attributeName == null) ? ""
|
||||
: (", attribute=" + attributeName))
|
||||
+ ((attributeValue == null) ? ""
|
||||
: (", value='" + attributeValue + "'")),
|
||||
false);
|
||||
this.elementName = elementName;
|
||||
this.attributeName = attributeName;
|
||||
this.attributeValue = attributeValue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cleans up the object when it's destroyed.
|
||||
*/
|
||||
protected void finalize()
|
||||
throws Throwable
|
||||
{
|
||||
this.elementName = null;
|
||||
this.attributeName = null;
|
||||
this.attributeValue = null;
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the name of the element in which the validation is violated.
|
||||
* If there is no current element, null is returned.
|
||||
*/
|
||||
public String getElementName()
|
||||
{
|
||||
return this.elementName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the name of the attribute in which the validation is violated.
|
||||
* If there is no current attribute, null is returned.
|
||||
*/
|
||||
public String getAttributeName()
|
||||
{
|
||||
return this.attributeName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the value of the attribute in which the validation is violated.
|
||||
* If there is no current attribute, null is returned.
|
||||
*/
|
||||
public String getAttributeValue()
|
||||
{
|
||||
return this.attributeValue;
|
||||
}
|
||||
|
||||
}
|
631
core/src/processing/xml/XMLValidator.java
Normal file
631
core/src/processing/xml/XMLValidator.java
Normal file
@ -0,0 +1,631 @@
|
||||
/* NonValidator.java NanoXML/Java
|
||||
*
|
||||
* $Revision: 1.4 $
|
||||
* $Date: 2002/02/03 21:19:38 $
|
||||
* $Name: RELEASE_2_2_1 $
|
||||
*
|
||||
* This file is part of NanoXML 2 for Java.
|
||||
* Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from the
|
||||
* use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
package processing.xml;
|
||||
|
||||
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Properties;
|
||||
import java.util.Stack;
|
||||
|
||||
|
||||
/**
|
||||
* XMLValidator implementation based on NonValidator (which implemented
|
||||
* IXMLValidator in the original NanoXML).
|
||||
* This implementation processes the DTD and handles entity definitions.
|
||||
* It does not do any validation itself.
|
||||
*
|
||||
* @author Marc De Scheemaecker
|
||||
* @author processing.org
|
||||
*/
|
||||
public class XMLValidator
|
||||
{
|
||||
|
||||
/**
|
||||
* The parameter entity resolver.
|
||||
*/
|
||||
protected XMLEntityResolver parameterEntityResolver;
|
||||
|
||||
|
||||
/**
|
||||
* Contains the default values for attributes for the different element
|
||||
* types.
|
||||
*/
|
||||
protected Hashtable<String, Properties> attributeDefaultValues;
|
||||
|
||||
|
||||
/**
|
||||
* The stack of elements to be processed.
|
||||
*/
|
||||
protected Stack<Properties> currentElements;
|
||||
|
||||
|
||||
/**
|
||||
* Creates the "validator".
|
||||
*/
|
||||
public XMLValidator()
|
||||
{
|
||||
this.attributeDefaultValues = new Hashtable<String, Properties>();
|
||||
this.currentElements = new Stack<Properties>();
|
||||
this.parameterEntityResolver = new XMLEntityResolver();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cleans up the object when it's destroyed.
|
||||
*/
|
||||
protected void finalize()
|
||||
throws Throwable
|
||||
{
|
||||
this.parameterEntityResolver = null;
|
||||
this.attributeDefaultValues.clear();
|
||||
this.attributeDefaultValues = null;
|
||||
this.currentElements.clear();
|
||||
this.currentElements = null;
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the parameter entity resolver.
|
||||
*
|
||||
* @param resolver the entity resolver.
|
||||
*/
|
||||
public void setParameterEntityResolver(XMLEntityResolver resolver)
|
||||
{
|
||||
this.parameterEntityResolver = resolver;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the parameter entity resolver.
|
||||
*
|
||||
* @return the entity resolver.
|
||||
*/
|
||||
public XMLEntityResolver getParameterEntityResolver()
|
||||
{
|
||||
return this.parameterEntityResolver;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parses the DTD. The validator object is responsible for reading the
|
||||
* full DTD.
|
||||
*
|
||||
* @param publicID the public ID, which may be null.
|
||||
* @param reader the reader to read the DTD from.
|
||||
* @param entityResolver the entity resolver.
|
||||
* @param external true if the DTD is external.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
* If something went wrong.
|
||||
*/
|
||||
public void parseDTD(String publicID,
|
||||
StdXMLReader reader,
|
||||
XMLEntityResolver entityResolver,
|
||||
boolean external)
|
||||
throws Exception
|
||||
{
|
||||
XMLUtil.skipWhitespace(reader, null);
|
||||
int origLevel = reader.getStreamLevel();
|
||||
|
||||
for (;;) {
|
||||
String str = XMLUtil.read(reader, '%');
|
||||
char ch = str.charAt(0);
|
||||
|
||||
if (ch == '%') {
|
||||
XMLUtil.processEntity(str, reader,
|
||||
this.parameterEntityResolver);
|
||||
continue;
|
||||
} else if (ch == '<') {
|
||||
this.processElement(reader, entityResolver);
|
||||
} else if (ch == ']') {
|
||||
return; // end internal DTD
|
||||
} else {
|
||||
XMLUtil.errorInvalidInput(reader.getSystemID(),
|
||||
reader.getLineNr(),
|
||||
str);
|
||||
}
|
||||
|
||||
do {
|
||||
ch = reader.read();
|
||||
|
||||
if (external && (reader.getStreamLevel() < origLevel)) {
|
||||
reader.unread(ch);
|
||||
return; // end external DTD
|
||||
}
|
||||
} while ((ch == ' ') || (ch == '\t') || (ch == '\n')
|
||||
|| (ch == '\r'));
|
||||
|
||||
reader.unread(ch);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes an element in the DTD.
|
||||
*
|
||||
* @param reader the reader to read data from.
|
||||
* @param entityResolver the entity resolver.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
* If something went wrong.
|
||||
*/
|
||||
protected void processElement(StdXMLReader reader,
|
||||
XMLEntityResolver entityResolver)
|
||||
throws Exception
|
||||
{
|
||||
String str = XMLUtil.read(reader, '%');
|
||||
char ch = str.charAt(0);
|
||||
|
||||
if (ch != '!') {
|
||||
XMLUtil.skipTag(reader);
|
||||
return;
|
||||
}
|
||||
|
||||
str = XMLUtil.read(reader, '%');
|
||||
ch = str.charAt(0);
|
||||
|
||||
switch (ch) {
|
||||
case '-':
|
||||
XMLUtil.skipComment(reader);
|
||||
break;
|
||||
|
||||
case '[':
|
||||
this.processConditionalSection(reader, entityResolver);
|
||||
break;
|
||||
|
||||
case 'E':
|
||||
this.processEntity(reader, entityResolver);
|
||||
break;
|
||||
|
||||
case 'A':
|
||||
this.processAttList(reader, entityResolver);
|
||||
break;
|
||||
|
||||
default:
|
||||
XMLUtil.skipTag(reader);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes a conditional section.
|
||||
*
|
||||
* @param reader the reader to read data from.
|
||||
* @param entityResolver the entity resolver.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
* If something went wrong.
|
||||
*/
|
||||
protected void processConditionalSection(StdXMLReader reader,
|
||||
XMLEntityResolver entityResolver)
|
||||
throws Exception
|
||||
{
|
||||
XMLUtil.skipWhitespace(reader, null);
|
||||
|
||||
String str = XMLUtil.read(reader, '%');
|
||||
char ch = str.charAt(0);
|
||||
|
||||
if (ch != 'I') {
|
||||
XMLUtil.skipTag(reader);
|
||||
return;
|
||||
}
|
||||
|
||||
str = XMLUtil.read(reader, '%');
|
||||
ch = str.charAt(0);
|
||||
|
||||
switch (ch) {
|
||||
case 'G':
|
||||
this.processIgnoreSection(reader, entityResolver);
|
||||
return;
|
||||
|
||||
case 'N':
|
||||
break;
|
||||
|
||||
default:
|
||||
XMLUtil.skipTag(reader);
|
||||
return;
|
||||
}
|
||||
|
||||
if (! XMLUtil.checkLiteral(reader, "CLUDE")) {
|
||||
XMLUtil.skipTag(reader);
|
||||
return;
|
||||
}
|
||||
|
||||
XMLUtil.skipWhitespace(reader, null);
|
||||
|
||||
str = XMLUtil.read(reader, '%');
|
||||
ch = str.charAt(0);
|
||||
|
||||
if (ch != '[') {
|
||||
XMLUtil.skipTag(reader);
|
||||
return;
|
||||
}
|
||||
|
||||
Reader subreader = new CDATAReader(reader);
|
||||
StringBuffer buf = new StringBuffer(1024);
|
||||
|
||||
for (;;) {
|
||||
int ch2 = subreader.read();
|
||||
|
||||
if (ch2 < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
buf.append((char) ch2);
|
||||
}
|
||||
|
||||
subreader.close();
|
||||
reader.startNewStream(new StringReader(buf.toString()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes an ignore section.
|
||||
*
|
||||
* @param reader the reader to read data from.
|
||||
* @param entityResolver the entity resolver.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
* If something went wrong.
|
||||
*/
|
||||
protected void processIgnoreSection(StdXMLReader reader,
|
||||
XMLEntityResolver entityResolver)
|
||||
throws Exception
|
||||
{
|
||||
if (! XMLUtil.checkLiteral(reader, "NORE")) {
|
||||
XMLUtil.skipTag(reader);
|
||||
return;
|
||||
}
|
||||
|
||||
XMLUtil.skipWhitespace(reader, null);
|
||||
|
||||
String str = XMLUtil.read(reader, '%');
|
||||
char ch = str.charAt(0);
|
||||
|
||||
if (ch != '[') {
|
||||
XMLUtil.skipTag(reader);
|
||||
return;
|
||||
}
|
||||
|
||||
Reader subreader = new CDATAReader(reader);
|
||||
subreader.close();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes an ATTLIST element.
|
||||
*
|
||||
* @param reader the reader to read data from.
|
||||
* @param entityResolver the entity resolver.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
* If something went wrong.
|
||||
*/
|
||||
protected void processAttList(StdXMLReader reader,
|
||||
XMLEntityResolver entityResolver)
|
||||
throws Exception
|
||||
{
|
||||
if (! XMLUtil.checkLiteral(reader, "TTLIST")) {
|
||||
XMLUtil.skipTag(reader);
|
||||
return;
|
||||
}
|
||||
|
||||
XMLUtil.skipWhitespace(reader, null);
|
||||
String str = XMLUtil.read(reader, '%');
|
||||
char ch = str.charAt(0);
|
||||
while (ch == '%') {
|
||||
XMLUtil.processEntity(str, reader,
|
||||
this.parameterEntityResolver);
|
||||
str = XMLUtil.read(reader, '%');
|
||||
ch = str.charAt(0);
|
||||
}
|
||||
reader.unread(ch);
|
||||
String elementName = XMLUtil.scanIdentifier(reader);
|
||||
XMLUtil.skipWhitespace(reader, null);
|
||||
|
||||
str = XMLUtil.read(reader, '%');
|
||||
ch = str.charAt(0);
|
||||
while (ch == '%') {
|
||||
XMLUtil.processEntity(str, reader,
|
||||
this.parameterEntityResolver);
|
||||
str = XMLUtil.read(reader, '%');
|
||||
ch = str.charAt(0);
|
||||
}
|
||||
|
||||
Properties props = new Properties();
|
||||
|
||||
while (ch != '>') {
|
||||
reader.unread(ch);
|
||||
String attName = XMLUtil.scanIdentifier(reader);
|
||||
XMLUtil.skipWhitespace(reader, null);
|
||||
str = XMLUtil.read(reader, '%');
|
||||
ch = str.charAt(0);
|
||||
while (ch == '%') {
|
||||
XMLUtil.processEntity(str, reader,
|
||||
this.parameterEntityResolver);
|
||||
str = XMLUtil.read(reader, '%');
|
||||
ch = str.charAt(0);
|
||||
}
|
||||
|
||||
if (ch == '(') {
|
||||
while (ch != ')') {
|
||||
str = XMLUtil.read(reader, '%');
|
||||
ch = str.charAt(0);
|
||||
while (ch == '%') {
|
||||
XMLUtil.processEntity(str, reader,
|
||||
this.parameterEntityResolver);
|
||||
str = XMLUtil.read(reader, '%');
|
||||
ch = str.charAt(0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader.unread(ch);
|
||||
XMLUtil.scanIdentifier(reader);
|
||||
}
|
||||
|
||||
XMLUtil.skipWhitespace(reader, null);
|
||||
str = XMLUtil.read(reader, '%');
|
||||
ch = str.charAt(0);
|
||||
while (ch == '%') {
|
||||
XMLUtil.processEntity(str, reader,
|
||||
this.parameterEntityResolver);
|
||||
str = XMLUtil.read(reader, '%');
|
||||
ch = str.charAt(0);
|
||||
}
|
||||
|
||||
if (ch == '#') {
|
||||
str = XMLUtil.scanIdentifier(reader);
|
||||
XMLUtil.skipWhitespace(reader, null);
|
||||
|
||||
if (! str.equals("FIXED")) {
|
||||
XMLUtil.skipWhitespace(reader, null);
|
||||
|
||||
str = XMLUtil.read(reader, '%');
|
||||
ch = str.charAt(0);
|
||||
while (ch == '%') {
|
||||
XMLUtil.processEntity(str, reader,
|
||||
this.parameterEntityResolver);
|
||||
str = XMLUtil.read(reader, '%');
|
||||
ch = str.charAt(0);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
reader.unread(ch);
|
||||
}
|
||||
|
||||
String value = XMLUtil.scanString(reader, '%',
|
||||
this.parameterEntityResolver);
|
||||
props.put(attName, value);
|
||||
XMLUtil.skipWhitespace(reader, null);
|
||||
|
||||
str = XMLUtil.read(reader, '%');
|
||||
ch = str.charAt(0);
|
||||
while (ch == '%') {
|
||||
XMLUtil.processEntity(str, reader,
|
||||
this.parameterEntityResolver);
|
||||
str = XMLUtil.read(reader, '%');
|
||||
ch = str.charAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (! props.isEmpty()) {
|
||||
this.attributeDefaultValues.put(elementName, props);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes an ENTITY element.
|
||||
*
|
||||
* @param reader the reader to read data from.
|
||||
* @param entityResolver the entity resolver.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
* If something went wrong.
|
||||
*/
|
||||
protected void processEntity(StdXMLReader reader,
|
||||
XMLEntityResolver entityResolver)
|
||||
throws Exception
|
||||
{
|
||||
if (! XMLUtil.checkLiteral(reader, "NTITY")) {
|
||||
XMLUtil.skipTag(reader);
|
||||
return;
|
||||
}
|
||||
|
||||
XMLUtil.skipWhitespace(reader, null);
|
||||
char ch = XMLUtil.readChar(reader, '\0');
|
||||
|
||||
if (ch == '%') {
|
||||
XMLUtil.skipWhitespace(reader, null);
|
||||
entityResolver = this.parameterEntityResolver;
|
||||
} else {
|
||||
reader.unread(ch);
|
||||
}
|
||||
|
||||
String key = XMLUtil.scanIdentifier(reader);
|
||||
XMLUtil.skipWhitespace(reader, null);
|
||||
ch = XMLUtil.readChar(reader, '%');
|
||||
String systemID = null;
|
||||
String publicID = null;
|
||||
|
||||
switch (ch) {
|
||||
case 'P':
|
||||
if (! XMLUtil.checkLiteral(reader, "UBLIC")) {
|
||||
XMLUtil.skipTag(reader);
|
||||
return;
|
||||
}
|
||||
|
||||
XMLUtil.skipWhitespace(reader, null);
|
||||
publicID = XMLUtil.scanString(reader, '%',
|
||||
this.parameterEntityResolver);
|
||||
XMLUtil.skipWhitespace(reader, null);
|
||||
systemID = XMLUtil.scanString(reader, '%',
|
||||
this.parameterEntityResolver);
|
||||
XMLUtil.skipWhitespace(reader, null);
|
||||
XMLUtil.readChar(reader, '%');
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
if (! XMLUtil.checkLiteral(reader, "YSTEM")) {
|
||||
XMLUtil.skipTag(reader);
|
||||
return;
|
||||
}
|
||||
|
||||
XMLUtil.skipWhitespace(reader, null);
|
||||
systemID = XMLUtil.scanString(reader, '%',
|
||||
this.parameterEntityResolver);
|
||||
XMLUtil.skipWhitespace(reader, null);
|
||||
XMLUtil.readChar(reader, '%');
|
||||
break;
|
||||
|
||||
case '"':
|
||||
case '\'':
|
||||
reader.unread(ch);
|
||||
String value = XMLUtil.scanString(reader, '%',
|
||||
this.parameterEntityResolver);
|
||||
entityResolver.addInternalEntity(key, value);
|
||||
XMLUtil.skipWhitespace(reader, null);
|
||||
XMLUtil.readChar(reader, '%');
|
||||
break;
|
||||
|
||||
default:
|
||||
XMLUtil.skipTag(reader);
|
||||
}
|
||||
|
||||
if (systemID != null) {
|
||||
entityResolver.addExternalEntity(key, publicID, systemID);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Indicates that an element has been started.
|
||||
*
|
||||
* @param name the name of the element.
|
||||
* @param systemId the system ID of the XML data of the element.
|
||||
* @param lineNr the line number in the XML data of the element.
|
||||
*/
|
||||
public void elementStarted(String name,
|
||||
String systemId,
|
||||
int lineNr)
|
||||
{
|
||||
Properties attribs
|
||||
= (Properties) this.attributeDefaultValues.get(name);
|
||||
|
||||
if (attribs == null) {
|
||||
attribs = new Properties();
|
||||
} else {
|
||||
attribs = (Properties) attribs.clone();
|
||||
}
|
||||
|
||||
this.currentElements.push(attribs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Indicates that the current element has ended.
|
||||
*
|
||||
* @param name the name of the element.
|
||||
* @param systemId the system ID of the XML data of the element.
|
||||
* @param lineNr the line number in the XML data of the element.
|
||||
*/
|
||||
public void elementEnded(String name,
|
||||
String systemId,
|
||||
int lineNr)
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method is called when the attributes of an XML element have been
|
||||
* processed.
|
||||
* If there are attributes with a default value which have not been
|
||||
* specified yet, they have to be put into <I>extraAttributes</I>.
|
||||
*
|
||||
* @param name the name of the element.
|
||||
* @param extraAttributes where to put extra attributes.
|
||||
* @param systemId the system ID of the XML data of the element.
|
||||
* @param lineNr the line number in the XML data of the element.
|
||||
*/
|
||||
public void elementAttributesProcessed(String name,
|
||||
Properties extraAttributes,
|
||||
String systemId,
|
||||
int lineNr)
|
||||
{
|
||||
Properties props = (Properties) this.currentElements.pop();
|
||||
Enumeration<?> en = props.keys();
|
||||
|
||||
while (en.hasMoreElements()) {
|
||||
String key = (String) en.nextElement();
|
||||
extraAttributes.put(key, props.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Indicates that an attribute has been added to the current element.
|
||||
*
|
||||
* @param key the name of the attribute.
|
||||
* @param value the value of the attribute.
|
||||
* @param systemId the system ID of the XML data of the element.
|
||||
* @param lineNr the line number in the XML data of the element.
|
||||
*/
|
||||
public void attributeAdded(String key,
|
||||
String value,
|
||||
String systemId,
|
||||
int lineNr)
|
||||
{
|
||||
Properties props = (Properties) this.currentElements.peek();
|
||||
|
||||
if (props.containsKey(key)) {
|
||||
props.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Indicates that a new #PCDATA element has been encountered.
|
||||
*
|
||||
* @param systemId the system ID of the XML data of the element.
|
||||
* @param lineNr the line number in the XML data of the element.
|
||||
*/
|
||||
public void PCDataAdded(String systemId,
|
||||
int lineNr)
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
}
|
307
core/src/processing/xml/XMLWriter.java
Normal file
307
core/src/processing/xml/XMLWriter.java
Normal file
@ -0,0 +1,307 @@
|
||||
/* XMLWriter.java NanoXML/Java
|
||||
*
|
||||
* $Revision: 1.4 $
|
||||
* $Date: 2002/03/24 11:37:51 $
|
||||
* $Name: RELEASE_2_2_1 $
|
||||
*
|
||||
* This file is part of NanoXML 2 for Java.
|
||||
* Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from the
|
||||
* use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
package processing.xml;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Vector;
|
||||
|
||||
|
||||
/**
|
||||
* An XMLWriter writes XML data to a stream.
|
||||
*
|
||||
* @author Marc De Scheemaecker
|
||||
*/
|
||||
public class XMLWriter
|
||||
{
|
||||
|
||||
/**
|
||||
* Where to write the output to.
|
||||
*/
|
||||
private PrintWriter writer;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new XML writer.
|
||||
*
|
||||
* @param writer where to write the output to.
|
||||
*/
|
||||
public XMLWriter(Writer writer)
|
||||
{
|
||||
if (writer instanceof PrintWriter) {
|
||||
this.writer = (PrintWriter) writer;
|
||||
} else {
|
||||
this.writer = new PrintWriter(writer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new XML writer.
|
||||
*
|
||||
* @param stream where to write the output to.
|
||||
*/
|
||||
public XMLWriter(OutputStream stream)
|
||||
{
|
||||
this.writer = new PrintWriter(stream);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cleans up the object when it's destroyed.
|
||||
*/
|
||||
protected void finalize()
|
||||
throws Throwable
|
||||
{
|
||||
this.writer = null;
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes an XML element.
|
||||
*
|
||||
* @param xml the non-null XML element to write.
|
||||
*/
|
||||
public void write(XMLElement xml)
|
||||
throws IOException
|
||||
{
|
||||
this.write(xml, false, 0, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes an XML element.
|
||||
*
|
||||
* @param xml the non-null XML element to write.
|
||||
* @param prettyPrint if spaces need to be inserted to make the output more
|
||||
* readable
|
||||
*/
|
||||
public void write(XMLElement xml,
|
||||
boolean prettyPrint)
|
||||
throws IOException
|
||||
{
|
||||
this.write(xml, prettyPrint, 0, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes an XML element.
|
||||
*
|
||||
* @param xml the non-null XML element to write.
|
||||
* @param prettyPrint if spaces need to be inserted to make the output more
|
||||
* readable
|
||||
* @param indent how many spaces to indent the element.
|
||||
*/
|
||||
public void write(XMLElement xml,
|
||||
boolean prettyPrint,
|
||||
int indent)
|
||||
throws IOException
|
||||
{
|
||||
this.write(xml, prettyPrint, indent, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes an XML element.
|
||||
*
|
||||
* @param xml the non-null XML element to write.
|
||||
* @param prettyPrint if spaces need to be inserted to make the output more
|
||||
* readable
|
||||
* @param indent how many spaces to indent the element.
|
||||
*/
|
||||
public void write(XMLElement xml,
|
||||
boolean prettyPrint,
|
||||
int indent,
|
||||
boolean collapseEmptyElements)
|
||||
throws IOException
|
||||
{
|
||||
if (prettyPrint) {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
this.writer.print(' ');
|
||||
}
|
||||
}
|
||||
|
||||
if (xml.getLocalName() == null) {
|
||||
if (xml.getContent() != null) {
|
||||
if (prettyPrint) {
|
||||
this.writeEncoded(xml.getContent().trim());
|
||||
writer.println();
|
||||
} else {
|
||||
this.writeEncoded(xml.getContent());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.writer.print('<');
|
||||
this.writer.print(xml.getName());
|
||||
Vector<String> nsprefixes = new Vector<String>();
|
||||
|
||||
if (xml.getNamespace() != null) {
|
||||
if (xml.getLocalName().equals(xml.getName())) {
|
||||
this.writer.print(" xmlns=\"" + xml.getNamespace() + '"');
|
||||
} else {
|
||||
String prefix = xml.getName();
|
||||
prefix = prefix.substring(0, prefix.indexOf(':'));
|
||||
nsprefixes.addElement(prefix);
|
||||
this.writer.print(" xmlns:" + prefix);
|
||||
this.writer.print("=\"" + xml.getNamespace() + "\"");
|
||||
}
|
||||
}
|
||||
|
||||
Enumeration<?> en = xml.enumerateAttributeNames();
|
||||
|
||||
while (en.hasMoreElements()) {
|
||||
String key = (String) en.nextElement();
|
||||
int index = key.indexOf(':');
|
||||
|
||||
if (index >= 0) {
|
||||
String namespace = xml.getAttributeNamespace(key);
|
||||
|
||||
if (namespace != null) {
|
||||
String prefix = key.substring(0, index);
|
||||
|
||||
if (! nsprefixes.contains(prefix)) {
|
||||
this.writer.print(" xmlns:" + prefix);
|
||||
this.writer.print("=\"" + namespace + '"');
|
||||
nsprefixes.addElement(prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
en = xml.enumerateAttributeNames();
|
||||
|
||||
while (en.hasMoreElements()) {
|
||||
String key = (String) en.nextElement();
|
||||
String value = xml.getAttribute(key, null);
|
||||
this.writer.print(" " + key + "=\"");
|
||||
this.writeEncoded(value);
|
||||
this.writer.print('"');
|
||||
}
|
||||
|
||||
if ((xml.getContent() != null)
|
||||
&& (xml.getContent().length() > 0)) {
|
||||
writer.print('>');
|
||||
this.writeEncoded(xml.getContent());
|
||||
writer.print("</" + xml.getName() + '>');
|
||||
|
||||
if (prettyPrint) {
|
||||
writer.println();
|
||||
}
|
||||
} else if (xml.hasChildren() || (! collapseEmptyElements)) {
|
||||
writer.print('>');
|
||||
|
||||
if (prettyPrint) {
|
||||
writer.println();
|
||||
}
|
||||
|
||||
en = xml.enumerateChildren();
|
||||
|
||||
while (en.hasMoreElements()) {
|
||||
XMLElement child = (XMLElement) en.nextElement();
|
||||
this.write(child, prettyPrint, indent + 4,
|
||||
collapseEmptyElements);
|
||||
}
|
||||
|
||||
if (prettyPrint) {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
this.writer.print(' ');
|
||||
}
|
||||
}
|
||||
|
||||
this.writer.print("</" + xml.getName() + ">");
|
||||
|
||||
if (prettyPrint) {
|
||||
writer.println();
|
||||
}
|
||||
} else {
|
||||
this.writer.print("/>");
|
||||
|
||||
if (prettyPrint) {
|
||||
writer.println();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.writer.flush();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes a string encoding reserved characters.
|
||||
*
|
||||
* @param str the string to write.
|
||||
*/
|
||||
private void writeEncoded(String str)
|
||||
{
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
char c = str.charAt(i);
|
||||
|
||||
switch (c) {
|
||||
case 0x0A:
|
||||
this.writer.print(c);
|
||||
break;
|
||||
|
||||
case '<':
|
||||
this.writer.print("<");
|
||||
break;
|
||||
|
||||
case '>':
|
||||
this.writer.print(">");
|
||||
break;
|
||||
|
||||
case '&':
|
||||
this.writer.print("&");
|
||||
break;
|
||||
|
||||
case '\'':
|
||||
this.writer.print("'");
|
||||
break;
|
||||
|
||||
case '"':
|
||||
this.writer.print(""");
|
||||
break;
|
||||
|
||||
default:
|
||||
if ((c < ' ') || (c > 0x7E)) {
|
||||
this.writer.print("&#x");
|
||||
this.writer.print(Integer.toString(c, 16));
|
||||
this.writer.print(';');
|
||||
} else {
|
||||
this.writer.print(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user