/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* Part of the Processing project - http://processing.org Copyright (c) 2006-10 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 version 2.1 as published by the Free Software Foundation. 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; import java.util.Map; /** * ( begin auto-generated from PShape.xml ) * * Datatype for storing shapes. Processing can currently load and display SVG * (Scalable Vector Graphics) shapes. Before a shape is used, it must be loaded * with the loadShape() function. The shape() * function is used to draw the shape to the display window. The * PShape object contain a group of methods, linked below, that can * operate on the shape data. * * The loadShape() function supports SVG files created with Inkscape and * Adobe Illustrator. It is not a full SVG implementation, but offers some * straightforward support for handling vector data. * * ( end auto-generated ) *
* 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. * *
* 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().
*
* @webref shape
* @usage Web & Application
* @see PApplet#loadShape(String)
* @see PApplet#createShape()
* @see PApplet#shapeMode(int)
* @instanceName sh any variable of type PShape
*/
public class PShape implements PConstants {
/**
*
*/
protected String name;
/**
*
*/
protected MapAdvanced
* Overrides this shape's style information and uses PGraphics styles and
* colors. Identical to ignoreStyles(true). Also disables styles for all child
* shapes.
*
* @webref pshape:method
* @usage web_application
* @brief Disables the shape's style data and uses Processing styles
* @see PShape#enableStyle()
*/
public void disableStyle() {
style = false;
for (int i = 0; i < childCount; i++) {
children[i].disableStyle();
}
}
/**
* ( begin auto-generated from PShape_enableStyle.xml )
*
* Enables the shape's style data and ignores Processing's current styles.
* Styles include attributes such as colors, stroke weight, and stroke joints.
*
*
* @webref pshape:method
* @usage web_application
* @brief Enables the shape's style data and ignores the Processing styles
* @see PShape#disableStyle()
*/
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).
*
* @return
*/
public float getWidth() {
//checkBounds();
return width;
}
/**
* Get the height of the drawing area (not necessarily the shape boundary).
*
* @return
*/
public float getHeight() {
//checkBounds();
return height;
}
/**
* Get the depth of the shape area (not necessarily the shape boundary).Only
* makes sense for 3D PShape subclasses, such as PShape3D.
*
* @return
*/
public float getDepth() {
//checkBounds();
return depth;
}
/*
// TODO unapproved
protected PVector getTop() {
return getTop(null);
}
protected PVector getTop(PVector top) {
if (top == null) {
top = new PVector();
}
return top;
}
protected PVector getBottom() {
return getBottom(null);
}
protected PVector getBottom(PVector bottom) {
if (bottom == null) {
bottom = new PVector();
}
return bottom;
}
*/
/**
* Return true if this shape is 2D.Defaults to true.
*
* @return
*/
public boolean is2D() {
return !is3D;
}
/**
* Return true if this shape is 3D.Defaults to false.
*
* @return
*/
public boolean is3D() {
return is3D;
}
/**
*
* @param val
*/
public void set3D(boolean val) {
is3D = val;
}
// /**
// * Return true if this shape requires rendering through OpenGL. Defaults to false.
// */
// // TODO unapproved
// public boolean isGL() {
// return false;
// }
///////////////////////////////////////////////////////////
//
// Drawing methods
/**
*
* @param mode
*/
public void textureMode(int mode) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "textureMode()");
return;
}
textureMode = mode;
}
/**
*
* @param tex
*/
public void texture(PImage tex) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "texture()");
return;
}
image = tex;
}
/**
*
*/
public void noTexture() {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "noTexture()");
return;
}
image = null;
}
// TODO unapproved
/**
*
* @param solid
*/
protected void solid(boolean solid) {
}
/**
* @webref shape:vertex
* @brief Starts a new contour
* @see PShape#endContour()
*/
public void beginContour() {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "beginContour()");
return;
}
if (family == GROUP) {
PGraphics.showWarning("Cannot begin contour in GROUP shapes");
return;
}
if (openContour) {
PGraphics.showWarning("Already called beginContour().");
return;
}
openContour = true;
beginContourImpl();
}
/**
*
*/
protected void beginContourImpl() {
if (vertexCodes == null) {
vertexCodes = new int[10];
} else if (vertexCodes.length == vertexCodeCount) {
vertexCodes = PApplet.expand(vertexCodes);
}
vertexCodes[vertexCodeCount++] = BREAK;
}
/**
* @webref shape:vertex
* @brief Ends a contour
* @see PShape#beginContour()
*/
public void endContour() {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "endContour()");
return;
}
if (family == GROUP) {
PGraphics.showWarning("Cannot end contour in GROUP shapes");
return;
}
if (!openContour) {
PGraphics.showWarning("Need to call beginContour() first.");
return;
}
endContourImpl();
openContour = false;
}
/**
*
*/
protected void endContourImpl() {
}
/**
*
* @param x
* @param y
*/
public void vertex(float x, float y) {
if (vertices == null) {
vertices = new float[10][2];
} else if (vertices.length == vertexCount) {
vertices = (float[][]) PApplet.expand(vertices);
}
vertices[vertexCount++] = new float[]{x, y};
if (vertexCodes == null) {
vertexCodes = new int[10];
} else if (vertexCodes.length == vertexCodeCount) {
vertexCodes = PApplet.expand(vertexCodes);
}
vertexCodes[vertexCodeCount++] = VERTEX;
if (x > width) {
width = x;
}
if (y > height) {
height = y;
}
}
/**
*
* @param x
* @param y
* @param u
* @param v
*/
public void vertex(float x, float y, float u, float v) {
}
/**
*
* @param x
* @param y
* @param z
*/
public void vertex(float x, float y, float z) {
vertex(x, y); // maybe? maybe not?
}
/**
*
* @param x
* @param y
* @param z
* @param u
* @param v
*/
public void vertex(float x, float y, float z, float u, float v) {
}
/**
*
* @param nx
* @param ny
* @param nz
*/
public void normal(float nx, float ny, float nz) {
}
/**
*
* @param name
* @param x
* @param y
* @param z
*/
public void attribPosition(String name, float x, float y, float z) {
}
/**
*
* @param name
* @param nx
* @param ny
* @param nz
*/
public void attribNormal(String name, float nx, float ny, float nz) {
}
/**
*
* @param name
* @param color
*/
public void attribColor(String name, int color) {
}
/**
*
* @param name
* @param values
*/
public void attrib(String name, float... values) {
}
/**
*
* @param name
* @param values
*/
public void attrib(String name, int... values) {
}
/**
*
* @param name
* @param values
*/
public void attrib(String name, boolean... values) {
}
/**
* @webref pshape:method
* @brief Starts the creation of a new PShape
* @see PApplet#endShape()
*/
public void beginShape() {
beginShape(POLYGON);
}
/**
*
* @param kind
*/
public void beginShape(int kind) {
this.kind = kind;
openShape = true;
}
/**
* @webref pshape:method
* @brief Finishes the creation of a new PShape
* @see PApplet#beginShape()
*/
public void endShape() {
endShape(OPEN);
}
/**
*
* @param mode
*/
public void endShape(int mode) {
if (family == GROUP) {
PGraphics.showWarning("Cannot end GROUP shape");
return;
}
if (!openShape) {
PGraphics.showWarning("Need to call beginShape() first");
return;
}
close = (mode == CLOSE);
// this is the state of the shape
openShape = false;
}
//////////////////////////////////////////////////////////////
// STROKE CAP/JOIN/WEIGHT
/**
*
* @param weight
*/
public void strokeWeight(float weight) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "strokeWeight()");
return;
}
strokeWeight = weight;
}
/**
*
* @param join
*/
public void strokeJoin(int join) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "strokeJoin()");
return;
}
strokeJoin = join;
}
/**
*
* @param cap
*/
public void strokeCap(int cap) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "strokeCap()");
return;
}
strokeCap = cap;
}
//////////////////////////////////////////////////////////////
// FILL COLOR
/**
*
*/
public void noFill() {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "noFill()");
return;
}
fill = false;
fillColor = 0x0;
if (!setAmbient) {
ambientColor = fillColor;
}
}
/**
*
* @param rgb
*/
public void fill(int rgb) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "fill()");
return;
}
fill = true;
colorCalc(rgb);
fillColor = calcColor;
if (!setAmbient) {
ambientColor = fillColor;
}
}
/**
*
* @param rgb
* @param alpha
*/
public void fill(int rgb, float alpha) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "fill()");
return;
}
fill = true;
colorCalc(rgb, alpha);
fillColor = calcColor;
if (!setAmbient) {
ambientColor = fillColor;
}
}
/**
*
* @param gray
*/
public void fill(float gray) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "fill()");
return;
}
fill = true;
colorCalc(gray);
fillColor = calcColor;
if (!setAmbient) {
ambientColor = fillColor;
}
}
/**
*
* @param gray
* @param alpha
*/
public void fill(float gray, float alpha) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "fill()");
return;
}
fill = true;
colorCalc(gray, alpha);
fillColor = calcColor;
if (!setAmbient) {
ambient(fillColor);
setAmbient = false;
}
if (!setAmbient) {
ambientColor = fillColor;
}
}
/**
*
* @param x
* @param y
* @param z
*/
public void fill(float x, float y, float z) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "fill()");
return;
}
fill = true;
colorCalc(x, y, z);
fillColor = calcColor;
if (!setAmbient) {
ambientColor = fillColor;
}
}
/**
*
* @param x
* @param y
* @param z
* @param a
*/
public void fill(float x, float y, float z, float a) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "fill()");
return;
}
fill = true;
colorCalc(x, y, z, a);
fillColor = calcColor;
if (!setAmbient) {
ambientColor = fillColor;
}
}
//////////////////////////////////////////////////////////////
// STROKE COLOR
/**
*
*/
public void noStroke() {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "noStroke()");
return;
}
stroke = false;
}
/**
*
* @param rgb
*/
public void stroke(int rgb) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "stroke()");
return;
}
stroke = true;
colorCalc(rgb);
strokeColor = calcColor;
}
/**
*
* @param rgb
* @param alpha
*/
public void stroke(int rgb, float alpha) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "stroke()");
return;
}
stroke = true;
colorCalc(rgb, alpha);
strokeColor = calcColor;
}
/**
*
* @param gray
*/
public void stroke(float gray) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "stroke()");
return;
}
stroke = true;
colorCalc(gray);
strokeColor = calcColor;
}
/**
*
* @param gray
* @param alpha
*/
public void stroke(float gray, float alpha) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "stroke()");
return;
}
stroke = true;
colorCalc(gray, alpha);
strokeColor = calcColor;
}
/**
*
* @param x
* @param y
* @param z
*/
public void stroke(float x, float y, float z) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "stroke()");
return;
}
stroke = true;
colorCalc(x, y, z);
strokeColor = calcColor;
}
/**
*
* @param x
* @param y
* @param z
* @param alpha
*/
public void stroke(float x, float y, float z, float alpha) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "stroke()");
return;
}
stroke = true;
colorCalc(x, y, z, alpha);
strokeColor = calcColor;
}
//////////////////////////////////////////////////////////////
// TINT COLOR
/**
*
*/
public void noTint() {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "noTint()");
return;
}
tint = false;
}
/**
*
* @param rgb
*/
public void tint(int rgb) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "tint()");
return;
}
tint = true;
colorCalc(rgb);
tintColor = calcColor;
}
/**
*
* @param rgb
* @param alpha
*/
public void tint(int rgb, float alpha) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "tint()");
return;
}
tint = true;
colorCalc(rgb, alpha);
tintColor = calcColor;
}
/**
*
* @param gray
*/
public void tint(float gray) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "tint()");
return;
}
tint = true;
colorCalc(gray);
tintColor = calcColor;
}
/**
*
* @param gray
* @param alpha
*/
public void tint(float gray, float alpha) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "tint()");
return;
}
tint = true;
colorCalc(gray, alpha);
tintColor = calcColor;
}
/**
*
* @param x
* @param y
* @param z
*/
public void tint(float x, float y, float z) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "tint()");
return;
}
tint = true;
colorCalc(x, y, z);
tintColor = calcColor;
}
/**
*
* @param x
* @param y
* @param z
* @param alpha
*/
public void tint(float x, float y, float z, float alpha) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "tint()");
return;
}
tint = true;
colorCalc(x, y, z, alpha);
tintColor = calcColor;
}
//////////////////////////////////////////////////////////////
// Ambient set/update
/**
*
* @param rgb
*/
public void ambient(int rgb) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "ambient()");
return;
}
setAmbient = true;
colorCalc(rgb);
ambientColor = calcColor;
}
/**
*
* @param gray
*/
public void ambient(float gray) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "ambient()");
return;
}
setAmbient = true;
colorCalc(gray);
ambientColor = calcColor;
}
/**
*
* @param x
* @param y
* @param z
*/
public void ambient(float x, float y, float z) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "ambient()");
return;
}
setAmbient = true;
colorCalc(x, y, z);
ambientColor = calcColor;
}
//////////////////////////////////////////////////////////////
// Specular set/update
/**
*
* @param rgb
*/
public void specular(int rgb) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "specular()");
return;
}
colorCalc(rgb);
specularColor = calcColor;
}
/**
*
* @param gray
*/
public void specular(float gray) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "specular()");
return;
}
colorCalc(gray);
specularColor = calcColor;
}
/**
*
* @param x
* @param y
* @param z
*/
public void specular(float x, float y, float z) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "specular()");
return;
}
colorCalc(x, y, z);
specularColor = calcColor;
}
//////////////////////////////////////////////////////////////
// Emissive set/update
/**
*
* @param rgb
*/
public void emissive(int rgb) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "emissive()");
return;
}
colorCalc(rgb);
emissiveColor = calcColor;
}
/**
*
* @param gray
*/
public void emissive(float gray) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "emissive()");
return;
}
colorCalc(gray);
emissiveColor = calcColor;
}
/**
*
* @param x
* @param y
* @param z
*/
public void emissive(float x, float y, float z) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "emissive()");
return;
}
colorCalc(x, y, z);
emissiveColor = calcColor;
}
//////////////////////////////////////////////////////////////
// Shininess set/update
/**
*
* @param shine
*/
public void shininess(float shine) {
if (!openShape) {
PGraphics.showWarning(OUTSIDE_BEGIN_END_ERROR, "shininess()");
return;
}
shininess = shine;
}
///////////////////////////////////////////////////////////
//
// Bezier curves
/**
*
* @param detail
*/
public void bezierDetail(int detail) {
}
/**
*
* @param x2
* @param y2
* @param x3
* @param y3
* @param x4
* @param y4
*/
public void bezierVertex(float x2, float y2,
float x3, float y3,
float x4, float y4) {
if (vertices == null) {
vertices = new float[10][];
} else if (vertexCount + 2 >= vertices.length) {
vertices = (float[][]) PApplet.expand(vertices);
}
vertices[vertexCount++] = new float[]{x2, y2};
vertices[vertexCount++] = new float[]{x3, y3};
vertices[vertexCount++] = new float[]{x4, y4};
// vertexCodes must be allocated because a vertex() call is required
if (vertexCodes.length == vertexCodeCount) {
vertexCodes = PApplet.expand(vertexCodes);
}
vertexCodes[vertexCodeCount++] = BEZIER_VERTEX;
if (x4 > width) {
width = x4;
}
if (y4 > height) {
height = y4;
}
}
/**
*
* @param x2
* @param y2
* @param z2
* @param x3
* @param y3
* @param z3
* @param x4
* @param y4
* @param z4
*/
public void bezierVertex(float x2, float y2, float z2,
float x3, float y3, float z3,
float x4, float y4, float z4) {
}
/**
*
* @param cx
* @param cy
* @param x3
* @param y3
*/
public void quadraticVertex(float cx, float cy,
float x3, float y3) {
if (vertices == null) {
vertices = new float[10][];
} else if (vertexCount + 1 >= vertices.length) {
vertices = (float[][]) PApplet.expand(vertices);
}
vertices[vertexCount++] = new float[]{cx, cy};
vertices[vertexCount++] = new float[]{x3, y3};
// vertexCodes must be allocated because a vertex() call is required
if (vertexCodes.length == vertexCodeCount) {
vertexCodes = PApplet.expand(vertexCodes);
}
vertexCodes[vertexCodeCount++] = QUADRATIC_VERTEX;
if (x3 > width) {
width = x3;
}
if (y3 > height) {
height = y3;
}
}
/**
*
* @param cx
* @param cy
* @param cz
* @param x3
* @param y3
* @param z3
*/
public void quadraticVertex(float cx, float cy, float cz,
float x3, float y3, float z3) {
}
///////////////////////////////////////////////////////////
//
// Catmull-Rom curves
/**
*
* @param detail
*/
public void curveDetail(int detail) {
}
/**
*
* @param tightness
*/
public void curveTightness(float tightness) {
}
/**
*
* @param x
* @param y
*/
public void curveVertex(float x, float y) {
}
/**
*
* @param x
* @param y
* @param z
*/
public void curveVertex(float x, float y, float z) {
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
/*
boolean strokeSaved;
int strokeColorSaved;
float strokeWeightSaved;
int strokeCapSaved;
int strokeJoinSaved;
boolean fillSaved;
int fillColorSaved;
int rectModeSaved;
int ellipseModeSaved;
int shapeModeSaved;
*/
/**
*
* @param g
*/
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);
}
}
/**
*
* @param 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();
}
}
/**
*
* @param g
*/
protected 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();
}
}
////////////////////////////////////////////////////////////////////////
//
// Shape copy
// TODO unapproved
/**
*
* @param parent
* @param src
* @return
*/
static protected PShape createShape(PApplet parent, PShape src) {
PShape dest = null;
switch (src.family) {
case GROUP:
dest = parent.createShape(GROUP);
PShape.copyGroup(parent, src, dest);
break;
case PRIMITIVE:
dest = parent.createShape(src.kind, src.params);
PShape.copyPrimitive(src, dest);
break;
case GEOMETRY:
dest = parent.createShape(src.kind);
PShape.copyGeometry(src, dest);
break;
case PATH:
dest = parent.createShape(PATH);
PShape.copyPath(src, dest);
break;
default:
break;
}
dest.setName(src.name);
return dest;
}
// TODO unapproved
/**
*
* @param parent
* @param src
* @param dest
*/
static protected void copyGroup(PApplet parent, PShape src, PShape dest) {
copyMatrix(src, dest);
copyStyles(src, dest);
copyImage(src, dest);
for (int i = 0; i < src.childCount; i++) {
PShape c = PShape.createShape(parent, src.children[i]);
dest.addChild(c);
}
}
// TODO unapproved
/**
*
* @param src
* @param dest
*/
static protected void copyPrimitive(PShape src, PShape dest) {
copyMatrix(src, dest);
copyStyles(src, dest);
copyImage(src, dest);
}
// TODO unapproved
/**
*
* @param src
* @param dest
*/
static protected void copyGeometry(PShape src, PShape dest) {
dest.beginShape(src.getKind());
copyMatrix(src, dest);
copyStyles(src, dest);
copyImage(src, dest);
if (src.style) {
for (int i = 0; i < src.vertexCount; i++) {
float[] vert = src.vertices[i];
dest.fill((int) (vert[PGraphics.A] * 255) << 24
| (int) (vert[PGraphics.R] * 255) << 16
| (int) (vert[PGraphics.G] * 255) << 8
| (int) (vert[PGraphics.B] * 255));
// Do we need to copy these as well?
// dest.ambient(vert[PGraphics.AR] * 255, vert[PGraphics.AG] * 255, vert[PGraphics.AB] * 255);
// dest.specular(vert[PGraphics.SPR] * 255, vert[PGraphics.SPG] * 255, vert[PGraphics.SPB] * 255);
// dest.emissive(vert[PGraphics.ER] * 255, vert[PGraphics.EG] * 255, vert[PGraphics.EB] * 255);
// dest.shininess(vert[PGraphics.SHINE]);
if (0 < PApplet.dist(vert[PGraphics.NX],
vert[PGraphics.NY],
vert[PGraphics.NZ], 0, 0, 0)) {
dest.normal(vert[PGraphics.NX],
vert[PGraphics.NY],
vert[PGraphics.NZ]);
}
dest.vertex(vert[X], vert[Y], vert[Z],
vert[PGraphics.U],
vert[PGraphics.V]);
}
} else {
for (int i = 0; i < src.vertexCount; i++) {
float[] vert = src.vertices[i];
if (vert[Z] == 0) {
dest.vertex(vert[X], vert[Y]);
} else {
dest.vertex(vert[X], vert[Y], vert[Z]);
}
}
}
dest.endShape();
}
// TODO unapproved
/**
*
* @param src
* @param dest
*/
static protected void copyPath(PShape src, PShape dest) {
copyMatrix(src, dest);
copyStyles(src, dest);
copyImage(src, dest);
dest.close = src.close;
dest.setPath(src.vertexCount, src.vertices, src.vertexCodeCount, src.vertexCodes);
}
// TODO unapproved
/**
*
* @param src
* @param dest
*/
static protected void copyMatrix(PShape src, PShape dest) {
if (src.matrix != null) {
dest.applyMatrix(src.matrix);
}
}
// TODO unapproved
/**
*
* @param src
* @param dest
*/
static protected void copyStyles(PShape src, PShape dest) {
dest.ellipseMode = src.ellipseMode;
dest.rectMode = src.rectMode;
if (src.stroke) {
dest.stroke = true;
dest.strokeColor = src.strokeColor;
dest.strokeWeight = src.strokeWeight;
dest.strokeCap = src.strokeCap;
dest.strokeJoin = src.strokeJoin;
} else {
dest.stroke = false;
}
if (src.fill) {
dest.fill = true;
dest.fillColor = src.fillColor;
} else {
dest.fill = false;
}
}
// TODO unapproved
/**
*
* @param src
* @param dest
*/
static protected void copyImage(PShape src, PShape dest) {
if (src.image != null) {
dest.texture(src.image);
}
}
////////////////////////////////////////////////////////////////////////
/**
* Called by the following (the shape() command adds the g) PShape s =
* loadShape("blah.svg"); shape(s);
*
* @param g
*/
public void draw(PGraphics g) {
if (visible) {
pre(g);
drawImpl(g);
post(g);
}
}
/**
* Draws the SVG document.
*
* @param g
*/
protected void drawImpl(PGraphics g) {
switch (family) {
case GROUP:
drawGroup(g);
break;
case PRIMITIVE:
drawPrimitive(g);
break;
case GEOMETRY:
// Not same as path: `kind` matters.
// drawPath(g);
drawGeometry(g);
break;
case PATH:
drawPath(g);
break;
default:
break;
}
}
/**
*
* @param g
*/
protected void drawGroup(PGraphics g) {
for (int i = 0; i < childCount; i++) {
children[i].draw(g);
}
}
/**
*
* @param g
*/
protected void drawPrimitive(PGraphics g) {
switch (kind) {
case POINT:
g.point(params[0], params[1]);
break;
case 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]);
}
break;
case TRIANGLE:
g.triangle(params[0], params[1],
params[2], params[3],
params[4], params[5]);
break;
case QUAD:
g.quad(params[0], params[1],
params[2], params[3],
params[4], params[5],
params[6], params[7]);
break;
case RECT:
if (image != null) {
int oldMode = g.imageMode;
g.imageMode(CORNER);
g.image(image, params[0], params[1], params[2], params[3]);
g.imageMode(oldMode);
} else {
int oldMode = g.rectMode;
g.rectMode(rectMode);
if (params.length == 4) {
g.rect(params[0], params[1],
params[2], params[3]);
} else if (params.length == 5) {
g.rect(params[0], params[1],
params[2], params[3],
params[4]);
} else if (params.length == 8) {
g.rect(params[0], params[1],
params[2], params[3],
params[4], params[5],
params[6], params[7]);
}
g.rectMode(oldMode);
}
break;
case ELLIPSE: {
int oldMode = g.ellipseMode;
g.ellipseMode(ellipseMode);
g.ellipse(params[0], params[1],
params[2], params[3]);
g.ellipseMode(oldMode);
break;
}
case ARC: {
int oldMode = g.ellipseMode;
g.ellipseMode(ellipseMode);
if (params.length == 6) {
g.arc(params[0], params[1],
params[2], params[3],
params[4], params[5]);
} else if (params.length == 7) {
g.arc(params[0], params[1],
params[2], params[3],
params[4], params[5],
(int) params[6]);
}
g.ellipseMode(oldMode);
break;
}
case BOX:
if (params.length == 1) {
g.box(params[0]);
} else {
g.box(params[0], params[1], params[2]);
}
break;
case SPHERE:
g.sphere(params[0]);
break;
default:
break;
}
}
/**
*
* @param g
*/
protected void drawGeometry(PGraphics g) {
// get cache object using 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[Z] == 0) {
g.vertex(vert[X], vert[Y]);
} else {
g.vertex(vert[X], vert[Y], vert[Z]);
}
}
}
g.endShape(close ? CLOSE : OPEN);
}
/*
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();
}
*/
/**
*
* @param g
*/
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;
}
boolean insideContour = false;
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 QUADRATIC_VERTEX:
g.quadraticVertex(vertices[index + 0][X], vertices[index + 0][Y],
vertices[index + 1][X], vertices[index + 1][Y]);
index += 2;
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++;
break;
case BREAK:
if (insideContour) {
g.endContour();
}
g.beginContour();
insideContour = true;
}
}
} 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 QUADRATIC_VERTEX:
g.quadraticVertex(vertices[index + 0][X], vertices[index + 0][Y], vertices[index + 0][Z],
vertices[index + 1][X], vertices[index + 1][Y], vertices[index + 0][Z]);
index += 2;
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++;
break;
case BREAK:
if (insideContour) {
g.endContour();
}
g.beginContour();
insideContour = true;
}
}
}
}
if (insideContour) {
g.endContour();
}
g.endShape(close ? CLOSE : OPEN);
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
/**
*
* @return
*/
public PShape getParent() {
return parent;
}
/**
* @return @webref @brief Returns the number of children
*/
public int getChildCount() {
return childCount;
}
/**
* Resize the children[] array to be in line with childCount
*/
protected void crop() {
// https://github.com/processing/processing/issues/3347
if (children.length != childCount) {
children = (PShape[]) PApplet.subset(children, 0, childCount);
}
}
/**
*
* @return
*/
public PShape[] getChildren() {
crop();
return children;
}
/**
* ( begin auto-generated from PShape_getChild.xml )
*
* Extracts a child shape from a parent shape.Specify the name of the shape
* with the target parameter. The shape is returned as a
* PShape object, or null is returned if there is an error.
*
*
* @return
* @webref pshape:method
* @usage web_application
* @brief Returns a child element of a shape as a PShape object
* @param index the layer position of the shape to get
* @see PShape#addChild(PShape)
*/
public PShape getChild(int index) {
crop();
return children[index];
}
/**
* @param target the name of the shape to get
* @return
*/
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 eldest grandparent, so that children can be found
* anywhere.
*
* @param target
* @return
*/
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
/**
* @webref pshape:method
* @brief Adds a new child
* @param who any variable of type PShape
* @see PShape#getChild(int)
*/
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);
}
}
// adds child who exactly at position idx in the array of children.
/**
* @param who
* @param idx the layer position in which to insert the new child
*/
public void addChild(PShape who, int idx) {
if (idx < childCount) {
if (childCount == children.length) {
children = (PShape[]) PApplet.expand(children);
}
// Copy [idx, childCount - 1] to [idx + 1, childCount]
for (int i = childCount - 1; i >= idx; i--) {
children[i + 1] = children[i];
}
childCount++;
children[idx] = who;
who.parent = this;
if (who.getName() != null) {
addName(who.getName(), who);
}
}
}
/**
* Remove the child shape with index idx.
*
* @param idx
*/
public void removeChild(int idx) {
if (idx < childCount) {
PShape child = children[idx];
// Copy [idx + 1, childCount - 1] to [idx, childCount - 2]
for (int i = idx; i < childCount - 1; i++) {
children[i] = children[i + 1];
}
childCount--;
if (child.getName() != null && nameTable != null) {
nameTable.remove(child.getName());
}
}
}
/**
* Add a shape to the name lookup table.
*
* @param nom
* @param shape
*/
public void addName(String nom, PShape shape) {
if (parent != null) {
parent.addName(nom, shape);
} else {
if (nameTable == null) {
nameTable = new HashMap<>();
}
nameTable.put(nom, shape);
}
}
/**
* Returns the index of child who.
*
* @param who
* @return
*/
public int getChildIndex(PShape who) {
for (int i = 0; i < childCount; i++) {
if (children[i] == who) {
return i;
}
}
return -1;
}
/**
*
* @return
*/
public PShape getTessellation() {
return null;
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
/**
* The shape type, one of GROUP, PRIMITIVE, PATH, or GEOMETRY.
*
* @return
*/
public int getFamily() {
return family;
}
/**
*
* @return
*/
public int getKind() {
return kind;
}
/**
*
* @return
*/
public float[] getParams() {
return getParams(null);
}
/**
*
* @param target
* @return
*/
public float[] getParams(float[] target) {
if (target == null || target.length != params.length) {
target = new float[params.length];
}
PApplet.arrayCopy(params, target);
return target;
}
/**
*
* @param index
* @return
*/
public float getParam(int index) {
return params[index];
}
/**
*
* @param source
*/
protected void setParams(float[] source) {
if (params == null) {
params = new float[source.length];
}
if (source.length != params.length) {
PGraphics.showWarning("Wrong number of parameters");
return;
}
PApplet.arrayCopy(source, params);
}
/**
*
* @param vcount
* @param verts
*/
public void setPath(int vcount, float[][] verts) {
setPath(vcount, verts, 0, null);
}
/**
*
* @param vcount
* @param verts
* @param ccount
* @param codes
*/
protected void setPath(int vcount, float[][] verts, int ccount, int[] codes) {
if (verts == null || verts.length < vcount) {
return;
}
if (0 < ccount && (codes == null || codes.length < ccount)) {
return;
}
int ndim = verts[0].length;
vertexCount = vcount;
vertices = new float[vertexCount][ndim];
for (int i = 0; i < vertexCount; i++) {
PApplet.arrayCopy(verts[i], vertices[i]);
}
vertexCodeCount = ccount;
if (0 < vertexCodeCount) {
vertexCodes = new int[vertexCodeCount];
PApplet.arrayCopy(codes, vertexCodes, vertexCodeCount);
}
}
/**
* @return @webref pshape:method
* @brief Returns the total number of vertices as an int
* @see PShape#getVertex(int)
* @see PShape#setVertex(int, float, float)
*/
public int getVertexCount() {
if (family == GROUP || family == PRIMITIVE) {
PGraphics.showWarning(NO_VERTICES_ERROR);
}
return vertexCount;
}
/**
* @return @webref pshape:method
* @brief Returns the vertex at the index position
* @param index the location of the vertex
* @see PShape#setVertex(int, float, float)
* @see PShape#getVertexCount()
*/
public PVector getVertex(int index) {
return getVertex(index, null);
}
/**
* @param index
* @param vec PVector to assign the data to
* @return
*/
public PVector getVertex(int index, PVector vec) {
if (vec == null) {
vec = new PVector();
}
float[] vert = vertices[index];
vec.x = vert[X];
vec.y = vert[Y];
if (vert.length > 2) {
vec.z = vert[Z];
} else {
vec.z = 0; // in case this isn't a new vector
}
return vec;
}
/**
*
* @param index
* @return
*/
public float getVertexX(int index) {
return vertices[index][X];
}
/**
*
* @param index
* @return
*/
public float getVertexY(int index) {
return vertices[index][Y];
}
/**
*
* @param index
* @return
*/
public float getVertexZ(int index) {
return vertices[index][Z];
}
/**
* @webref pshape:method
* @brief Sets the vertex at the index position
* @param index the location of the vertex
* @param x the x value for the vertex
* @param y the y value for the vertex
* @see PShape#getVertex(int)
* @see PShape#getVertexCount()
*/
public void setVertex(int index, float x, float y) {
if (openShape) {
PGraphics.showWarning(INSIDE_BEGIN_END_ERROR, "setVertex()");
return;
}
vertices[index][X] = x;
vertices[index][Y] = y;
}
/**
* @param index
* @param x
* @param z the z value for the vertex
* @param y
*/
public void setVertex(int index, float x, float y, float z) {
if (openShape) {
PGraphics.showWarning(INSIDE_BEGIN_END_ERROR, "setVertex()");
return;
}
vertices[index][X] = x;
vertices[index][Y] = y;
vertices[index][Z] = z;
}
/**
* @param index
* @param vec the PVector to define the x, y, z coordinates
*/
public void setVertex(int index, PVector vec) {
if (openShape) {
PGraphics.showWarning(INSIDE_BEGIN_END_ERROR, "setVertex()");
return;
}
vertices[index][X] = vec.x;
vertices[index][Y] = vec.y;
if (vertices[index].length > 2) {
vertices[index][Z] = vec.z;
} else if (vec.z != 0 && vec.z == vec.z) {
throw new IllegalArgumentException("Cannot set a z-coordinate on a 2D shape");
}
}
/**
*
* @param index
* @return
*/
public PVector getNormal(int index) {
return getNormal(index, null);
}
/**
*
* @param index
* @param vec
* @return
*/
public PVector getNormal(int index, PVector vec) {
if (vec == null) {
vec = new PVector();
}
vec.x = vertices[index][PGraphics.NX];
vec.y = vertices[index][PGraphics.NY];
vec.z = vertices[index][PGraphics.NZ];
return vec;
}
/**
*
* @param index
* @return
*/
public float getNormalX(int index) {
return vertices[index][PGraphics.NX];
}
/**
*
* @param index
* @return
*/
public float getNormalY(int index) {
return vertices[index][PGraphics.NY];
}
/**
*
* @param index
* @return
*/
public float getNormalZ(int index) {
return vertices[index][PGraphics.NZ];
}
/**
*
* @param index
* @param nx
* @param ny
* @param nz
*/
public void setNormal(int index, float nx, float ny, float nz) {
if (openShape) {
PGraphics.showWarning(INSIDE_BEGIN_END_ERROR, "setNormal()");
return;
}
vertices[index][PGraphics.NX] = nx;
vertices[index][PGraphics.NY] = ny;
vertices[index][PGraphics.NZ] = nz;
}
/**
*
* @param name
* @param index
* @param values
*/
public void setAttrib(String name, int index, float... values) {
}
/**
*
* @param name
* @param index
* @param values
*/
public void setAttrib(String name, int index, int... values) {
}
/**
*
* @param name
* @param index
* @param values
*/
public void setAttrib(String name, int index, boolean... values) {
}
/**
*
* @param index
* @return
*/
public float getTextureU(int index) {
return vertices[index][PGraphics.U];
}
/**
*
* @param index
* @return
*/
public float getTextureV(int index) {
return vertices[index][PGraphics.V];
}
/**
*
* @param index
* @param u
* @param v
*/
public void setTextureUV(int index, float u, float v) {
if (openShape) {
PGraphics.showWarning(INSIDE_BEGIN_END_ERROR, "setTextureUV()");
return;
}
// make sure we allocated the vertices array and that vertex exists
if (vertices == null
|| index >= vertices.length) {
PGraphics.showWarning(NO_SUCH_VERTEX_ERROR + " (" + index + ")", "setTextureUV()");
return;
}
vertices[index][PGraphics.U] = u;
vertices[index][PGraphics.V] = v;
}
/**
*
* @param mode
*/
public void setTextureMode(int mode) {
if (openShape) {
PGraphics.showWarning(INSIDE_BEGIN_END_ERROR, "setTextureMode()");
return;
}
textureMode = mode;
}
/**
*
* @param tex
*/
public void setTexture(PImage tex) {
if (openShape) {
PGraphics.showWarning(INSIDE_BEGIN_END_ERROR, "setTexture()");
return;
}
image = tex;
}
/**
*
* @param index
* @return
*/
public int getFill(int index) {
// make sure we allocated the vertices array and that vertex exists
if (vertices == null
|| index >= vertices.length) {
PGraphics.showWarning(NO_SUCH_VERTEX_ERROR + " (" + index + ")", "getFill()");
return fillColor;
}
if (image == null) {
int a = (int) (vertices[index][PGraphics.A] * 255);
int r = (int) (vertices[index][PGraphics.R] * 255);
int green = (int) (vertices[index][PGraphics.G] * 255);
int b = (int) (vertices[index][PGraphics.B] * 255);
return (a << 24) | (r << 16) | (green << 8) | b;
} else {
return 0;
}
}
/**
* @param fill
* @nowebref
*/
public void setFill(boolean fill) {
if (openShape) {
PGraphics.showWarning(INSIDE_BEGIN_END_ERROR, "setFill()");
return;
}
this.fill = fill;
}
/**
* ( begin auto-generated from PShape_setFill.xml )
*
* The setFill() method defines the fill color of a PShape. This
* method is used after shapes are created or when a shape is defined
* explicitly (e.g. createShape(RECT, 20, 20, 80, 80)) as shown in the
* above example. When a shape is created with beginShape() and
* endShape(), its attributes may be changed with fill() and
* stroke() within
* beginShape() and endShape(). However, after the shape is
* created, only the setFill() method can define a new fill value for
* the PShape.
*
*
* @webref
* @param fill
* @brief Set the fill value
*/
public void setFill(int fill) {
if (openShape) {
PGraphics.showWarning(INSIDE_BEGIN_END_ERROR, "setFill()");
return;
}
this.fillColor = fill;
if (vertices != null && perVertexStyles) {
for (int i = 0; i < vertexCount; i++) {
setFill(i, fill);
}
}
}
/**
* @param index
* @param fill
* @nowebref
*/
public void setFill(int index, int fill) {
if (openShape) {
PGraphics.showWarning(INSIDE_BEGIN_END_ERROR, "setFill()");
return;
}
if (!perVertexStyles) {
PGraphics.showWarning(PER_VERTEX_UNSUPPORTED, "setFill()");
return;
}
// make sure we allocated the vertices array and that vertex exists
if (vertices == null || index >= vertices.length) {
PGraphics.showWarning(NO_SUCH_VERTEX_ERROR + " (" + index + ")", "getFill()");
return;
}
if (image == null) {
vertices[index][PGraphics.A] = ((fill >> 24) & 0xFF) / 255.0f;
vertices[index][PGraphics.R] = ((fill >> 16) & 0xFF) / 255.0f;
vertices[index][PGraphics.G] = ((fill >> 8) & 0xFF) / 255.0f;
vertices[index][PGraphics.B] = ((fill) & 0xFF) / 255.0f;
}
}
/**
*
* @param index
* @return
*/
public int getTint(int index) {
// make sure we allocated the vertices array and that vertex exists
if (vertices == null || index >= vertices.length) {
PGraphics.showWarning(NO_SUCH_VERTEX_ERROR + " (" + index + ")", "getTint()");
return this.tintColor;
}
if (image != null) {
int a = (int) (vertices[index][PGraphics.A] * 255);
int r = (int) (vertices[index][PGraphics.R] * 255);
int green = (int) (vertices[index][PGraphics.G] * 255);
int b = (int) (vertices[index][PGraphics.B] * 255);
return (a << 24) | (r << 16) | (green << 8) | b;
} else {
return 0;
}
}
/**
*
* @param tint
*/
public void setTint(boolean tint) {
if (openShape) {
PGraphics.showWarning(INSIDE_BEGIN_END_ERROR, "setTint()");
return;
}
this.tint = tint;
}
/**
*
* @param fill
*/
public void setTint(int fill) {
if (openShape) {
PGraphics.showWarning(INSIDE_BEGIN_END_ERROR, "setTint()");
return;
}
tintColor = fill;
if (vertices != null) {
for (int i = 0; i < vertices.length; i++) {
setFill(i, fill);
}
}
}
/**
*
* @param index
* @param tint
*/
public void setTint(int index, int tint) {
if (openShape) {
PGraphics.showWarning(INSIDE_BEGIN_END_ERROR, "setTint()");
return;
}
// make sure we allocated the vertices array and that vertex exists
if (vertices == null
|| index >= vertices.length) {
PGraphics.showWarning(NO_SUCH_VERTEX_ERROR + " (" + index + ")", "setTint()");
return;
}
if (image != null) {
vertices[index][PGraphics.A] = ((tint >> 24) & 0xFF) / 255.0f;
vertices[index][PGraphics.R] = ((tint >> 16) & 0xFF) / 255.0f;
vertices[index][PGraphics.G] = ((tint >> 8) & 0xFF) / 255.0f;
vertices[index][PGraphics.B] = ((tint) & 0xFF) / 255.0f;
}
}
/**
*
* @param index
* @return
*/
public int getStroke(int index) {
// make sure we allocated the vertices array and that vertex exists
if (vertices == null
|| index >= vertices.length) {
PGraphics.showWarning(NO_SUCH_VERTEX_ERROR + " (" + index + ")", "getStroke()");
return strokeColor;
}
int a = (int) (vertices[index][PGraphics.SA] * 255);
int r = (int) (vertices[index][PGraphics.SR] * 255);
int green = (int) (vertices[index][PGraphics.SG] * 255);
int b = (int) (vertices[index][PGraphics.SB] * 255);
return (a << 24) | (r << 16) | (green << 8) | b;
}
/**
* @param stroke
* @nowebref
*/
public void setStroke(boolean stroke) {
if (openShape) {
PGraphics.showWarning(INSIDE_BEGIN_END_ERROR, "setStroke()");
return;
}
this.stroke = stroke;
}
/**
* ( begin auto-generated from PShape_setStroke.xml )
*
* The setStroke() method defines the outline color of a PShape.
* This method is used after shapes are created or when a shape is defined
* explicitly (e.g. createShape(RECT, 20, 20, 80, 80)) as shown in the
* above example. When a shape is created with beginShape() and
* endShape(), its attributes may be changed with fill() and
* stroke() within beginShape() and endShape(). However,
* after the shape is created, only the setStroke() method can define a
* new stroke value for the PShape.
*
*
* @webref
* @param stroke
* @brief Set the stroke value
*/
public void setStroke(int stroke) {
if (openShape) {
PGraphics.showWarning(INSIDE_BEGIN_END_ERROR, "setStroke()");
return;
}
strokeColor = stroke;
if (vertices != null && perVertexStyles) {
for (int i = 0; i < vertices.length; i++) {
setStroke(i, stroke);
}
}
}
/**
* @param index
* @param stroke
* @nowebref
*/
public void setStroke(int index, int stroke) {
if (openShape) {
PGraphics.showWarning(INSIDE_BEGIN_END_ERROR, "setStroke()");
return;
}
if (!perVertexStyles) {
PGraphics.showWarning(PER_VERTEX_UNSUPPORTED, "setStroke()");
return;
}
// make sure we allocated the vertices array and that vertex exists
if (vertices == null || index >= vertices.length) {
PGraphics.showWarning(NO_SUCH_VERTEX_ERROR + " (" + index + ")", "setStroke()");
return;
}
vertices[index][PGraphics.SA] = ((stroke >> 24) & 0xFF) / 255.0f;
vertices[index][PGraphics.SR] = ((stroke >> 16) & 0xFF) / 255.0f;
vertices[index][PGraphics.SG] = ((stroke >> 8) & 0xFF) / 255.0f;
vertices[index][PGraphics.SB] = ((stroke) & 0xFF) / 255.0f;
}
/**
*
* @param index
* @return
*/
public float getStrokeWeight(int index) {
// make sure we allocated the vertices array and that vertex exists
if (vertices == null || index >= vertices.length) {
PGraphics.showWarning(NO_SUCH_VERTEX_ERROR + " (" + index + ")", "getStrokeWeight()");
return strokeWeight;
}
return vertices[index][PGraphics.SW];
}
/**
*
* @param weight
*/
public void setStrokeWeight(float weight) {
if (openShape) {
PGraphics.showWarning(INSIDE_BEGIN_END_ERROR, "setStrokeWeight()");
return;
}
strokeWeight = weight;
if (vertices != null && perVertexStyles) {
for (int i = 0; i < vertexCount; i++) {
setStrokeWeight(i, weight);
}
}
}
/**
*
* @param index
* @param weight
*/
public void setStrokeWeight(int index, float weight) {
if (openShape) {
PGraphics.showWarning(INSIDE_BEGIN_END_ERROR, "setStrokeWeight()");
return;
}
if (!perVertexStyles) {
PGraphics.showWarning(PER_VERTEX_UNSUPPORTED, "setStrokeWeight()");
return;
}
// make sure we allocated the vertices array and that vertex exists
if (vertices == null || index >= vertices.length) {
PGraphics.showWarning(NO_SUCH_VERTEX_ERROR + " (" + index + ")", "setStrokeWeight()");
return;
}
vertices[index][PGraphics.SW] = weight;
}
/**
*
* @param join
*/
public void setStrokeJoin(int join) {
if (openShape) {
PGraphics.showWarning(INSIDE_BEGIN_END_ERROR, "setStrokeJoin()");
return;
}
strokeJoin = join;
}
/**
*
* @param cap
*/
public void setStrokeCap(int cap) {
if (openShape) {
PGraphics.showWarning(INSIDE_BEGIN_END_ERROR, "setStrokeCap()");
return;
}
strokeCap = cap;
}
/**
*
* @param index
* @return
*/
public int getAmbient(int index) {
// make sure we allocated the vertices array and that vertex exists
if (vertices == null || index >= vertices.length) {
PGraphics.showWarning(NO_SUCH_VERTEX_ERROR + " (" + index + ")", "getAmbient()");
return ambientColor;
}
int r = (int) (vertices[index][PGraphics.AR] * 255);
int green = (int) (vertices[index][PGraphics.AG] * 255);
int b = (int) (vertices[index][PGraphics.AB] * 255);
return 0xff000000 | (r << 16) | (green << 8) | b;
}
/**
*
* @param ambient
*/
public void setAmbient(int ambient) {
if (openShape) {
PGraphics.showWarning(INSIDE_BEGIN_END_ERROR, "setAmbient()");
return;
}
ambientColor = ambient;
if (vertices != null) {
for (int i = 0; i < vertices.length; i++) {
setAmbient(i, ambient);
}
}
}
/**
*
* @param index
* @param ambient
*/
public void setAmbient(int index, int ambient) {
if (openShape) {
PGraphics.showWarning(INSIDE_BEGIN_END_ERROR, "setAmbient()");
return;
}
// make sure we allocated the vertices array and that vertex exists
if (vertices == null || index >= vertices.length) {
PGraphics.showWarning(NO_SUCH_VERTEX_ERROR + " (" + index + ")", "setAmbient()");
return;
}
vertices[index][PGraphics.AR] = ((ambient >> 16) & 0xFF) / 255.0f;
vertices[index][PGraphics.AG] = ((ambient >> 8) & 0xFF) / 255.0f;
vertices[index][PGraphics.AB] = ((ambient) & 0xFF) / 255.0f;
}
/**
*
* @param index
* @return
*/
public int getSpecular(int index) {
// make sure we allocated the vertices array and that vertex exists
if (vertices == null || index >= vertices.length) {
PGraphics.showWarning(NO_SUCH_VERTEX_ERROR + " (" + index + ")", "getSpecular()");
return specularColor;
}
int r = (int) (vertices[index][PGraphics.SPR] * 255);
int green = (int) (vertices[index][PGraphics.SPG] * 255);
int b = (int) (vertices[index][PGraphics.SPB] * 255);
return 0xff000000 | (r << 16) | (green << 8) | b;
}
/**
*
* @param specular
*/
public void setSpecular(int specular) {
if (openShape) {
PGraphics.showWarning(INSIDE_BEGIN_END_ERROR, "setSpecular()");
return;
}
specularColor = specular;
if (vertices != null) {
for (int i = 0; i < vertices.length; i++) {
setSpecular(i, specular);
}
}
}
/**
*
* @param index
* @param specular
*/
public void setSpecular(int index, int specular) {
if (openShape) {
PGraphics.showWarning(INSIDE_BEGIN_END_ERROR, "setSpecular()");
return;
}
// make sure we allocated the vertices array and that vertex exists
if (vertices == null || index >= vertices.length) {
PGraphics.showWarning(NO_SUCH_VERTEX_ERROR + " (" + index + ")", "setSpecular()");
return;
}
vertices[index][PGraphics.SPR] = ((specular >> 16) & 0xFF) / 255.0f;
vertices[index][PGraphics.SPG] = ((specular >> 8) & 0xFF) / 255.0f;
vertices[index][PGraphics.SPB] = ((specular) & 0xFF) / 255.0f;
}
/**
*
* @param index
* @return
*/
public int getEmissive(int index) {
// make sure we allocated the vertices array and that vertex exists
if (vertices == null || index >= vertices.length) {
PGraphics.showWarning(NO_SUCH_VERTEX_ERROR + " (" + index + ")", "getEmissive()");
return emissiveColor;
}
int r = (int) (vertices[index][PGraphics.ER] * 255);
int green = (int) (vertices[index][PGraphics.EG] * 255);
int b = (int) (vertices[index][PGraphics.EB] * 255);
return 0xff000000 | (r << 16) | (green << 8) | b;
}
/**
*
* @param emissive
*/
public void setEmissive(int emissive) {
if (openShape) {
PGraphics.showWarning(INSIDE_BEGIN_END_ERROR, "setEmissive()");
return;
}
emissiveColor = emissive;
if (vertices != null) {
for (int i = 0; i < vertices.length; i++) {
setEmissive(i, emissive);
}
}
}
/**
*
* @param index
* @param emissive
*/
public void setEmissive(int index, int emissive) {
if (openShape) {
PGraphics.showWarning(INSIDE_BEGIN_END_ERROR, "setEmissive()");
return;
}
// make sure we allocated the vertices array and that vertex exists
if (vertices == null
|| index >= vertices.length) {
PGraphics.showWarning(NO_SUCH_VERTEX_ERROR + " (" + index + ")", "setEmissive()");
return;
}
vertices[index][PGraphics.ER] = ((emissive >> 16) & 0xFF) / 255.0f;
vertices[index][PGraphics.EG] = ((emissive >> 8) & 0xFF) / 255.0f;
vertices[index][PGraphics.EB] = ((emissive) & 0xFF) / 255.0f;
}
/**
*
* @param index
* @return
*/
public float getShininess(int index) {
// make sure we allocated the vertices array and that vertex exists
if (vertices == null
|| index >= vertices.length) {
PGraphics.showWarning(NO_SUCH_VERTEX_ERROR + " (" + index + ")", "getShininess()");
return shininess;
}
return vertices[index][PGraphics.SHINE];
}
/**
*
* @param shine
*/
public void setShininess(float shine) {
if (openShape) {
PGraphics.showWarning(INSIDE_BEGIN_END_ERROR, "setShininess()");
return;
}
shininess = shine;
if (vertices != null) {
for (int i = 0; i < vertices.length; i++) {
setShininess(i, shine);
}
}
}
/**
*
* @param index
* @param shine
*/
public void setShininess(int index, float shine) {
if (openShape) {
PGraphics.showWarning(INSIDE_BEGIN_END_ERROR, "setShininess()");
return;
}
// make sure we allocated the vertices array and that vertex exists
if (vertices == null
|| index >= vertices.length) {
PGraphics.showWarning(NO_SUCH_VERTEX_ERROR + " (" + index + ")", "setShininess()");
return;
}
vertices[index][PGraphics.SHINE] = shine;
}
/**
*
* @return
*/
public int[] getVertexCodes() {
if (vertexCodes == null) {
return null;
}
if (vertexCodes.length != vertexCodeCount) {
vertexCodes = PApplet.subset(vertexCodes, 0, vertexCodeCount);
}
return vertexCodes;
}
/**
*
* @return
*/
public int getVertexCodeCount() {
return vertexCodeCount;
}
/**
* One of VERTEX, BEZIER_VERTEX, CURVE_VERTEX, or BREAK.
*
* @param index
* @return
*/
public int getVertexCode(int index) {
return vertexCodes[index];
}
/**
*
* @return
*/
public boolean isClosed() {
return close;
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
/**
* Return true if this x, y coordinate is part of this shape.Only works with
* PATH shapes or GROUP shapes that contain other GROUPs or PATHs.
*
* @param x
* @param y
* @return
*/
public boolean contains(float x, float y) {
switch (family) {
case PATH:
// apply the inverse transformation matrix to the point coordinates
PMatrix inverseCoords = matrix.get();
inverseCoords.invert(); // maybe cache this?
inverseCoords.invert(); // maybe cache this?
PVector p = new PVector();
inverseCoords.mult(new PVector(x, y), p);
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
boolean c = false;
for (int i = 0, j = vertexCount - 1; i < vertexCount; j = i++) {
if (((vertices[i][Y] > p.y) != (vertices[j][Y] > p.y))
&& (p.x
< (vertices[j][X] - vertices[i][X])
* (y - vertices[i][Y])
/ (vertices[j][1] - vertices[i][Y])
+ vertices[i][X])) {
c = !c;
}
}
return c;
case GROUP:
// If this is a group, loop through children until we find one that
// contains the supplied coordinates. If a child does not support
// contains() throw a warning and continue.
for (int i = 0; i < childCount; i++) {
if (children[i].contains(x, y)) {
return true;
}
}
return false;
default:
// https://github.com/processing/processing/issues/1280
throw new IllegalArgumentException("The contains() method is only implemented for paths.");
}
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
// 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
/**
* ( begin auto-generated from PShape_translate.xml )
*
* Specifies an amount to displace the shape. The x parameter specifies
* left/right translation, the y parameter specifies up/down
* translation, and the z parameter specifies translations toward/away
* from the screen. Subsequent calls to the method accumulates the effect. For
* example, calling translate(50, 0) and then
* translate(20, 0) is the same as translate(70, 0). This
* transformation is applied directly to the shape, it's not refreshed each
* time draw() is run.
*
* Using this method with the z parameter requires using the P3D
* parameter in combination with size.
*
*
* @webref pshape:method
* @usage web_application
* @brief Displaces the shape
* @param x left/right translation
* @param y up/down translation
* @see PShape#rotate(float)
* @see PShape#scale(float)
* @see PShape#resetMatrix()
*/
public void translate(float x, float y) {
checkMatrix(2);
matrix.translate(x, y);
}
/**
* @param x
* @param y
* @param z forward/back translation
*/
public void translate(float x, float y, float z) {
checkMatrix(3);
matrix.translate(x, y, z);
}
/**
* ( begin auto-generated from PShape_rotateX.xml )
*
* Rotates a shape around the x-axis the amount specified by the
* angle parameter. Angles should be specified in radians (values from
* 0 to TWO_PI) or converted to radians with the radians() method.
*
* Shapes are always rotated around the upper-left corner of their bounding
* box. Positive numbers rotate objects in a clockwise direction. Subsequent
* calls to the method accumulates the effect. For example, calling
* rotateX(HALF_PI) and then rotateX(HALF_PI) is the same as
* rotateX(PI). This transformation is applied directly to the shape,
* it's not refreshed each time draw() is run.
*
* This method requires a 3D renderer. You need to use P3D as a third
* parameter for the size() function as shown in the example above.
*
*
* @webref pshape:method
* @usage web_application
* @brief Rotates the shape around the x-axis
* @param angle angle of rotation specified in radians
* @see PShape#rotate(float)
* @see PShape#rotateY(float)
* @see PShape#rotateZ(float)
* @see PShape#scale(float)
* @see PShape#translate(float, float)
* @see PShape#resetMatrix()
*/
public void rotateX(float angle) {
rotate(angle, 1, 0, 0);
}
/**
* ( begin auto-generated from PShape_rotateY.xml )
*
* Rotates a shape around the y-axis the amount specified by the
* angle parameter. Angles should be specified in radians (values from
* 0 to TWO_PI) or converted to radians with the radians() method.
*
* Shapes are always rotated around the upper-left corner of their bounding
* box. Positive numbers rotate objects in a clockwise direction. Subsequent
* calls to the method accumulates the effect. For example, calling
* rotateY(HALF_PI) and then rotateY(HALF_PI) is the same as
* rotateY(PI). This transformation is applied directly to the shape,
* it's not refreshed each time draw() is run.
*
* This method requires a 3D renderer. You need to use P3D as a third
* parameter for the size() function as shown in the example above.
*
*
* @webref pshape:method
* @usage web_application
* @brief Rotates the shape around the y-axis
* @param angle angle of rotation specified in radians
* @see PShape#rotate(float)
* @see PShape#rotateX(float)
* @see PShape#rotateZ(float)
* @see PShape#scale(float)
* @see PShape#translate(float, float)
* @see PShape#resetMatrix()
*/
public void rotateY(float angle) {
rotate(angle, 0, 1, 0);
}
/**
* ( begin auto-generated from PShape_rotateZ.xml )
*
* Rotates a shape around the z-axis the amount specified by the
* angle parameter. Angles should be specified in radians (values from
* 0 to TWO_PI) or converted to radians with the radians() method.
*
* Shapes are always rotated around the upper-left corner of their bounding
* box. Positive numbers rotate objects in a clockwise direction. Subsequent
* calls to the method accumulates the effect. For example, calling
* rotateZ(HALF_PI) and then rotateZ(HALF_PI) is the same as
* rotateZ(PI). This transformation is applied directly to the shape,
* it's not refreshed each time draw() is run.
*
* This method requires a 3D renderer. You need to use P3D as a third
* parameter for the size() function as shown in the example above.
*
*
* @webref pshape:method
* @usage web_application
* @brief Rotates the shape around the z-axis
* @param angle angle of rotation specified in radians
* @see PShape#rotate(float)
* @see PShape#rotateX(float)
* @see PShape#rotateY(float)
* @see PShape#scale(float)
* @see PShape#translate(float, float)
* @see PShape#resetMatrix()
*/
public void rotateZ(float angle) {
rotate(angle, 0, 0, 1);
}
/**
* ( begin auto-generated from PShape_rotate.xml )
*
* Rotates a shape the amount specified by the angle parameter. Angles
* should be specified in radians (values from 0 to TWO_PI) or converted to
* radians with the radians() method.
*
* Shapes are always rotated around the upper-left corner of their bounding
* box. Positive numbers rotate objects in a clockwise direction.
* Transformations apply to everything that happens after and subsequent calls
* to the method accumulates the effect. For example, calling
* rotate(HALF_PI) and then rotate(HALF_PI) is the same as
* rotate(PI). This transformation is applied directly to the shape,
* it's not refreshed each time draw() is run.
*
*
* @webref pshape:method
* @usage web_application
* @brief Rotates the shape
* @param angle angle of rotation specified in radians
* @see PShape#rotateX(float)
* @see PShape#rotateY(float)
* @see PShape#rotateZ(float)
* @see PShape#scale(float)
* @see PShape#translate(float, float)
* @see PShape#resetMatrix()
*/
public void rotate(float angle) {
checkMatrix(2); // at least 2...
matrix.rotate(angle);
}
/**
* @param angle
* @param v2
* @param v0
* @param v1
* @nowebref
*/
public void rotate(float angle, float v0, float v1, float v2) {
checkMatrix(3);
float norm2 = v0 * v0 + v1 * v1 + v2 * v2;
if (Math.abs(norm2 - 1) > EPSILON) {
// The rotation vector is not normalized.
float norm = PApplet.sqrt(norm2);
v0 /= norm;
v1 /= norm;
v2 /= norm;
}
matrix.rotate(angle, v0, v1, v2);
}
//
/**
* ( begin auto-generated from PShape_scale.xml )
*
* Increases or decreases the size of a shape by expanding and contracting
* vertices. Shapes always scale from the relative origin of their bounding
* box. Scale values are specified as decimal percentages. For example, the
* method call scale(2.0) increases the dimension of a shape by 200%.
* Subsequent calls to the method multiply the effect. For example, calling
* scale(2.0) and then scale(1.5) is the same as
* scale(3.0). This transformation is applied directly to the shape,
* it's not refreshed each time draw() is run.
*
* Using this method with the z parameter requires using the P3D
* parameter in combination with size.
*
*
* @webref pshape:method
* @usage web_application
* @brief Increases and decreases the size of a shape
* @param s percentate to scale the object
* @see PShape#rotate(float)
* @see PShape#translate(float, float)
* @see PShape#resetMatrix()
*/
public void scale(float s) {
checkMatrix(2); // at least 2...
matrix.scale(s);
}
/**
*
* @param x
* @param y
*/
public void scale(float x, float y) {
checkMatrix(2);
matrix.scale(x, y);
}
/**
* @param x percentage to scale the object in the x-axis
* @param y percentage to scale the object in the y-axis
* @param z percentage to scale the object in the z-axis
*/
public void scale(float x, float y, float z) {
checkMatrix(3);
matrix.scale(x, y, z);
}
//
/**
* ( begin auto-generated from PShape_resetMatrix.xml )
*
* Replaces the current matrix of a shape with the identity matrix. The
* equivalent function in OpenGL is glLoadIdentity().
*
*
* @webref pshape:method
* @brief Replaces the current matrix of a shape with the identity matrix
* @usage web_application
* @see PShape#rotate(float)
* @see PShape#scale(float)
* @see PShape#translate(float, float)
*/
public void resetMatrix() {
checkMatrix(2);
matrix.reset();
}
/**
*
* @param source
*/
public void applyMatrix(PMatrix source) {
if (source instanceof PMatrix2D) {
applyMatrix((PMatrix2D) source);
} else if (source instanceof PMatrix3D) {
applyMatrix((PMatrix3D) source);
}
}
/**
*
* @param 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);
}
/**
*
* @param n00
* @param n01
* @param n02
* @param n10
* @param n11
* @param n12
*/
public void applyMatrix(float n00, float n01, float n02,
float n10, float n11, float n12) {
checkMatrix(2);
matrix.apply(n00, n01, n02,
n10, n11, n12);
}
/**
*
* @param source
*/
public void applyMatrix(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);
}
/**
*
* @param n00
* @param n01
* @param n02
* @param n03
* @param n10
* @param n11
* @param n12
* @param n13
* @param n20
* @param n21
* @param n22
* @param n23
* @param n30
* @param n31
* @param n32
* @param n33
*/
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 at least the specified number of dimensions.
*
* @param 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.
*
* @param mode
*/
// public void pivot(float x, float y) {
// px = x;
// py = y;
// }
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public void colorMode(int mode) {
colorMode(mode, colorModeX, colorModeY, colorModeZ, colorModeA);
}
/**
* @param mode
* @param max range for all color elements
*/
public void colorMode(int mode, float max) {
colorMode(mode, max, max, max, max);
}
/**
* @param mode
* @param maxX range for the red or hue depending on the current color mode
* @param maxY range for the green or saturation depending on the current
* color mode
* @param maxZ range for the blue or brightness depending on the current color
* mode
*/
public void colorMode(int mode, float maxX, float maxY, float maxZ) {
colorMode(mode, maxX, maxY, maxZ, colorModeA);
}
/**
* @param mode
* @param maxA range for the alpha
* @param maxX
* @param maxZ
* @param maxY
*/
public final void colorMode(int mode,
float maxX, float maxY, float maxZ, float maxA) {
colorMode = mode;
colorModeX = maxX; // still needs to be set for hsb
colorModeY = maxY;
colorModeZ = maxZ;
colorModeA = maxA;
// if color max values are all 1, then no need to scale
colorModeScale
= ((maxA != 1) || (maxX != maxY) || (maxY != maxZ) || (maxZ != maxA));
// if color is rgb/0..255 this will make it easier for the
// red() green() etc functions
colorModeDefault = (colorMode == RGB)
&& (colorModeA == 255) && (colorModeX == 255)
&& (colorModeY == 255) && (colorModeZ == 255);
}
/**
*
* @param rgb
*/
protected void colorCalc(int rgb) {
if (((rgb & 0xff000000) == 0) && (rgb <= colorModeX)) {
colorCalc((float) rgb);
} else {
colorCalcARGB(rgb, colorModeA);
}
}
/**
*
* @param rgb
* @param alpha
*/
protected void colorCalc(int rgb, float alpha) {
if (((rgb & 0xff000000) == 0) && (rgb <= colorModeX)) { // see above
colorCalc((float) rgb, alpha);
} else {
colorCalcARGB(rgb, alpha);
}
}
/**
*
* @param gray
*/
protected void colorCalc(float gray) {
colorCalc(gray, colorModeA);
}
/**
*
* @param gray
* @param alpha
*/
protected void colorCalc(float gray, float alpha) {
if (gray > colorModeX) {
gray = colorModeX;
}
if (alpha > colorModeA) {
alpha = colorModeA;
}
if (gray < 0) {
gray = 0;
}
if (alpha < 0) {
alpha = 0;
}
calcR = colorModeScale ? (gray / colorModeX) : gray;
calcG = calcR;
calcB = calcR;
calcA = colorModeScale ? (alpha / colorModeA) : alpha;
calcRi = (int) (calcR * 255);
calcGi = (int) (calcG * 255);
calcBi = (int) (calcB * 255);
calcAi = (int) (calcA * 255);
calcColor = (calcAi << 24) | (calcRi << 16) | (calcGi << 8) | calcBi;
calcAlpha = (calcAi != 255);
}
/**
*
* @param x
* @param y
* @param z
*/
protected void colorCalc(float x, float y, float z) {
colorCalc(x, y, z, colorModeA);
}
/**
*
* @param x
* @param y
* @param z
* @param a
*/
protected void colorCalc(float x, float y, float z, float a) {
if (x > colorModeX) {
x = colorModeX;
}
if (y > colorModeY) {
y = colorModeY;
}
if (z > colorModeZ) {
z = colorModeZ;
}
if (a > colorModeA) {
a = colorModeA;
}
if (x < 0) {
x = 0;
}
if (y < 0) {
y = 0;
}
if (z < 0) {
z = 0;
}
if (a < 0) {
a = 0;
}
switch (colorMode) {
case RGB:
if (colorModeScale) {
calcR = x / colorModeX;
calcG = y / colorModeY;
calcB = z / colorModeZ;
calcA = a / colorModeA;
} else {
calcR = x;
calcG = y;
calcB = z;
calcA = a;
}
break;
case HSB:
x /= colorModeX; // h
y /= colorModeY; // s
z /= colorModeZ; // b
calcA = colorModeScale ? (a / colorModeA) : a;
if (y == 0) { // saturation == 0
calcR = calcG = calcB = z;
} else {
float which = (x - (int) x) * 6.0f;
float f = which - (int) which;
float p = z * (1.0f - y);
float q = z * (1.0f - y * f);
float t = z * (1.0f - (y * (1.0f - f)));
switch ((int) which) {
case 0:
calcR = z;
calcG = t;
calcB = p;
break;
case 1:
calcR = q;
calcG = z;
calcB = p;
break;
case 2:
calcR = p;
calcG = z;
calcB = t;
break;
case 3:
calcR = p;
calcG = q;
calcB = z;
break;
case 4:
calcR = t;
calcG = p;
calcB = z;
break;
case 5:
calcR = z;
calcG = p;
calcB = q;
break;
}
}
break;
}
calcRi = (int) (255 * calcR);
calcGi = (int) (255 * calcG);
calcBi = (int) (255 * calcB);
calcAi = (int) (255 * calcA);
calcColor = (calcAi << 24) | (calcRi << 16) | (calcGi << 8) | calcBi;
calcAlpha = (calcAi != 255);
}
/**
*
* @param argb
* @param alpha
*/
protected void colorCalcARGB(int argb, float alpha) {
if (alpha == colorModeA) {
calcAi = (argb >> 24) & 0xff;
calcColor = argb;
} else {
calcAi = (int) (((argb >> 24) & 0xff) * (alpha / colorModeA));
calcColor = (calcAi << 24) | (argb & 0xFFFFFF);
}
calcRi = (argb >> 16) & 0xff;
calcGi = (argb >> 8) & 0xff;
calcBi = argb & 0xff;
calcA = calcAi / 255.0f;
calcR = calcRi / 255.0f;
calcG = calcGi / 255.0f;
calcB = calcBi / 255.0f;
calcAlpha = (calcAi != 255);
}
}