major changes to internal rendering for PShape, also changes to candy to

reflect PShape object
This commit is contained in:
benfry
2008-09-01 20:58:29 +00:00
parent b804e612d2
commit e67556e03d
23 changed files with 2087 additions and 1723 deletions
+1 -1
View File
@@ -80,7 +80,7 @@ The naming of jar and zip files in the tool/* directory doesn't matter.
When Processing loads, the jar and zip files will be searched for
Mangler.class. Even though this tool is found in package poos.shoe,
it will be sussed out. Package names are encouraged/recommended/required.
it will be sussed out. Package names are required.
Loose .class files are not supported, use only jar and zip files.
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry excluding="processing/candy/Group.java" kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry combineaccessrules="false" kind="src" path="/core"/>
<classpathentry combineaccessrules="false" kind="src" path="/xml"/>
+6 -6
View File
@@ -1,12 +1,12 @@
#Sat Nov 11 10:35:15 EST 2006
#Thu Aug 28 18:42:23 EDT 2008
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.3
org.eclipse.jdt.core.compiler.compliance=1.5
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=ignore
org.eclipse.jdt.core.compiler.problem.enumIdentifier=ignore
org.eclipse.jdt.core.compiler.source=1.3
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.5
-3
View File
@@ -1,3 +0,0 @@
#Sat Nov 11 10:35:15 EST 2006
eclipse.preferences.version=1
internal.default.compliance=default
+609
View File
@@ -0,0 +1,609 @@
package processing.candy;
import java.awt.Paint;
import java.util.HashMap;
import processing.core.*;
import processing.xml.XMLElement;
public class BaseObject extends PShape {
XMLElement element;
float opacity;
Gradient strokeGradient;
Paint strokeGradientPaint;
String strokeName; // id of another object, gradients only?
Gradient fillGradient;
Paint fillGradientPaint;
String fillName; // id of another object
public BaseObject(BaseObject parent, XMLElement properties) {
//super(GROUP);
if (parent == null) {
// set values to their defaults according to the SVG spec
stroke = false;
strokeColor = 0xff000000;
strokeWeight = 1;
strokeCap = PConstants.SQUARE; // equivalent to BUTT in svg spec
strokeJoin = PConstants.MITER;
strokeGradient = null;
strokeGradientPaint = null;
strokeName = null;
fill = true;
fillColor = 0xff000000;
fillGradient = null;
fillGradientPaint = null;
fillName = null;
//hasTransform = false;
//transformation = null; //new float[] { 1, 0, 0, 1, 0, 0 };
opacity = 1;
} else {
stroke = parent.stroke;
strokeColor = parent.strokeColor;
strokeWeight = parent.strokeWeight;
strokeCap = parent.strokeCap;
strokeJoin = parent.strokeJoin;
strokeGradient = parent.strokeGradient;
strokeGradientPaint = parent.strokeGradientPaint;
strokeName = parent.strokeName;
fill = parent.fill;
fillColor = parent.fillColor;
fillGradient = parent.fillGradient;
fillGradientPaint = parent.fillGradientPaint;
fillName = parent.fillName;
//hasTransform = parent.hasTransform;
//transformation = parent.transformation;
opacity = parent.opacity;
}
element = properties;
name = properties.getStringAttribute("id");
if (name != null) {
table.put(name, this);
//System.out.println("now parsing " + id);
}
String displayStr = properties.getStringAttribute("display", "inline");
visible = !displayStr.equals("none");
String transformStr = properties.getStringAttribute("transform");
if (transformStr != null) {
float[] t = parseMatrix(transformStr);
matrix = new PMatrix3D(t[0], t[1], t[2], t[3], t[4], t[5]);
}
parseColors(properties);
}
// http://www.w3.org/TR/SVG/coords.html#TransformAttribute
static protected float[] parseMatrix(String matrixStr) {
/*
String prefix = "matrix(";
int start = matrixStr.indexOf(prefix);
if (start == -1) return null;
int stop = matrixStr.indexOf(')');
String content = matrixStr.substring(start + matrixStr.length(), stop);
return PApplet.parseFloat(PApplet.splitTokens(content.trim()));
*/
String[] pieces = PApplet.match(matrixStr, "\\s*(\\w+)\\((.*)\\)");
if (pieces.length != 2) {
System.err.println("Could not parse transform " + matrixStr);
return null;
}
float[] m = PApplet.parseFloat(PApplet.splitTokens(pieces[1]));
if (pieces[0].equals("matrix")) {
return m;
} else if (pieces[0].equals("translate")) {
float tx = m[0];
float ty = (m.length == 2) ? m[1] : m[0];
return new float[] { 1, 0, tx, 0, 1, ty };
} else if (pieces[0].equals("scale")) {
float sx = m[0];
float sy = (m.length == 2) ? m[1] : m[0];
return new float[] { sx, 0, 0, 0, sy, 0 };
} else if (pieces[0].equals("rotate")) {
float angle = m[0];
if (m.length == 1) {
float c = PApplet.cos(angle);
float s = PApplet.sin(angle);
return new float[] { c, -s, 0, s, c, 0 };
} else if (m.length == 3) {
PMatrix2D mat = new PMatrix2D(0, 1, m[1], 1, 0, m[2]);
mat.rotate(m[0]);
mat.translate(-m[1], -m[2]);
return mat.get(null);
}
} else if (pieces[0].equals("skewX")) {
return new float[] { 1, PApplet.tan(m[0]), 0, 0, 1, 0 };
} else if (pieces[0].equals("skewY")) {
return new float[] { 1, 0, 0, PApplet.tan(m[0]), 1, 0 };
}
return null;
}
/*
protected void parseTransformation2(XMLElement properties) {
String transform =
if (transform != null) {
//this.hasTransform = true;
transform = transform.substring(7, transform.length() - 2);
String tf[] = PApplet.splitTokens(transform);
float[] transformation = PApplet.parseFloat(tf);
matrix = new PMatrix3D(transformation[0], transformation[1], transformation[2],
transformation[3], transformation[4], transformation[5]);
}
}
*/
/*
static protected AffineTransform parseTransform(String what) {
if (what != null) {
if (what.startsWith("matrix(") && what.endsWith(")")) {
// columns go first with AT constructor
what = what.substring(7, what.length() - 1);
return new AffineTransform(PApplet.parseFloat(PApplet.split(what, ' ')));
}
}
return null;
}
*/
protected void parseColors(XMLElement properties) {
if (properties.hasAttribute("opacity")) {
opacity = properties.getFloatAttribute("opacity");
}
int opacityMask = ((int) (opacity * 255)) << 24;
if (properties.hasAttribute("stroke")) {
String strokeText = properties.getStringAttribute("stroke");
if (strokeText.equals("none")) {
stroke = false;
} else if (strokeText.startsWith("#")) {
stroke = true;
strokeColor = opacityMask |
(Integer.parseInt(strokeText.substring(1), 16)) & 0xFFFFFF;
} else if (strokeText.startsWith("rgb")) {
stroke = true;
strokeColor = opacityMask | parseRGB(strokeText);
} else if (strokeText.startsWith("url(#")) {
strokeName = strokeText.substring(5, strokeText.length() - 1);
Object strokeObject = table.get(strokeName);
if (strokeObject instanceof Gradient) {
strokeGradient = (Gradient) strokeObject;
strokeGradientPaint = calcGradientPaint(strokeGradient); //, opacity);
} else {
System.err.println("url " + strokeName + " refers to unexpected data");
}
}
}
if (properties.hasAttribute("stroke-width")) {
// if NaN (i.e. if it's 'inherit') then default back to the inherit setting
strokeWeight = properties.getFloatAttribute("stroke-width", strokeWeight);
}
if (properties.hasAttribute("stroke-linejoin")) {
String linejoin = properties.getStringAttribute("stroke-linejoin");
if (linejoin.equals("inherit")) {
// do nothing, will inherit automatically
} else if (linejoin.equals("miter")) {
strokeJoin = PConstants.MITER;
} else if (linejoin.equals("round")) {
strokeJoin = PConstants.ROUND;
} else if (linejoin.equals("bevel")) {
strokeJoin = PConstants.BEVEL;
}
}
if (properties.hasAttribute("stroke-linecap")) {
String linecap = properties.getStringAttribute("stroke-linecap");
if (linecap.equals("inherit")) {
// do nothing, will inherit automatically
} else if (linecap.equals("butt")) {
strokeCap = PConstants.SQUARE;
} else if (linecap.equals("round")) {
strokeCap = PConstants.ROUND;
} else if (linecap.equals("square")) {
strokeCap = PConstants.PROJECT;
}
}
// fill defaults to black (though stroke defaults to "none")
// http://www.w3.org/TR/SVG/painting.html#FillProperties
if (properties.hasAttribute("fill")) {
String fillText = properties.getStringAttribute("fill");
if (fillText.equals("none")) {
fill = false;
} else if (fillText.startsWith("#")) {
fill = true;
fillColor = opacityMask |
(Integer.parseInt(fillText.substring(1), 16)) & 0xFFFFFF;
//System.out.println("hex for fill is " + PApplet.hex(fillColor));
} else if (fillText.startsWith("rgb")) {
fill = true;
fillColor = opacityMask | parseRGB(fillText);
} else if (fillText.startsWith("url(#")) {
fillName = fillText.substring(5, fillText.length() - 1);
//PApplet.println("looking for " + fillName);
Object fillObject = table.get(fillName);
//PApplet.println("found " + fillObject);
if (fillObject instanceof Gradient) {
fill = true;
fillGradient = (Gradient) fillObject;
fillGradientPaint = calcGradientPaint(fillGradient); //, opacity);
//PApplet.println("got filla " + fillObject);
} else {
System.err.println("url " + fillName + " refers to unexpected data");
}
}
}
}
static protected int parseRGB(String what) {
int leftParen = what.indexOf('(') + 1;
int rightParen = what.indexOf(')');
String sub = what.substring(leftParen, rightParen);
int[] values = PApplet.parseInt(PApplet.splitTokens(sub, ", "));
return (values[0] << 16) | (values[1] << 8) | (values[2]);
}
static protected HashMap<String, String> parseStyleAttributes(String style) {
HashMap<String, String> table = new HashMap<String, String>();
String[] pieces = style.split(";");
for (int i = 0; i < pieces.length; i++) {
String[] parts = pieces[i].split(":");
table.put(parts[0], parts[1]);
}
return table;
}
/**
* Parse a size that may have a suffix for its units.
* Ignoring cases where this could also be a percentage.
* The <A HREF="http://www.w3.org/TR/SVG/coords.html#Units">units</A> spec:
* <UL>
* <LI>"1pt" equals "1.25px" (and therefore 1.25 user units)
* <LI>"1pc" equals "15px" (and therefore 15 user units)
* <LI>"1mm" would be "3.543307px" (3.543307 user units)
* <LI>"1cm" equals "35.43307px" (and therefore 35.43307 user units)
* <LI>"1in" equals "90px" (and therefore 90 user units)
* </UL>
*/
static protected float parseUnitSize(String text) {
int len = text.length() - 2;
if (text.endsWith("pt")) {
return PApplet.parseFloat(text.substring(0, len)) * 1.25f;
} else if (text.endsWith("pc")) {
return PApplet.parseFloat(text.substring(0, len)) * 15;
} else if (text.endsWith("mm")) {
return PApplet.parseFloat(text.substring(0, len)) * 3.543307f;
} else if (text.endsWith("cm")) {
return PApplet.parseFloat(text.substring(0, len)) * 35.43307f;
} else if (text.endsWith("in")) {
return PApplet.parseFloat(text.substring(0, len)) * 90;
} else if (text.endsWith("px")) {
return PApplet.parseFloat(text.substring(0, len));
} else {
return PApplet.parseFloat(text);
}
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
// these are a set of hacks so that gradients can be hacked into Java 2D.
/*
protected Paint getGradient(String name, float cx, float cy, float r) {
BaseObject obj = (BaseObject) findChild(name);
if (obj != null) {
if (obj.fillGradient != null) {
return obj.calcGradientPaint(obj.fillGradient, cx, cy, r);
}
}
throw new RuntimeException("No gradient found for shape " + name);
}
protected Paint getGradient(String name, float x1, float y1, float x2, float y2) {
BaseObject obj = (BaseObject) findChild(name);
if (obj != null) {
if (obj.fillGradient != null) {
return obj.calcGradientPaint(obj.fillGradient, x1, y1, x2, y2);
}
}
throw new RuntimeException("No gradient found for shape " + name);
}
protected void strokeGradient(PGraphics g, String name, float x, float y, float r) {
Paint paint = getGradient(name, x, y, r);
if (g instanceof PGraphicsJava2D) {
PGraphicsJava2D p2d = (PGraphicsJava2D) g;
p2d.strokeGradient = true;
p2d.strokeGradientObject = paint;
}
}
protected void strokeGradient(PGraphics g, String name, float x1, float y1, float x2, float y2) {
Paint paint = getGradient(name, x1, y1, x2, y2);
if (g instanceof PGraphicsJava2D) {
PGraphicsJava2D p2d = (PGraphicsJava2D) g;
p2d.strokeGradient = true;
p2d.strokeGradientObject = paint;
}
}
protected void fillGradient(PGraphics g, String name, float x, float y, float r) {
Paint paint = getGradient(name, x, y, r);
if (g instanceof PGraphicsJava2D) {
PGraphicsJava2D p2d = (PGraphicsJava2D) g;
p2d.fillGradient = true;
p2d.fillGradientObject = paint;
}
}
protected void fillGradient(PGraphics g, String name, float x1, float y1, float x2, float y2) {
Paint paint = getGradient(name, x1, y1, x2, y2);
if (g instanceof PGraphicsJava2D) {
PGraphicsJava2D p2d = (PGraphicsJava2D) g;
p2d.fillGradient = true;
p2d.fillGradientObject = paint;
}
}
*/
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
protected Paint calcGradientPaint(Gradient gradient) {
if (gradient instanceof LinearGradient) {
LinearGradient grad = (LinearGradient) gradient;
return new LinearGradientPaint(grad.x1, grad.y1, grad.x2, grad.y2,
grad.offset, grad.color, grad.count,
opacity);
} else if (gradient instanceof RadialGradient) {
RadialGradient grad = (RadialGradient) gradient;
return new RadialGradientPaint(grad.cx, grad.cy, grad.r,
grad.offset, grad.color, grad.count,
opacity);
}
return null;
}
protected Paint calcGradientPaint(Gradient gradient,
float x1, float y1, float x2, float y2) {
if (gradient instanceof LinearGradient) {
LinearGradient grad = (LinearGradient) gradient;
return new LinearGradientPaint(x1, y1, x2, y2,
grad.offset, grad.color, grad.count,
opacity);
}
throw new RuntimeException("Not a linear gradient.");
}
protected Paint calcGradientPaint(Gradient gradient,
float cx, float cy, float r) {
if (gradient instanceof RadialGradient) {
RadialGradient grad = (RadialGradient) gradient;
return new RadialGradientPaint(cx, cy, r,
grad.offset, grad.color, grad.count,
opacity);
}
throw new RuntimeException("Not a radial gradient.");
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
protected void styles(PGraphics g) {
super.styles(g);
if (g instanceof PGraphicsJava2D) {
PGraphicsJava2D p2d = (PGraphicsJava2D) g;
if (strokeGradient != null) {
p2d.strokeGradient = true;
p2d.strokeGradientObject = strokeGradientPaint;
} else {
// need to shut off, in case parent object has a gradient applied
//p2d.strokeGradient = false;
}
if (fillGradient != null) {
p2d.fillGradient = true;
p2d.fillGradientObject = fillGradientPaint;
} else {
// need to shut off, in case parent object has a gradient applied
//p2d.fillGradient = false;
}
}
}
/**
* Overrides SVG-set styles and uses PGraphics styles and colors.
* Identical to ignoreStyles(true).
*/
public void ignoreStyles() {
//ignoreStyles(true);
styles = false;
}
/**
* Enables or disables style information (fill and stroke) set in the file.
* @param state true to use user-specified stroke/fill, false for svg version
*/
public void ignoreStyles(boolean state) {
//ignoreStyles = state;
styles = !state;
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public void drawImpl(PGraphics g) {
// do nothing
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
/**
* Get a particular element based on its SVG ID. When editing SVG by hand,
* this is the id="" tag on any SVG element. When editing from Illustrator,
* these IDs can be edited by expanding the layers palette. The names used
* in the layers palette, both for the layers or the shapes and groups
* beneath them can be used here.
* <PRE>
* // This code grabs "Layer 3" and the shapes beneath it.
* SVG layer3 = svg.get("Layer 3");
* </PRE>
*/
public PShape getChild(String name) {
PShape found = super.getChild(name);
if (found != null) return found;
// otherwise try with underscores instead of spaces
return super.getChild(name.replace(' ', '_'));
}
protected void parseGroup(XMLElement graphics) {
XMLElement[] elements = graphics.getChildren();
//objects = new BaseObject[elements.length];
children = new PShape[elements.length];
childCount = 0;
for (XMLElement elem : elements) {
addChild(parseGroupChild(elem));
}
// for (int i = 0; i < elements.length; i++) {
// String name = elements[i].getName(); //getElement();
// XMLElement elem = elements[i];
//
// addChild(parseGroupChild(elem, name));
// }
}
protected PShape parseGroupChild(XMLElement elem) {
String name = elem.getName();
if (name.equals("g")) {
return new BaseObject(this, elem);
} else if (name.equals("defs")) {
// generally this will contain gradient info, so may
// as well just throw it into a group element for parsing
return new BaseObject(this, elem);
} else if (name.equals("line")) {
return new Line(this, elem);
} else if (name.equals("circle")) {
return new Circle(this, elem);
} else if (name.equals("ellipse")) {
return new Ellipse(this, elem);
} else if (name.equals("rect")) {
return new Rect(this, elem);
} else if (name.equals("polygon")) {
return new Poly(this, elem, true);
} else if (name.equals("polyline")) {
return new Poly(this, elem, false);
} else if (name.equals("path")) {
return new Path(this, elem);
} else if (name.equals("radialGradient")) {
return new RadialGradient(this, elem);
} else if (name.equals("linearGradient")) {
return new LinearGradient(this, elem);
} else if (name.equals("text")) {
PApplet.println("Text is not currently handled, " +
"convert text to outlines instead.");
} else if (name.equals("filter")) {
PApplet.println("Filters are not supported.");
} else if (name.equals("mask")) {
PApplet.println("Masks are not supported.");
} else {
System.err.println("Ignoring <" + name + "> tag.");
}
return null;
}
/**
* Prints out the SVG document useful for parsing
*/
public void print() {
PApplet.println(element.toString());
}
}
+23
View File
@@ -0,0 +1,23 @@
package processing.candy;
import processing.core.*;
import processing.xml.XMLElement;
public class Circle extends BaseObject {
//float x, y, radius;
public Circle(BaseObject parent, XMLElement properties) {
super(parent, properties);
this.x = properties.getFloatAttribute("cx");
this.y = properties.getFloatAttribute("cy");
float radius = properties.getFloatAttribute("r") * 2;
width = height = radius;
}
public void drawImpl(PGraphics g) {
g.ellipseMode(PConstants.CENTER);
g.ellipse(x, y, width, height);
}
}
+32
View File
@@ -0,0 +1,32 @@
package processing.candy;
import processing.core.*;
import processing.xml.XMLElement;
public class Ellipse extends BaseObject {
// float x, y, rx, ry;
public Ellipse(BaseObject parent, XMLElement properties) {
super(parent, properties);
x = properties.getFloatAttribute("cx");
y = properties.getFloatAttribute("cy");
float rx = properties.getFloatAttribute("rx");
float ry = properties.getFloatAttribute("ry");
x -= rx;
y -= ry;
width = rx * 2;
height = ry * 2;
}
public void drawImpl(PGraphics g) {
//g.ellipseMode(PConstants.CENTER);
//g.ellipse(x, y, rx, ry);
g.ellipseMode(PConstants.CORNERS);
g.ellipse(x, y, width, height);
}
}
+59
View File
@@ -0,0 +1,59 @@
package processing.candy;
import java.awt.geom.AffineTransform;
import java.util.HashMap;
import processing.core.PApplet;
import processing.core.PGraphics;
import processing.xml.XMLElement;
abstract public class Gradient extends BaseObject {
AffineTransform transform;
float[] offset;
int[] color;
int count;
public Gradient(BaseObject parent, XMLElement properties) {
super(parent, properties);
XMLElement elements[] = properties.getChildren();
offset = new float[elements.length];
color = new int[elements.length];
// <stop offset="0" style="stop-color:#967348"/>
for (int i = 0; i < elements.length; i++) {
XMLElement elem = elements[i];
String name = elem.getName();
if (name.equals("stop")) {
offset[count] = elem.getFloatAttribute("offset");
String style = elem.getStringAttribute("style");
HashMap<String, String> styles = parseStyleAttributes(style);
String colorStr = styles.get("stop-color");
if (colorStr == null) colorStr = "#000000";
String opacityStr = styles.get("stop-opacity");
if (opacityStr == null) opacityStr = "1";
int tupacity = (int) (PApplet.parseFloat(opacityStr) * 255);
color[count] = (tupacity << 24) |
Integer.parseInt(colorStr.substring(1), 16);
count++;
//System.out.println("this color is " + PApplet.hex(color[count]));
/*
int idx = farbe.indexOf("#");
if (idx != -1) {
color[count] = Integer.parseInt(farbe.substring(idx+1), 16);
count++;
} else {
System.err.println("problem with gradient stop " + properties);
}
*/
}
}
}
abstract public void drawImpl(PGraphics g);
}
+25
View File
@@ -0,0 +1,25 @@
package processing.candy;
import processing.core.PGraphics;
import processing.xml.XMLElement;
public class Line extends BaseObject {
float x1, y1, x2, y2;
public Line(BaseObject parent, XMLElement properties) {
super(parent, properties);
kind = LINES;
this.x1 = properties.getFloatAttribute("x1");
this.y1 = properties.getFloatAttribute("y1");
this.x2 = properties.getFloatAttribute("x2");
this.y2 = properties.getFloatAttribute("y2");
}
public void drawImpl(PGraphics g) {
g.line(x1, y1, x2, y2);
}
}
@@ -0,0 +1,41 @@
package processing.candy;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import processing.core.PGraphics;
import processing.xml.XMLElement;
public class LinearGradient extends Gradient {
float x1, y1, x2, y2;
public LinearGradient(BaseObject parent, XMLElement properties) {
super(parent, properties);
this.x1 = properties.getFloatAttribute("x1");
this.y1 = properties.getFloatAttribute("y1");
this.x2 = properties.getFloatAttribute("x2");
this.y2 = properties.getFloatAttribute("y2");
String transformStr =
properties.getStringAttribute("gradientTransform");
if (transformStr != null) {
this.transform = new AffineTransform(parseMatrix(transformStr));
Point2D t1 = transform.transform(new Point2D.Float(x1, y1), null);
Point2D t2 = transform.transform(new Point2D.Float(x2, y2), null);
this.x1 = (float) t1.getX();
this.y1 = (float) t1.getY();
this.x2 = (float) t2.getX();
this.y2 = (float) t2.getY();
}
}
public void drawImpl(PGraphics g) { }
}
+416
View File
@@ -0,0 +1,416 @@
package processing.candy;
import processing.core.*;
import processing.core.PConstants;
import processing.core.PGraphics;
import processing.xml.XMLElement;
public class Path extends BaseObject {
public int count = 0;
public float[] x = new float[4];
public float[] y = new float[4];
static public final int MOVETO = 0;
static public final int LINETO = 1;
static public final int CURVETO = 2;
static public final int QCURVETO = 3;
public int[] kind = new int[4];
public boolean closed = false;
public Path(BaseObject parent, XMLElement properties) {
super(parent, properties);
String pathDataBuffer = "";
if (!properties.hasAttribute("d"))
return;
pathDataBuffer = properties.getStringAttribute("d");
StringBuffer pathChars = new StringBuffer();
boolean lastSeparate = false;
for (int i = 0; i < pathDataBuffer.length(); i++) {
char c = pathDataBuffer.charAt(i);
boolean separate = false;
if (c == 'M' || c == 'm' ||
c == 'L' || c == 'l' ||
c == 'H' || c == 'h' ||
c == 'V' || c == 'v' ||
c == 'C' || c == 'c' || // beziers
c == 'S' || c == 's' ||
c == 'Q' || c == 'q' || // quadratic beziers
c == 'T' || c == 't' ||
c == 'Z' || c == 'z' || // closepath
c == ',') {
separate = true;
if (i != 0) {
pathChars.append("|");
}
}
if (c == 'Z' || c == 'z') {
separate = false;
}
if (c == '-' && !lastSeparate) {
pathChars.append("|");
}
if (c != ',') {
pathChars.append("" + pathDataBuffer.charAt(i));
}
if (separate && c != ',' && c != '-') {
pathChars.append("|");
}
lastSeparate = separate;
}
pathDataBuffer = pathChars.toString();
//String pathDataKeys[] = PApplet.split(pathDataBuffer, '|');
// use whitespace constant to get rid of extra spaces and CR or LF
String pathDataKeys[] =
PApplet.splitTokens(pathDataBuffer, "|" + PConstants.WHITESPACE);
//for (int j = 0; j < pathDataKeys.length; j++) {
// PApplet.println(j + "\t" + pathDataKeys[j]);
//}
//PApplet.println(pathDataKeys);
//PApplet.println();
//float cp[] = {0, 0};
float cx = 0;
float cy = 0;
int i = 0;
//for (int i = 0; i < pathDataKeys.length; i++) {
while (i < pathDataKeys.length) {
char c = pathDataKeys[i].charAt(0);
switch (c) {
//M - move to (absolute)
case 'M':
/*
cp[0] = PApplet.parseFloat(pathDataKeys[i + 1]);
cp[1] = PApplet.parseFloat(pathDataKeys[i + 2]);
float s[] = {cp[0], cp[1]};
i += 2;
points.add(s);
*/
cx = PApplet.parseFloat(pathDataKeys[i + 1]);
cy = PApplet.parseFloat(pathDataKeys[i + 2]);
moveto(cx, cy);
i += 3;
break;
//m - move to (relative)
case 'm':
/*
cp[0] = cp[0] + PApplet.parseFloat(pathDataKeys[i + 1]);
cp[1] = cp[1] + PApplet.parseFloat(pathDataKeys[i + 2]);
float s[] = {cp[0], cp[1]};
i += 2;
points.add(s);
*/
cx = cx + PApplet.parseFloat(pathDataKeys[i + 1]);
cy = cy + PApplet.parseFloat(pathDataKeys[i + 2]);
moveto(cx, cy);
i += 3;
break;
case 'L':
cx = PApplet.parseFloat(pathDataKeys[i + 1]);
cy = PApplet.parseFloat(pathDataKeys[i + 2]);
lineto(cx, cy);
i += 3;
break;
case 'l':
cx = cx + PApplet.parseFloat(pathDataKeys[i + 1]);
cy = cy + PApplet.parseFloat(pathDataKeys[i + 2]);
lineto(cx, cy);
i += 3;
break;
// horizontal lineto absolute
case 'H':
cx = PApplet.parseFloat(pathDataKeys[i + 1]);
lineto(cx, cy);
i += 2;
break;
// horizontal lineto relative
case 'h':
cx = cx + PApplet.parseFloat(pathDataKeys[i + 1]);
lineto(cx, cy);
i += 2;
break;
case 'V':
cy = PApplet.parseFloat(pathDataKeys[i + 1]);
lineto(cx, cy);
i += 2;
break;
case 'v':
cy = cy + PApplet.parseFloat(pathDataKeys[i + 1]);
lineto(cx, cy);
i += 2;
break;
// C - curve to (absolute)
case 'C': {
float ctrlX1 = PApplet.parseFloat(pathDataKeys[i + 1]);
float ctrlY1 = PApplet.parseFloat(pathDataKeys[i + 2]);
float ctrlX2 = PApplet.parseFloat(pathDataKeys[i + 3]);
float ctrlY2 = PApplet.parseFloat(pathDataKeys[i + 4]);
float endX = PApplet.parseFloat(pathDataKeys[i + 5]);
float endY = PApplet.parseFloat(pathDataKeys[i + 6]);
curveto(ctrlX1, ctrlY1, ctrlX2, ctrlY2, endX, endY);
cx = endX;
cy = endY;
i += 7;
}
break;
// c - curve to (relative)
case 'c': {
float ctrlX1 = cx + PApplet.parseFloat(pathDataKeys[i + 1]);
float ctrlY1 = cy + PApplet.parseFloat(pathDataKeys[i + 2]);
float ctrlX2 = cx + PApplet.parseFloat(pathDataKeys[i + 3]);
float ctrlY2 = cy + PApplet.parseFloat(pathDataKeys[i + 4]);
float endX = cx + PApplet.parseFloat(pathDataKeys[i + 5]);
float endY = cy + PApplet.parseFloat(pathDataKeys[i + 6]);
curveto(ctrlX1, ctrlY1, ctrlX2, ctrlY2, endX, endY);
cx = endX;
cy = endY;
i += 7;
}
break;
// S - curve to shorthand (absolute)
case 'S': {
float ppx = x[count-2];
float ppy = y[count-2];
float px = x[count-1];
float py = y[count-1];
float ctrlX1 = px + (px - ppx);
float ctrlY1 = py + (py - ppy);
float ctrlX2 = PApplet.parseFloat(pathDataKeys[i + 1]);
float ctrlY2 = PApplet.parseFloat(pathDataKeys[i + 2]);
float endX = PApplet.parseFloat(pathDataKeys[i + 3]);
float endY = PApplet.parseFloat(pathDataKeys[i + 4]);
curveto(ctrlX1, ctrlY1, ctrlX2, ctrlY2, endX, endY);
cx = endX;
cy = endY;
i += 5;
}
break;
// s - curve to shorthand (relative)
case 's': {
float ppx = x[count-2];
float ppy = y[count-2];
float px = x[count-1];
float py = y[count-1];
float ctrlX1 = px + (px - ppx);
float ctrlY1 = py + (py - ppy);
float ctrlX2 = cx + PApplet.parseFloat(pathDataKeys[i + 1]);
float ctrlY2 = cy + PApplet.parseFloat(pathDataKeys[i + 2]);
float endX = cx + PApplet.parseFloat(pathDataKeys[i + 3]);
float endY = cy + PApplet.parseFloat(pathDataKeys[i + 4]);
curveto(ctrlX1, ctrlY1, ctrlX2, ctrlY2, endX, endY);
cx = endX;
cy = endY;
i += 5;
}
break;
// Q - quadratic curve to (absolute)
case 'Q': {
float ctrlX = PApplet.parseFloat(pathDataKeys[i + 1]);
float ctrlY = PApplet.parseFloat(pathDataKeys[i + 2]);
float endX = PApplet.parseFloat(pathDataKeys[i + 3]);
float endY = PApplet.parseFloat(pathDataKeys[i + 4]);
curveto(ctrlX, ctrlY, endX, endY);
cx = endX;
cy = endY;
i += 5;
}
break;
// q - quadratic curve to (relative)
case 'q': {
float ctrlX = cx + PApplet.parseFloat(pathDataKeys[i + 1]);
float ctrlY = cy + PApplet.parseFloat(pathDataKeys[i + 2]);
float endX = cx + PApplet.parseFloat(pathDataKeys[i + 3]);
float endY = cy + PApplet.parseFloat(pathDataKeys[i + 4]);
curveto(ctrlX, ctrlY, endX, endY);
cx = endX;
cy = endY;
i += 5;
}
break;
// T - quadratic curve to shorthand (absolute)
// The control point is assumed to be the reflection of the
// control point on the previous command relative to the
// current point. (If there is no previous command or if the
// previous command was not a Q, q, T or t, assume the control
// point is coincident with the current point.)
case 'T': {
float ppx = x[count-2];
float ppy = y[count-2];
float px = x[count-1];
float py = y[count-1];
float ctrlX = px + (px - ppx);
float ctrlY = py + (py - ppy);
float endX = PApplet.parseFloat(pathDataKeys[i + 1]);
float endY = PApplet.parseFloat(pathDataKeys[i + 2]);
curveto(ctrlX, ctrlY, endX, endY);
cx = endX;
cy = endY;
i += 3;
}
break;
// t - quadratic curve to shorthand (relative)
case 't': {
float ppx = x[count-2];
float ppy = y[count-2];
float px = x[count-1];
float py = y[count-1];
float ctrlX = px + (px - ppx);
float ctrlY = py + (py - ppy);
float endX = cx + PApplet.parseFloat(pathDataKeys[i + 1]);
float endY = cy + PApplet.parseFloat(pathDataKeys[i + 2]);
curveto(ctrlX, ctrlY, endX, endY);
cx = endX;
cy = endY;
i += 3;
}
break;
case 'Z':
case 'z':
closed = true;
i++;
break;
default:
String parsed =
PApplet.join(PApplet.subset(pathDataKeys, 0, i), ",");
String unparsed =
PApplet.join(PApplet.subset(pathDataKeys, i), ",");
System.err.println("parsed: " + parsed);
System.err.println("unparsed: " + unparsed);
throw new RuntimeException("shape command not handled: " + pathDataKeys[i]);
}
}
}
protected void moveto(float px, float py) {
if (count == x.length) {
x = PApplet.expand(x);
y = PApplet.expand(y);
kind = PApplet.expand(kind);
}
kind[count] = MOVETO;
x[count] = px;
y[count] = py;
count++;
}
protected void lineto(float px, float py) {
if (count == x.length) {
x = PApplet.expand(x);
y = PApplet.expand(y);
kind = PApplet.expand(kind);
}
kind[count] = LINETO;
x[count] = px;
y[count] = py;
count++;
}
/** Quadratic curveto command. */
protected void curveto(float x1, float y1, float x2, float y2) {
if (count + 2 >= x.length) {
x = PApplet.expand(x);
y = PApplet.expand(y);
kind = PApplet.expand(kind);
}
kind[count] = QCURVETO;
x[count] = x1;
y[count] = y1;
count++;
x[count] = x2;
y[count] = y2;
count++;
}
/** Cubic curveto command. */
protected void curveto(float x1, float y1, float x2, float y2, float x3, float y3) {
if (count + 2 >= x.length) {
x = PApplet.expand(x);
y = PApplet.expand(y);
kind = PApplet.expand(kind);
}
kind[count] = CURVETO;
x[count] = x1;
y[count] = y1;
count++;
x[count] = x2;
y[count] = y2;
count++;
x[count] = x3;
y[count] = y3;
count++;
}
public void drawImpl(PGraphics g) {
g.beginShape();
g.vertex(x[0], y[0]);
int i = 1; // moveto has the first point
while (i < count) {
switch (kind[i]) {
case MOVETO:
g.breakShape();
g.vertex(x[i], y[i]);
i++;
break;
case LINETO:
g.vertex(x[i], y[i]);
i++;
break;
case QCURVETO: // doubles the control point
g.bezierVertex(x[i], y[i], x[i+1], y[i+1], x[i+1], y[i+1]);
i += 2;
break;
case CURVETO:
g.bezierVertex(x[i], y[i], x[i+1], y[i+1], x[i+2], y[i+2]);
i += 3;
break;
}
}
g.endShape(closed ? PConstants.CLOSE : PConstants.OPEN);
}
}
+41
View File
@@ -0,0 +1,41 @@
package processing.candy;
import processing.core.*;
import processing.xml.XMLElement;
public class Poly extends BaseObject {
float points[][] = null;
/** true if polygon, false if polyline */
boolean closed;
public Poly(BaseObject parent, XMLElement properties, boolean closed) {
super(parent, properties);
String pointsBuffer[] = null;
this.closed = closed;
if (properties.hasAttribute("points")) {
pointsBuffer = PApplet.splitTokens(properties.getStringAttribute("points"));
}
points = new float[pointsBuffer.length][2];
for (int i = 0; i < points.length; i++) {
String pb[] = PApplet.split(pointsBuffer[i], ',');
points[i][0] = Float.valueOf(pb[0]).floatValue();
points[i][1] = Float.valueOf(pb[1]).floatValue();
}
}
public void drawImpl(PGraphics g) {
if (points != null) {
if (points.length > 0) {
g.beginShape();
for (int i = 0; i < points.length; i++) {
g.vertex(points[i][0], points[i][1]);
}
g.endShape(closed ? PConstants.CLOSE : PConstants.OPEN);
}
}
}
}
@@ -0,0 +1,36 @@
package processing.candy;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import processing.core.PGraphics;
import processing.xml.XMLElement;
public class RadialGradient extends Gradient {
float cx, cy, r;
public RadialGradient(BaseObject parent, XMLElement properties) {
super(parent, properties);
this.cx = properties.getFloatAttribute("cx");
this.cy = properties.getFloatAttribute("cy");
this.r = properties.getFloatAttribute("r");
String transformStr =
properties.getStringAttribute("gradientTransform");
if (transformStr != null) {
this.transform = new AffineTransform(parseMatrix(transformStr));
Point2D t1 = transform.transform(new Point2D.Float(cx, cy), null);
Point2D t2 = transform.transform(new Point2D.Float(cx + r, cy), null);
this.cx = (float) t1.getX();
this.cy = (float) t1.getY();
this.r = (float) (t2.getX() - t1.getX());
}
}
public void drawImpl(PGraphics g) { }
}
+24
View File
@@ -0,0 +1,24 @@
package processing.candy;
import processing.core.*;
import processing.xml.XMLElement;
public class Rect extends BaseObject {
// float x, y, w, h;
public Rect(BaseObject parent, XMLElement properties) {
super(parent, properties);
x = properties.getFloatAttribute("x");
y = properties.getFloatAttribute("y");
width = properties.getFloatAttribute("width");
height = properties.getFloatAttribute("height");
}
public void drawImpl(PGraphics g) {
g.rectMode(PConstants.CORNER);
g.rect(x, y, width, height);
}
}
File diff suppressed because it is too large Load Diff
+4 -2
View File
@@ -187,9 +187,11 @@ public interface PConstants {
// the low four bits set the variety,
// higher bits set the specific shape type
static final int POINTS = (1 << 4) | 0;
static final int GROUP = (1 << 2);
static final int POINTS = (1 << 4);
static final int LINES = (1 << 5) | 0;
static final int LINES = (1 << 5);
//static final int LINE_STRIP = (1 << 5) | 1;
//static final int LINE_LOOP = (1 << 5) | 2;
+1 -52
View File
@@ -108,47 +108,11 @@ public abstract class PGraphics extends PImage implements PConstants {
static public final int EG = 33;
static public final int EB = 34;
//has this vertex been lit yet
// has this vertex been lit yet
static public final int BEEN_LIT = 35;
static final int VERTEX_FIELD_COUNT = 36;
// line & triangle fields (note how these overlap)
static public final int INDEX = 0; // shape index
static public final int VERTEX1 = 1;
static public final int VERTEX2 = 2;
static public final int VERTEX3 = 3; // (triangles only)
static public final int TEXTURE_INDEX = 4; // (triangles only)
static public final int STROKE_MODE = 3; // (lines only)
static public final int STROKE_WEIGHT = 4; // (lines only)
static public final int LINE_FIELD_COUNT = 5;
static public final int TRIANGLE_FIELD_COUNT = 5;
static public final int TRI_DIFFUSE_R = 0;
static public final int TRI_DIFFUSE_G = 1;
static public final int TRI_DIFFUSE_B = 2;
static public final int TRI_DIFFUSE_A = 3;
static public final int TRI_SPECULAR_R = 4;
static public final int TRI_SPECULAR_G = 5;
static public final int TRI_SPECULAR_B = 6;
static public final int TRI_SPECULAR_A = 7;
static public final int TRIANGLE_COLOR_COUNT = 8;
// normal modes for lighting, these have the uglier naming
// because the constants are never seen by users
/// normal calculated per triangle
static public final int AUTO_NORMAL = 0;
/// one normal manually specified per shape
static public final int MANUAL_SHAPE_NORMAL = 1;
/// normals specified for each shape vertex
static public final int MANUAL_VERTEX_NORMAL = 2;
/// width minus one (useful for many calculations)
public int width1;
@@ -982,24 +946,9 @@ public abstract class PGraphics extends PImage implements PConstants {
* that's how things are implemented.
*/
abstract public void beginShape(int kind);
/*
shape = kind;
// reset vertex, line and triangle information
// every shape is rendered at endShape();
vertexCount = 0;
splineVertexCount = 0;
//spline_vertices_flat = true;
//strokeChanged = false;
//fillChanged = false;
//normalChanged = false;
*/
public void normal(float nx, float ny, float nz) {
//depthError("normal");
}
@@ -1792,9 +1792,6 @@ public class PGraphics2D extends PGraphics {
*/
protected void clear() {
Arrays.fill(pixels, backgroundColor);
// for (int i = 0; i < pixelCount; i++) {
// pixels[i] = backgroundColor;
// }
}
+51 -67
View File
@@ -41,6 +41,41 @@ import java.util.*;
*/
public class PGraphics3D extends PGraphics {
// line & triangle fields (note how these overlap)
static public final int INDEX = 0; // shape index
static public final int VERTEX1 = 1;
static public final int VERTEX2 = 2;
static public final int VERTEX3 = 3; // (triangles only)
static public final int TEXTURE_INDEX = 4; // (triangles only)
static public final int STROKE_MODE = 3; // (lines only)
static public final int STROKE_WEIGHT = 4; // (lines only)
static public final int LINE_FIELD_COUNT = 5;
static public final int TRIANGLE_FIELD_COUNT = 5;
static public final int TRI_DIFFUSE_R = 0;
static public final int TRI_DIFFUSE_G = 1;
static public final int TRI_DIFFUSE_B = 2;
static public final int TRI_DIFFUSE_A = 3;
static public final int TRI_SPECULAR_R = 4;
static public final int TRI_SPECULAR_G = 5;
static public final int TRI_SPECULAR_B = 6;
static public final int TRI_SPECULAR_A = 7;
static public final int TRIANGLE_COLOR_COUNT = 8;
// normal modes for lighting, these have the uglier naming
// because the constants are never seen by users
/// normal calculated per triangle
static public final int AUTO_NORMAL = 0;
/// one normal manually specified per shape
static public final int MANUAL_SHAPE_NORMAL = 1;
/// normals specified for each shape vertex
static public final int MANUAL_VERTEX_NORMAL = 2;
// ........................................................
// Lighting-related variables
@@ -251,7 +286,7 @@ public class PGraphics3D extends PGraphics {
cameraFOV = 60 * DEG_TO_RAD; // at least for now
cameraX = width / 2.0f;
cameraY = height / 2.0f;
cameraZ = cameraY / ((float) tan(cameraFOV / 2.0f));
cameraZ = cameraY / ((float) Math.tan(cameraFOV / 2.0f));
cameraNear = cameraZ / 10.0f;
cameraFar = cameraZ * 10.0f;
cameraAspect = (float)width / (float)height;
@@ -502,12 +537,9 @@ public class PGraphics3D extends PGraphics {
textureImage = image;
if (texture_index == textures.length - 1) {
PImage temp[] = new PImage[texture_index<<1];
System.arraycopy(textures, 0, temp, 0, texture_index);
textures = temp;
//message(CHATTER, "allocating more textures " + textures.length);
textures = (PImage[]) PApplet.expand(textures);
}
if (textures[texture_index] != null) {
if (textures[texture_index] != null) { // ???
texture_index++;
}
textures[texture_index] = image;
@@ -2038,13 +2070,6 @@ public class PGraphics3D extends PGraphics {
}
private void crossProduct(float[] u, float[] v, float[] out) {
out[0] = u[1]*v[2] - u[2]*v[1];
out[1] = u[2]*v[0] - u[0]*v[2];
out[2] = u[0]*v[1] - u[1]*v[0];
}
private void light_triangle(int triIndex) {
int vIndex;
@@ -2109,7 +2134,7 @@ public class PGraphics3D extends PGraphics {
dv2[2] = vertices[vIndex3][VZ] - vertices[vIndex][VZ];
//float[] norm = new float[3];
crossProduct(dv1, dv2, norm);
cross(dv1, dv2, norm);
float nMag = mag(norm[X], norm[Y], norm[Z]);
if (nMag != 0 && nMag != 1) {
norm[X] /= nMag; norm[Y] /= nMag; norm[Z] /= nMag;
@@ -2177,7 +2202,7 @@ public class PGraphics3D extends PGraphics {
dv2[2] = vertices[vIndex3][VZ] - vertices[vIndex][VZ];
//float[] norm = new float[3];
crossProduct(dv1, dv2, norm);
cross(dv1, dv2, norm);
float nMag = mag(norm[X], norm[Y], norm[Z]);
if (nMag != 0 && nMag != 1) {
norm[X] /= nMag; norm[Y] /= nMag; norm[Z] /= nMag;
@@ -3116,7 +3141,7 @@ public class PGraphics3D extends PGraphics {
*/
public void perspective(float fov, float aspect, float zNear, float zFar) {
//float ymax = zNear * tan(fovy * PI / 360.0f);
float ymax = zNear * tan(fov / 2.0f);
float ymax = zNear * (float) Math.tan(fov / 2);
float ymin = -ymax;
float xmin = ymin * aspect;
@@ -3758,7 +3783,7 @@ public class PGraphics3D extends PGraphics {
lightPosition(lightCount, x, y, z);
lightDirection(lightCount, nx, ny, nz);
lightSpotAngle[lightCount] = angle;
lightSpotAngleCos[lightCount] = max(0, cos(angle));
lightSpotAngleCos[lightCount] = max(0, (float) Math.cos(angle));
lightSpotConcentration[lightCount] = concentration;
lightCount++;
@@ -3848,13 +3873,6 @@ public class PGraphics3D extends PGraphics {
*/
public void background(PImage image) {
super.background(image);
/*
for (int i = 0; i < pixelCount; i++) {
zbuffer[i] = Float.MAX_VALUE;
//stencil[i] = 0;
}
*/
Arrays.fill(zbuffer, Float.MAX_VALUE);
}
@@ -3864,18 +3882,8 @@ public class PGraphics3D extends PGraphics {
* Stencil buffer should also be cleared, but for now is ignored in P3D.
*/
protected void clear() {
//System.out.println("PGraphics3.clear(" +
// PApplet.hex(backgroundColor) + ")");
/*
for (int i = 0; i < pixelCount; i++) {
pixels[i] = backgroundColor;
zbuffer[i] = Float.MAX_VALUE;
//stencil[i] = 0;
}
*/
Arrays.fill(pixels, backgroundColor);
Arrays.fill(zbuffer, Float.MAX_VALUE);
clearRaw();
}
@@ -3928,18 +3936,12 @@ public class PGraphics3D extends PGraphics {
// MATH (internal use only)
/*
private final float mag(float a, float b) {
return (float)Math.sqrt(a*a + b*b);
}
*/
private final float mag(float a, float b, float c) {
return (float)Math.sqrt(a*a + b*b + c*c);
return (float) Math.sqrt(a*a + b*b + c*c);
}
private final float mag(float abc[]) {
return (float)Math.sqrt(abc[0]*abc[0] + abc[1]*abc[1] + abc[2]*abc[2]);
return (float) Math.sqrt(abc[0]*abc[0] + abc[1]*abc[1] + abc[2]*abc[2]);
}
private final float min(float a, float b) {
@@ -3950,41 +3952,23 @@ public class PGraphics3D extends PGraphics {
return (a > b) ? a : b;
}
/*
private final float max(float a, float b, float c) {
return Math.max(a, Math.max(b, c));
}
private final float sq(float a) {
return a*a;
}
*/
private final float pow(float a, float b) {
return (float)Math.pow(a, b);
return (float) Math.pow(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);
}
private final float tan(float angle) {
return (float)Math.tan(angle);
}
private float dot(float ax, float ay, float az,
float bx, float by, float bz) {
return ax * bx + ay * by + az * bz;
}
private final void cross(float[] a, float[] b, float[] out) {
out[0] = a[1]*b[2] - a[2]*b[1];
out[1] = a[2]*b[0] - a[0]*b[2];
out[2] = a[0]*b[1] - a[1]*b[0];
}
}
+321
View File
@@ -0,0 +1,321 @@
/* -*- 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 PMatrix2D implements PConstants {
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 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 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 != 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(PMatrix2D src) {
set(src.m00, src.m01, src.m02,
src.m10, src.m11, src.m12);
}
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 translate(float tx, float ty) {
m02 = tx*m00 + ty*m01 + m02;
m12 = tx*m10 + ty*m11 + m12;
}
public void rotate(float angle) {
// TODO fixme
}
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) {
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) {
}
/**
* Multiply this matrix by another.
*/
public void apply(PMatrix2D source) {
apply(source.m00, source.m01, source.m02,
source.m10, source.m11, source.m12);
}
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;
}
/**
* 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(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; }
//////////////////////////////////////////////////////////////
/**
* Multiply a four 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[] multiply(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;
}
/**
* 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();
}
//////////////////////////////////////////////////////////////
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);
}
}
+25 -26
View File
@@ -57,7 +57,7 @@ public final class PMatrix3D implements PConstants {
public PMatrix3D(float m00, float m01, float m02,
float m10, float m11, float m12) {
float m10, float m11, float m12) {
set(m00, m01, m02, 0,
m10, m11, m12, 0,
0, 0, 1, 0,
@@ -67,9 +67,9 @@ public final class PMatrix3D implements PConstants {
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) {
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,
@@ -640,33 +640,32 @@ public final class PMatrix3D implements PConstants {
max(max(abs(m30), abs(m31)),
max(abs(m32), abs(m33))))));
// avoid infinite loop
if (Float.isNaN(big) || Float.isInfinite(big)) {
big = 1000000; // set to something arbitrary
int digits = 1;
if (Float.isNaN(big) || Float.isInfinite(big)) { // avoid infinite loop
digits = 5;
} else {
while ((big /= 10) != 0) digits++; // cheap log()
}
int d = 1;
while ((big /= 10) != 0) d++; // 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(m00, d, 4) + " " +
PApplet.nfs(m01, d, 4) + " " +
PApplet.nfs(m02, d, 4) + " " +
PApplet.nfs(m03, d, 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(m10, d, 4) + " " +
PApplet.nfs(m11, d, 4) + " " +
PApplet.nfs(m12, d, 4) + " " +
PApplet.nfs(m13, d, 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(m20, d, 4) + " " +
PApplet.nfs(m21, d, 4) + " " +
PApplet.nfs(m22, d, 4) + " " +
PApplet.nfs(m23, d, 4));
System.out.println(PApplet.nfs(m30, d, 4) + " " +
PApplet.nfs(m31, d, 4) + " " +
PApplet.nfs(m32, d, 4) + " " +
PApplet.nfs(m33, d, 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();
}
+314 -75
View File
@@ -23,6 +23,8 @@
package processing.core;
import java.util.HashMap;
// take a look at the obj loader to see how this fits with things
// PShape.line() PShape.ellipse()?
@@ -30,57 +32,67 @@ package processing.core;
// line()
// endShape(s)
public class PShape {
abstract public class PShape implements PConstants {
public String name;
protected String name;
protected int kind;
protected int drawMode;
protected PMatrix3D matrix;
// setAxis -> .x and .y to move x and y coords of origin
protected float x;
protected float y;
protected float width;
protected float height;
// set to false if the object is hidden in the layers palette
public boolean display;
protected boolean visible;
public boolean stroke;
public int strokeColor;
public float strokeWeight; // default is 1
public int strokeCap;
public int strokeJoin;
protected boolean stroke;
protected int strokeColor;
protected float strokeWeight; // default is 1
protected int strokeCap;
protected int strokeJoin;
public boolean fill;
public int fillColor;
protected boolean fill;
protected int fillColor;
protected boolean styles;
//public boolean hasTransform;
public float[] transformation;
//
int kind;
PMatrix3D matrix;
//protected float[] transformation;
int[] opcode;
int opcodeCount;
// need to reorder vertex fields to make a VERTEX_SHORT_COUNT
// that puts all the non-rendering fields into later indices
int dataCount;
float[][] data; // second param is the VERTEX_FIELD_COUNT
// should this be called vertices (consistent with PGraphics internals)
// or does that hurt flexibility?
int childCount;
PShape[] children;
protected PShape parent;
protected int childCount;
protected PShape[] children;
protected HashMap<String,PShape> table;
// 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;
// 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;
// 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
@@ -92,37 +104,93 @@ public class PShape {
// material parameters will be thrown out,
// except those currently supported (kinds of lights)
// setAxis -> .x and .y to move x and y coords of origin
public float x;
public float y;
// pivot point for transformations
public float px;
public float py;
// public float px;
// public float py;
public PShape() {
this.kind = GROUP;
}
public PShape(int kind) {
this.kind = kind;
}
public PShape(float x, float y) {
this.x = x;
this.y = y;
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;
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
protected void checkBounds() {
if (width == 0 || height == 0) {
// calculate bounds here (also take kids into account)
width = 1;
height = 1;
}
}
public float getWidth() {
checkBounds();
return width;
}
public float getHeight() {
checkBounds();
return height;
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
/**
* Called by the following (the shape() command adds the g)
* PShape s = loadShapes("blah.svg");
* shape(s);
* Set the orientation for drawn objects, similar to PImage.imageMode().
* @param which Either CORNER, CORNERS, or CENTER.
*/
public void draw(PGraphics g) {
boolean flat = g instanceof PGraphics3D;
public void drawMode(int which) {
drawMode = which;
}
boolean strokeSaved;
int strokeColorSaved;
float strokeWeightSaved;
int strokeCapSaved;
int strokeJoinSaved;
boolean fillSaved;
int fillColorSaved;
int ellipseModeSaved;
protected void pre(PGraphics g) {
if (matrix != null) {
boolean flat = g instanceof PGraphics3D;
g.pushMatrix();
if (flat) {
g.applyMatrix(matrix.m00, matrix.m01, matrix.m02,
@@ -135,50 +203,217 @@ public class PShape {
}
}
// if g subclasses PGraphics2, ignore all lighting stuff and z coords
// otherwise if PGraphics3, need to call diffuse() etc
strokeSaved = g.stroke;
strokeColorSaved = g.strokeColor;
strokeWeightSaved = g.strokeWeight;
strokeCapSaved = g.strokeCap;
strokeJoinSaved = g.strokeJoin;
// unfortunately, also a problem with no way to encode stroke/fill
// being enabled/disabled.. this quickly gets into just having opcodes
// for the entire api, to deal with things like textures and images
fillSaved = g.fill;
fillColorSaved = g.fillColor;
switch (kind) {
case PATH:
for (int i = 0; i < opcodeCount; i++) {
switch (opcode[i]) {
case VERTEX:
break;
}
}
break;
ellipseModeSaved = g.ellipseMode;
case GROUP:
break;
case RECT:
break;
if (styles) {
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();
}
}
/**
* Called by the following (the shape() command adds the g)
* PShape s = loadShapes("blah.svg");
* shape(s);
*/
public void draw(PGraphics g) {
if (!visible) return;
if (drawMode == PConstants.CENTER) {
g.pushMatrix();
g.translate(-width/2, -height/2);
}
pre(g);
drawImpl(g);
post(g);
if (drawMode == PConstants.CENTER) {
g.popMatrix();
}
}
/**
* Convenience method to draw at a particular location.
*/
public void draw(PGraphics g, float x, float y) {
if (!visible) return;
g.pushMatrix();
if (drawMode == PConstants.CENTER) {
g.translate(x - width/2, y - height/2);
} else if ((drawMode == PConstants.CORNER) ||
(drawMode == PConstants.CORNERS)) {
g.translate(x, y);
}
pre(g);
drawImpl(g);
post(g);
g.popMatrix();
}
public void draw(PGraphics g, float x, float y, float c, float d) {
if (!visible) return;
g.pushMatrix();
if (drawMode == PConstants.CENTER) {
// x and y are center, c and d refer to a diameter
g.translate(x - c/2f, y - d/2f);
g.scale(c / width, d / height);
} else if (drawMode == PConstants.CORNER) {
g.translate(x, y);
g.scale(c / width, d / height);
} else if (drawMode == PConstants.CORNERS) {
// c and d are x2/y2, make them into width/height
c -= x;
d -= y;
// then same as above
g.translate(x, y);
g.scale(c / width, d / height);
}
pre(g);
drawImpl(g);
post(g);
g.popMatrix();
}
/**
* Draws the SVG document.
*/
abstract public void drawImpl(PGraphics g);
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public int getChildCount() {
return childCount;
}
public PShape getChild(int index) {
return children[index];
}
public PShape getChild(String name) {
if (table != null) {
for (String n : table.keySet()) {
if (n.equals(name)) {
return table.get(name);
}
}
}
for (int i = 0; i < childCount; i++) {
PShape found = children[i].getChild(name);
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 name) {
if (parent == null) {
return getChild(name);
} else {
return parent.findChild(name);
}
}
// can't be 'add' because that suggests additive geometry
public void addChild(PShape who) {
if (children == null) {
children = new PShape[2];
}
if (childCount == children.length) {
children = (PShape[]) PApplet.expand(children);
}
children[childCount++] = who;
who.parent = this;
if (table == null) {
table = new HashMap<String,PShape>();
}
table.put(who.getName(), who);
}
public PShape createGroup() {
PShape group = new PShape();
group.kind = GROUP;
addChild(group);
return group;
}
// public PShape createGroup() {
// PShape group = new PShape();
// group.kind = GROUP;
// addChild(group);
// return group;
// }
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
@@ -200,9 +435,6 @@ public class PShape {
}
//
public void rotateX(float angle) {
rotate(angle, 1, 0, 0);
}
@@ -232,10 +464,12 @@ public class PShape {
scale(s, s, s);
}
public void scale(float sx, float sy) {
scale(sx, sy, 1);
}
public void scale(float x, float y, float z) {
checkMatrix();
matrix.scale(x, y, z);
@@ -245,6 +479,10 @@ public class PShape {
//
public void resetMatrix() {
}
public void applyMatrix(float n00, float n01, float n02,
float n10, float n11, float n12) {
checkMatrix();
@@ -254,6 +492,7 @@ public class PShape {
0, 0, 0, 1);
}
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,
@@ -287,17 +526,17 @@ public class PShape {
* 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() {
}
// public void center() {
// }
/**
* Set the pivot point for all transformations.
*/
public void pivot(float x, float y) {
px = x;
py = y;
}
// public void pivot(float x, float y) {
// px = x;
// py = y;
// }
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+7 -5
View File
@@ -16,14 +16,14 @@ X build it and then exit
X notations have been added to the bug report that cover the plw changes
X Toolmenu won't show until I compile Mangler
X http://dev.processing.org/bugs/show_bug.cgi?id=892
_ transport error 208
_ http://dev.processing.org/bugs/show_bug.cgi?id=895
_ possible http://www.jetbrains.net/jira/browse/IDEADEV-4268
X update quaqua to 4.4.7 on macosx (http://www.randelshofer.ch/quaqua/)
X now supports 10.5 an 64 bit jnilib
_ video capture problems with opengl
_ http://dev.processing.org/bugs/show_bug.cgi?id=882
_ serial.available() broken with video
_ http://dev.processing.org/bugs/show_bug.cgi?id=829
_ add local variables to PdeRecognizer
_ remove static methods in PdePreprocessor, instead pull things from recog
@@ -59,6 +59,8 @@ _ but: open() is platform specific anyway, ppl can use exec()
[ needs verification ]
_ transport error 202
_ http://dev.processing.org/bugs/show_bug.cgi?id=895
_ check to see whether this bug is fixed once 0140 is released
_ properly handle non-ascii chars in p5 folder name
_ http://dev.processing.org/bugs/show_bug.cgi?id=49