mirror of
https://github.com/processing/processing4.git
synced 2026-05-05 02:15:30 +02:00
break PShape into AWT and non-AWT code
This commit is contained in:
@@ -40,9 +40,11 @@ import processing.core.*;
|
||||
* <p>
|
||||
* To get access to the Java 2D "Graphics2D" object for the default
|
||||
* renderer, use:
|
||||
* <PRE>Graphics2D g2 = ((PGraphicsJava2D)g).g2;</PRE>
|
||||
* This will let you do Java 2D stuff directly, but is not supported in
|
||||
* any way shape or form. Which just means "have fun, but don't complain
|
||||
* <PRE>
|
||||
* Graphics2D g2 = (Graphics2D) g.getNative();
|
||||
* </PRE>
|
||||
* This will let you do Graphics2D calls directly, but is not supported
|
||||
* in any way shape or form. Which just means "have fun, but don't complain
|
||||
* if it breaks."
|
||||
* <p>
|
||||
* Advanced <a href="http://docs.oracle.com/javase/7/docs/webnotes/tsg/TSG-Desktop/html/java2d.html">debugging notes</a> for Java2D.
|
||||
@@ -1822,7 +1824,7 @@ public class PGraphicsJava2D extends PGraphics {
|
||||
public PShape loadShape(String filename, String options) {
|
||||
String extension = PApplet.getExtension(filename);
|
||||
if (extension.equals("svg") || extension.equals("svgz")) {
|
||||
return new PShapeSVG(parent.loadXML(filename));
|
||||
return new PShapeJava2D(parent.loadXML(filename));
|
||||
}
|
||||
PGraphics.showWarning("Unsupported format: " + filename);
|
||||
return null;
|
||||
|
||||
346
core/src/processing/awt/PShapeJava2D.java
Normal file
346
core/src/processing/awt/PShapeJava2D.java
Normal file
@@ -0,0 +1,346 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2015 The Processing Foundation
|
||||
|
||||
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.awt;
|
||||
|
||||
import java.awt.Paint;
|
||||
import java.awt.PaintContext;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.Raster;
|
||||
import java.awt.image.WritableRaster;
|
||||
|
||||
import processing.core.PApplet;
|
||||
import processing.core.PGraphics;
|
||||
import processing.core.PShapeSVG;
|
||||
import processing.data.*;
|
||||
|
||||
|
||||
/**
|
||||
* Implements features for PShape that are specific to AWT and Java2D.
|
||||
* At the moment, this is gradients and java.awt.Paint handling.
|
||||
*/
|
||||
public class PShapeJava2D extends PShapeSVG {
|
||||
Paint strokeGradientPaint;
|
||||
Paint fillGradientPaint;
|
||||
|
||||
|
||||
public PShapeJava2D(XML svg) {
|
||||
super(svg);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void setParent(PShapeSVG parent) {
|
||||
if (parent instanceof PShapeJava2D) {
|
||||
PShapeJava2D pj = (PShapeJava2D) parent;
|
||||
fillGradientPaint = pj.fillGradientPaint;
|
||||
strokeGradientPaint = pj.strokeGradientPaint;
|
||||
|
||||
} else { // parent is null or not Java2D
|
||||
fillGradientPaint = null;
|
||||
strokeGradientPaint = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class LinearGradientPaint implements Paint {
|
||||
float x1, y1, x2, y2;
|
||||
float[] offset;
|
||||
int[] color;
|
||||
int count;
|
||||
float opacity;
|
||||
|
||||
public LinearGradientPaint(float x1, float y1, float x2, float y2,
|
||||
float[] offset, int[] color, int count,
|
||||
float opacity) {
|
||||
this.x1 = x1;
|
||||
this.y1 = y1;
|
||||
this.x2 = x2;
|
||||
this.y2 = y2;
|
||||
this.offset = offset;
|
||||
this.color = color;
|
||||
this.count = count;
|
||||
this.opacity = opacity;
|
||||
}
|
||||
|
||||
public PaintContext createContext(ColorModel cm,
|
||||
Rectangle deviceBounds, Rectangle2D userBounds,
|
||||
AffineTransform xform, RenderingHints hints) {
|
||||
Point2D t1 = xform.transform(new Point2D.Float(x1, y1), null);
|
||||
Point2D t2 = xform.transform(new Point2D.Float(x2, y2), null);
|
||||
return new LinearGradientContext((float) t1.getX(), (float) t1.getY(),
|
||||
(float) t2.getX(), (float) t2.getY());
|
||||
}
|
||||
|
||||
public int getTransparency() {
|
||||
return TRANSLUCENT; // why not.. rather than checking each color
|
||||
}
|
||||
|
||||
public class LinearGradientContext implements PaintContext {
|
||||
int ACCURACY = 2;
|
||||
float tx1, ty1, tx2, ty2;
|
||||
|
||||
public LinearGradientContext(float tx1, float ty1, float tx2, float ty2) {
|
||||
this.tx1 = tx1;
|
||||
this.ty1 = ty1;
|
||||
this.tx2 = tx2;
|
||||
this.ty2 = ty2;
|
||||
}
|
||||
|
||||
public void dispose() { }
|
||||
|
||||
public ColorModel getColorModel() { return ColorModel.getRGBdefault(); }
|
||||
|
||||
public Raster getRaster(int x, int y, int w, int h) {
|
||||
WritableRaster raster =
|
||||
getColorModel().createCompatibleWritableRaster(w, h);
|
||||
|
||||
int[] data = new int[w * h * 4];
|
||||
|
||||
// make normalized version of base vector
|
||||
float nx = tx2 - tx1;
|
||||
float ny = ty2 - ty1;
|
||||
float len = (float) Math.sqrt(nx*nx + ny*ny);
|
||||
if (len != 0) {
|
||||
nx /= len;
|
||||
ny /= len;
|
||||
}
|
||||
|
||||
int span = (int) PApplet.dist(tx1, ty1, tx2, ty2) * ACCURACY;
|
||||
if (span <= 0) {
|
||||
//System.err.println("span is too small");
|
||||
// annoying edge case where the gradient isn't legit
|
||||
int index = 0;
|
||||
for (int j = 0; j < h; j++) {
|
||||
for (int i = 0; i < w; i++) {
|
||||
data[index++] = 0;
|
||||
data[index++] = 0;
|
||||
data[index++] = 0;
|
||||
data[index++] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
int[][] interp = new int[span][4];
|
||||
int prev = 0;
|
||||
for (int i = 1; i < count; i++) {
|
||||
int c0 = color[i-1];
|
||||
int c1 = color[i];
|
||||
int last = (int) (offset[i] * (span-1));
|
||||
//System.out.println("last is " + last);
|
||||
for (int j = prev; j <= last; j++) {
|
||||
float btwn = PApplet.norm(j, prev, last);
|
||||
interp[j][0] = (int) PApplet.lerp((c0 >> 16) & 0xff, (c1 >> 16) & 0xff, btwn);
|
||||
interp[j][1] = (int) PApplet.lerp((c0 >> 8) & 0xff, (c1 >> 8) & 0xff, btwn);
|
||||
interp[j][2] = (int) PApplet.lerp(c0 & 0xff, c1 & 0xff, btwn);
|
||||
interp[j][3] = (int) (PApplet.lerp((c0 >> 24) & 0xff, (c1 >> 24) & 0xff, btwn) * opacity);
|
||||
//System.out.println(j + " " + interp[j][0] + " " + interp[j][1] + " " + interp[j][2]);
|
||||
}
|
||||
prev = last;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
for (int j = 0; j < h; j++) {
|
||||
for (int i = 0; i < w; i++) {
|
||||
//float distance = 0; //PApplet.dist(cx, cy, x + i, y + j);
|
||||
//int which = PApplet.min((int) (distance * ACCURACY), interp.length-1);
|
||||
float px = (x + i) - tx1;
|
||||
float py = (y + j) - ty1;
|
||||
// distance up the line is the dot product of the normalized
|
||||
// vector of the gradient start/stop by the point being tested
|
||||
int which = (int) ((px*nx + py*ny) * ACCURACY);
|
||||
if (which < 0) which = 0;
|
||||
if (which > interp.length-1) which = interp.length-1;
|
||||
//if (which > 138) System.out.println("grabbing " + which);
|
||||
|
||||
data[index++] = interp[which][0];
|
||||
data[index++] = interp[which][1];
|
||||
data[index++] = interp[which][2];
|
||||
data[index++] = interp[which][3];
|
||||
}
|
||||
}
|
||||
}
|
||||
raster.setPixels(0, 0, w, h, data);
|
||||
|
||||
return raster;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class RadialGradientPaint implements Paint {
|
||||
float cx, cy, radius;
|
||||
float[] offset;
|
||||
int[] color;
|
||||
int count;
|
||||
float opacity;
|
||||
|
||||
public RadialGradientPaint(float cx, float cy, float radius,
|
||||
float[] offset, int[] color, int count,
|
||||
float opacity) {
|
||||
this.cx = cx;
|
||||
this.cy = cy;
|
||||
this.radius = radius;
|
||||
this.offset = offset;
|
||||
this.color = color;
|
||||
this.count = count;
|
||||
this.opacity = opacity;
|
||||
}
|
||||
|
||||
public PaintContext createContext(ColorModel cm,
|
||||
Rectangle deviceBounds, Rectangle2D userBounds,
|
||||
AffineTransform xform, RenderingHints hints) {
|
||||
return new RadialGradientContext();
|
||||
}
|
||||
|
||||
public int getTransparency() {
|
||||
return TRANSLUCENT;
|
||||
}
|
||||
|
||||
public class RadialGradientContext implements PaintContext {
|
||||
int ACCURACY = 5;
|
||||
|
||||
public void dispose() {}
|
||||
|
||||
public ColorModel getColorModel() { return ColorModel.getRGBdefault(); }
|
||||
|
||||
public Raster getRaster(int x, int y, int w, int h) {
|
||||
WritableRaster raster =
|
||||
getColorModel().createCompatibleWritableRaster(w, h);
|
||||
|
||||
int span = (int) radius * ACCURACY;
|
||||
int[][] interp = new int[span][4];
|
||||
int prev = 0;
|
||||
for (int i = 1; i < count; i++) {
|
||||
int c0 = color[i-1];
|
||||
int c1 = color[i];
|
||||
int last = (int) (offset[i] * (span - 1));
|
||||
for (int j = prev; j <= last; j++) {
|
||||
float btwn = PApplet.norm(j, prev, last);
|
||||
interp[j][0] = (int) PApplet.lerp((c0 >> 16) & 0xff, (c1 >> 16) & 0xff, btwn);
|
||||
interp[j][1] = (int) PApplet.lerp((c0 >> 8) & 0xff, (c1 >> 8) & 0xff, btwn);
|
||||
interp[j][2] = (int) PApplet.lerp(c0 & 0xff, c1 & 0xff, btwn);
|
||||
interp[j][3] = (int) (PApplet.lerp((c0 >> 24) & 0xff, (c1 >> 24) & 0xff, btwn) * opacity);
|
||||
}
|
||||
prev = last;
|
||||
}
|
||||
|
||||
int[] data = new int[w * h * 4];
|
||||
int index = 0;
|
||||
for (int j = 0; j < h; j++) {
|
||||
for (int i = 0; i < w; i++) {
|
||||
float distance = PApplet.dist(cx, cy, x + i, y + j);
|
||||
int which = PApplet.min((int) (distance * ACCURACY), interp.length-1);
|
||||
|
||||
data[index++] = interp[which][0];
|
||||
data[index++] = interp[which][1];
|
||||
data[index++] = interp[which][2];
|
||||
data[index++] = interp[which][3];
|
||||
}
|
||||
}
|
||||
raster.setPixels(0, 0, w, h, data);
|
||||
|
||||
return raster;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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.");
|
||||
// }
|
||||
|
||||
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
|
||||
@Override
|
||||
protected void styles(PGraphics g) {
|
||||
super.styles(g);
|
||||
|
||||
//if (g instanceof PGraphicsJava2D) {
|
||||
PGraphicsJava2D p2d = (PGraphicsJava2D) g;
|
||||
|
||||
if (strokeGradient != null) {
|
||||
p2d.strokeGradient = true;
|
||||
if (strokeGradientPaint == null) {
|
||||
strokeGradientPaint = calcGradientPaint(strokeGradient);
|
||||
}
|
||||
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;
|
||||
if (fillGradientPaint == null) {
|
||||
fillGradientPaint = calcGradientPaint(fillGradient);
|
||||
}
|
||||
p2d.fillGradientObject = fillGradientPaint;
|
||||
} else {
|
||||
// need to shut off, in case parent object has a gradient applied
|
||||
//p2d.fillGradient = false;
|
||||
}
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,8 @@
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2006-11 Ben Fry and Casey Reas
|
||||
Copyright (c) 2012-15 The Processing Foundation
|
||||
Copyright (c) 2006-12 Ben Fry and Casey Reas
|
||||
Copyright (c) 2004-06 Michael Chang
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
@@ -23,19 +24,12 @@
|
||||
|
||||
package processing.core;
|
||||
|
||||
import processing.awt.PGraphicsJava2D;
|
||||
import processing.data.*;
|
||||
|
||||
import java.awt.Paint;
|
||||
import java.awt.PaintContext;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
// TODO replace these with PMatrix2D
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.Raster;
|
||||
import java.awt.image.WritableRaster;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
|
||||
@@ -95,30 +89,23 @@ public class PShapeSVG extends PShape {
|
||||
XML element;
|
||||
|
||||
/// Values between 0 and 1.
|
||||
float opacity;
|
||||
protected float opacity;
|
||||
float strokeOpacity;
|
||||
float fillOpacity;
|
||||
|
||||
/**
|
||||
* Used for percentages. Width of containing SVG.
|
||||
*/
|
||||
/** Width of containing SVG (used for percentages). */
|
||||
protected float svgWidth;
|
||||
/**
|
||||
* Used for percentages. Height of containing SVG.
|
||||
*/
|
||||
|
||||
/** Height of containing SVG (used for percentages). */
|
||||
protected float svgHeight;
|
||||
/**
|
||||
* Used for percentages. √((w² + h²)/2) of containing SVG.
|
||||
*/
|
||||
|
||||
/** √((w² + h²)/2) of containing SVG (used for percentages). */
|
||||
protected float svgXYSize;
|
||||
|
||||
|
||||
Gradient strokeGradient;
|
||||
Paint strokeGradientPaint;
|
||||
protected Gradient strokeGradient;
|
||||
String strokeName; // id of another object, gradients only?
|
||||
|
||||
Gradient fillGradient;
|
||||
Paint fillGradientPaint;
|
||||
protected Gradient fillGradient;
|
||||
String fillName; // id of another object
|
||||
|
||||
|
||||
@@ -150,7 +137,9 @@ public class PShapeSVG extends PShape {
|
||||
}
|
||||
|
||||
|
||||
protected PShapeSVG(PShapeSVG parent, XML properties, boolean parseKids) {
|
||||
// Broken out so that subclasses can copy any additional variables
|
||||
// (i.e. fillGradientPaint and strokeGradientPaint)
|
||||
protected void setParent(PShapeSVG parent) {
|
||||
// Need to set this so that findChild() works.
|
||||
// Otherwise 'parent' is null until addChild() is called later.
|
||||
this.parent = parent;
|
||||
@@ -163,13 +152,13 @@ public class PShapeSVG extends PShape {
|
||||
strokeCap = PConstants.SQUARE; // equivalent to BUTT in svg spec
|
||||
strokeJoin = PConstants.MITER;
|
||||
strokeGradient = null;
|
||||
strokeGradientPaint = null;
|
||||
// strokeGradientPaint = null;
|
||||
strokeName = null;
|
||||
|
||||
fill = true;
|
||||
fillColor = 0xff000000;
|
||||
fillGradient = null;
|
||||
fillGradientPaint = null;
|
||||
// fillGradientPaint = null;
|
||||
fillName = null;
|
||||
|
||||
//hasTransform = false;
|
||||
@@ -188,24 +177,26 @@ public class PShapeSVG extends PShape {
|
||||
strokeCap = parent.strokeCap;
|
||||
strokeJoin = parent.strokeJoin;
|
||||
strokeGradient = parent.strokeGradient;
|
||||
strokeGradientPaint = parent.strokeGradientPaint;
|
||||
// strokeGradientPaint = parent.strokeGradientPaint;
|
||||
strokeName = parent.strokeName;
|
||||
|
||||
fill = parent.fill;
|
||||
fillColor = parent.fillColor;
|
||||
fillGradient = parent.fillGradient;
|
||||
fillGradientPaint = parent.fillGradientPaint;
|
||||
// fillGradientPaint = parent.fillGradientPaint;
|
||||
fillName = parent.fillName;
|
||||
|
||||
//hasTransform = parent.hasTransform;
|
||||
//transformation = parent.transformation;
|
||||
|
||||
svgWidth = parent.svgWidth;
|
||||
svgHeight = parent.svgHeight;
|
||||
svgXYSize = parent.svgXYSize;
|
||||
|
||||
opacity = parent.opacity;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected PShapeSVG(PShapeSVG parent, XML properties, boolean parseKids) {
|
||||
setParent(parent);
|
||||
|
||||
// Need to get width/height in early.
|
||||
if (properties.getName().equals("svg")) {
|
||||
@@ -1256,7 +1247,7 @@ public class PShapeSVG extends PShape {
|
||||
String name = "";
|
||||
// String lColorText = colorText.toLowerCase();
|
||||
Gradient gradient = null;
|
||||
Paint paint = null;
|
||||
// Object paint = null;
|
||||
if (colorText.equals("none")) {
|
||||
visible = false;
|
||||
} else if (colorText.startsWith("url(#")) {
|
||||
@@ -1264,7 +1255,8 @@ public class PShapeSVG extends PShape {
|
||||
Object object = findChild(name);
|
||||
if (object instanceof Gradient) {
|
||||
gradient = (Gradient) object;
|
||||
paint = calcGradientPaint(gradient); //, opacity);
|
||||
// in 3.0a11, do this on first draw inside PShapeJava2D
|
||||
// paint = calcGradientPaint(gradient); //, opacity);
|
||||
} else {
|
||||
// visible = false;
|
||||
System.err.println("url " + name + " refers to unexpected data: " + object);
|
||||
@@ -1278,13 +1270,13 @@ public class PShapeSVG extends PShape {
|
||||
fillColor = color;
|
||||
fillName = name;
|
||||
fillGradient = gradient;
|
||||
fillGradientPaint = paint;
|
||||
// fillGradientPaint = paint;
|
||||
} else {
|
||||
stroke = visible;
|
||||
strokeColor = color;
|
||||
strokeName = name;
|
||||
strokeGradient = gradient;
|
||||
strokeGradientPaint = paint;
|
||||
// strokeGradientPaint = paint;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1316,8 +1308,8 @@ public class PShapeSVG extends PShape {
|
||||
|
||||
|
||||
/**
|
||||
* Deliberately conforms to HTML 4.01 color spec + en-gb grey,
|
||||
* not SVG's 147-color system.
|
||||
* Deliberately conforms to the HTML 4.01 color spec + en-gb grey, rather
|
||||
* than the (unlikely to be useful) entire 147-color system used in SVG.
|
||||
*/
|
||||
static protected IntDict colorNames = new IntDict(new Object[][] {
|
||||
{ "aqua", 0x00ffff },
|
||||
@@ -1469,12 +1461,12 @@ public class PShapeSVG extends PShape {
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
|
||||
static class Gradient extends PShapeSVG {
|
||||
static public class Gradient extends PShapeSVG {
|
||||
AffineTransform transform;
|
||||
|
||||
float[] offset;
|
||||
int[] color;
|
||||
int count;
|
||||
public float[] offset;
|
||||
public int[] color;
|
||||
public int count;
|
||||
|
||||
public Gradient(PShapeSVG parent, XML properties) {
|
||||
super(parent, properties, true);
|
||||
@@ -1517,8 +1509,8 @@ public class PShapeSVG extends PShape {
|
||||
}
|
||||
|
||||
|
||||
static class LinearGradient extends Gradient {
|
||||
float x1, y1, x2, y2;
|
||||
public class LinearGradient extends Gradient {
|
||||
public float x1, y1, x2, y2;
|
||||
|
||||
public LinearGradient(PShapeSVG parent, XML properties) {
|
||||
super(parent, properties);
|
||||
@@ -1547,8 +1539,8 @@ public class PShapeSVG extends PShape {
|
||||
}
|
||||
|
||||
|
||||
static class RadialGradient extends Gradient {
|
||||
float cx, cy, r;
|
||||
public class RadialGradient extends Gradient {
|
||||
public float cx, cy, r;
|
||||
|
||||
public RadialGradient(PShapeSVG parent, XML properties) {
|
||||
super(parent, properties);
|
||||
@@ -1575,287 +1567,6 @@ public class PShapeSVG extends PShape {
|
||||
}
|
||||
|
||||
|
||||
|
||||
static class LinearGradientPaint implements Paint {
|
||||
float x1, y1, x2, y2;
|
||||
float[] offset;
|
||||
int[] color;
|
||||
int count;
|
||||
float opacity;
|
||||
|
||||
public LinearGradientPaint(float x1, float y1, float x2, float y2,
|
||||
float[] offset, int[] color, int count,
|
||||
float opacity) {
|
||||
this.x1 = x1;
|
||||
this.y1 = y1;
|
||||
this.x2 = x2;
|
||||
this.y2 = y2;
|
||||
this.offset = offset;
|
||||
this.color = color;
|
||||
this.count = count;
|
||||
this.opacity = opacity;
|
||||
}
|
||||
|
||||
public PaintContext createContext(ColorModel cm,
|
||||
Rectangle deviceBounds, Rectangle2D userBounds,
|
||||
AffineTransform xform, RenderingHints hints) {
|
||||
Point2D t1 = xform.transform(new Point2D.Float(x1, y1), null);
|
||||
Point2D t2 = xform.transform(new Point2D.Float(x2, y2), null);
|
||||
return new LinearGradientContext((float) t1.getX(), (float) t1.getY(),
|
||||
(float) t2.getX(), (float) t2.getY());
|
||||
}
|
||||
|
||||
public int getTransparency() {
|
||||
return TRANSLUCENT; // why not.. rather than checking each color
|
||||
}
|
||||
|
||||
public class LinearGradientContext implements PaintContext {
|
||||
int ACCURACY = 2;
|
||||
float tx1, ty1, tx2, ty2;
|
||||
|
||||
public LinearGradientContext(float tx1, float ty1, float tx2, float ty2) {
|
||||
this.tx1 = tx1;
|
||||
this.ty1 = ty1;
|
||||
this.tx2 = tx2;
|
||||
this.ty2 = ty2;
|
||||
}
|
||||
|
||||
public void dispose() { }
|
||||
|
||||
public ColorModel getColorModel() { return ColorModel.getRGBdefault(); }
|
||||
|
||||
public Raster getRaster(int x, int y, int w, int h) {
|
||||
WritableRaster raster =
|
||||
getColorModel().createCompatibleWritableRaster(w, h);
|
||||
|
||||
int[] data = new int[w * h * 4];
|
||||
|
||||
// make normalized version of base vector
|
||||
float nx = tx2 - tx1;
|
||||
float ny = ty2 - ty1;
|
||||
float len = (float) Math.sqrt(nx*nx + ny*ny);
|
||||
if (len != 0) {
|
||||
nx /= len;
|
||||
ny /= len;
|
||||
}
|
||||
|
||||
int span = (int) PApplet.dist(tx1, ty1, tx2, ty2) * ACCURACY;
|
||||
if (span <= 0) {
|
||||
//System.err.println("span is too small");
|
||||
// annoying edge case where the gradient isn't legit
|
||||
int index = 0;
|
||||
for (int j = 0; j < h; j++) {
|
||||
for (int i = 0; i < w; i++) {
|
||||
data[index++] = 0;
|
||||
data[index++] = 0;
|
||||
data[index++] = 0;
|
||||
data[index++] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
int[][] interp = new int[span][4];
|
||||
int prev = 0;
|
||||
for (int i = 1; i < count; i++) {
|
||||
int c0 = color[i-1];
|
||||
int c1 = color[i];
|
||||
int last = (int) (offset[i] * (span-1));
|
||||
//System.out.println("last is " + last);
|
||||
for (int j = prev; j <= last; j++) {
|
||||
float btwn = PApplet.norm(j, prev, last);
|
||||
interp[j][0] = (int) PApplet.lerp((c0 >> 16) & 0xff, (c1 >> 16) & 0xff, btwn);
|
||||
interp[j][1] = (int) PApplet.lerp((c0 >> 8) & 0xff, (c1 >> 8) & 0xff, btwn);
|
||||
interp[j][2] = (int) PApplet.lerp(c0 & 0xff, c1 & 0xff, btwn);
|
||||
interp[j][3] = (int) (PApplet.lerp((c0 >> 24) & 0xff, (c1 >> 24) & 0xff, btwn) * opacity);
|
||||
//System.out.println(j + " " + interp[j][0] + " " + interp[j][1] + " " + interp[j][2]);
|
||||
}
|
||||
prev = last;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
for (int j = 0; j < h; j++) {
|
||||
for (int i = 0; i < w; i++) {
|
||||
//float distance = 0; //PApplet.dist(cx, cy, x + i, y + j);
|
||||
//int which = PApplet.min((int) (distance * ACCURACY), interp.length-1);
|
||||
float px = (x + i) - tx1;
|
||||
float py = (y + j) - ty1;
|
||||
// distance up the line is the dot product of the normalized
|
||||
// vector of the gradient start/stop by the point being tested
|
||||
int which = (int) ((px*nx + py*ny) * ACCURACY);
|
||||
if (which < 0) which = 0;
|
||||
if (which > interp.length-1) which = interp.length-1;
|
||||
//if (which > 138) System.out.println("grabbing " + which);
|
||||
|
||||
data[index++] = interp[which][0];
|
||||
data[index++] = interp[which][1];
|
||||
data[index++] = interp[which][2];
|
||||
data[index++] = interp[which][3];
|
||||
}
|
||||
}
|
||||
}
|
||||
raster.setPixels(0, 0, w, h, data);
|
||||
|
||||
return raster;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class RadialGradientPaint implements Paint {
|
||||
float cx, cy, radius;
|
||||
float[] offset;
|
||||
int[] color;
|
||||
int count;
|
||||
float opacity;
|
||||
|
||||
public RadialGradientPaint(float cx, float cy, float radius,
|
||||
float[] offset, int[] color, int count,
|
||||
float opacity) {
|
||||
this.cx = cx;
|
||||
this.cy = cy;
|
||||
this.radius = radius;
|
||||
this.offset = offset;
|
||||
this.color = color;
|
||||
this.count = count;
|
||||
this.opacity = opacity;
|
||||
}
|
||||
|
||||
public PaintContext createContext(ColorModel cm,
|
||||
Rectangle deviceBounds, Rectangle2D userBounds,
|
||||
AffineTransform xform, RenderingHints hints) {
|
||||
return new RadialGradientContext();
|
||||
}
|
||||
|
||||
public int getTransparency() {
|
||||
return TRANSLUCENT;
|
||||
}
|
||||
|
||||
public class RadialGradientContext implements PaintContext {
|
||||
int ACCURACY = 5;
|
||||
|
||||
public void dispose() {}
|
||||
|
||||
public ColorModel getColorModel() { return ColorModel.getRGBdefault(); }
|
||||
|
||||
public Raster getRaster(int x, int y, int w, int h) {
|
||||
WritableRaster raster =
|
||||
getColorModel().createCompatibleWritableRaster(w, h);
|
||||
|
||||
int span = (int) radius * ACCURACY;
|
||||
int[][] interp = new int[span][4];
|
||||
int prev = 0;
|
||||
for (int i = 1; i < count; i++) {
|
||||
int c0 = color[i-1];
|
||||
int c1 = color[i];
|
||||
int last = (int) (offset[i] * (span - 1));
|
||||
for (int j = prev; j <= last; j++) {
|
||||
float btwn = PApplet.norm(j, prev, last);
|
||||
interp[j][0] = (int) PApplet.lerp((c0 >> 16) & 0xff, (c1 >> 16) & 0xff, btwn);
|
||||
interp[j][1] = (int) PApplet.lerp((c0 >> 8) & 0xff, (c1 >> 8) & 0xff, btwn);
|
||||
interp[j][2] = (int) PApplet.lerp(c0 & 0xff, c1 & 0xff, btwn);
|
||||
interp[j][3] = (int) (PApplet.lerp((c0 >> 24) & 0xff, (c1 >> 24) & 0xff, btwn) * opacity);
|
||||
}
|
||||
prev = last;
|
||||
}
|
||||
|
||||
int[] data = new int[w * h * 4];
|
||||
int index = 0;
|
||||
for (int j = 0; j < h; j++) {
|
||||
for (int i = 0; i < w; i++) {
|
||||
float distance = PApplet.dist(cx, cy, x + i, y + j);
|
||||
int which = PApplet.min((int) (distance * ACCURACY), interp.length-1);
|
||||
|
||||
data[index++] = interp[which][0];
|
||||
data[index++] = interp[which][1];
|
||||
data[index++] = interp[which][2];
|
||||
data[index++] = interp[which][3];
|
||||
}
|
||||
}
|
||||
raster.setPixels(0, 0, w, h, data);
|
||||
|
||||
return raster;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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.");
|
||||
// }
|
||||
|
||||
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
|
||||
//public void drawImpl(PGraphics g) {
|
||||
// do nothing
|
||||
//}
|
||||
|
||||
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user