Skip to content

Commit 725b3ba

Browse files
committed
break PShape into AWT and non-AWT code
1 parent e2e6851 commit 725b3ba

File tree

3 files changed

+391
-332
lines changed

3 files changed

+391
-332
lines changed

core/src/processing/awt/PGraphicsJava2D.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,11 @@
4040
* <p>
4141
* To get access to the Java 2D "Graphics2D" object for the default
4242
* renderer, use:
43-
* <PRE>Graphics2D g2 = ((PGraphicsJava2D)g).g2;</PRE>
44-
* This will let you do Java 2D stuff directly, but is not supported in
45-
* any way shape or form. Which just means "have fun, but don't complain
43+
* <PRE>
44+
* Graphics2D g2 = (Graphics2D) g.getNative();
45+
* </PRE>
46+
* This will let you do Graphics2D calls directly, but is not supported
47+
* in any way shape or form. Which just means "have fun, but don't complain
4648
* if it breaks."
4749
* <p>
4850
* 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 void update(PImage source, boolean tint, int tintColor) {
18221824
public PShape loadShape(String filename, String options) {
18231825
String extension = PApplet.getExtension(filename);
18241826
if (extension.equals("svg") || extension.equals("svgz")) {
1825-
return new PShapeSVG(parent.loadXML(filename));
1827+
return new PShapeJava2D(parent.loadXML(filename));
18261828
}
18271829
PGraphics.showWarning("Unsupported format: " + filename);
18281830
return null;
Lines changed: 346 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,346 @@
1+
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2+
3+
/*
4+
Part of the Processing project - http://processing.org
5+
6+
Copyright (c) 2015 The Processing Foundation
7+
8+
This library is free software; you can redistribute it and/or
9+
modify it under the terms of the GNU Lesser General Public
10+
License version 2.1 as published by the Free Software Foundation.
11+
12+
This library is distributed in the hope that it will be useful,
13+
but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15+
Lesser General Public License for more details.
16+
17+
You should have received a copy of the GNU Lesser General
18+
Public License along with this library; if not, write to the
19+
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20+
Boston, MA 02111-1307 USA
21+
*/
22+
23+
package processing.awt;
24+
25+
import java.awt.Paint;
26+
import java.awt.PaintContext;
27+
import java.awt.Rectangle;
28+
import java.awt.RenderingHints;
29+
import java.awt.geom.AffineTransform;
30+
import java.awt.geom.Point2D;
31+
import java.awt.geom.Rectangle2D;
32+
import java.awt.image.ColorModel;
33+
import java.awt.image.Raster;
34+
import java.awt.image.WritableRaster;
35+
36+
import processing.core.PApplet;
37+
import processing.core.PGraphics;
38+
import processing.core.PShapeSVG;
39+
import processing.data.*;
40+
41+
42+
/**
43+
* Implements features for PShape that are specific to AWT and Java2D.
44+
* At the moment, this is gradients and java.awt.Paint handling.
45+
*/
46+
public class PShapeJava2D extends PShapeSVG {
47+
Paint strokeGradientPaint;
48+
Paint fillGradientPaint;
49+
50+
51+
public PShapeJava2D(XML svg) {
52+
super(svg);
53+
}
54+
55+
56+
@Override
57+
protected void setParent(PShapeSVG parent) {
58+
if (parent instanceof PShapeJava2D) {
59+
PShapeJava2D pj = (PShapeJava2D) parent;
60+
fillGradientPaint = pj.fillGradientPaint;
61+
strokeGradientPaint = pj.strokeGradientPaint;
62+
63+
} else { // parent is null or not Java2D
64+
fillGradientPaint = null;
65+
strokeGradientPaint = null;
66+
}
67+
}
68+
69+
70+
static class LinearGradientPaint implements Paint {
71+
float x1, y1, x2, y2;
72+
float[] offset;
73+
int[] color;
74+
int count;
75+
float opacity;
76+
77+
public LinearGradientPaint(float x1, float y1, float x2, float y2,
78+
float[] offset, int[] color, int count,
79+
float opacity) {
80+
this.x1 = x1;
81+
this.y1 = y1;
82+
this.x2 = x2;
83+
this.y2 = y2;
84+
this.offset = offset;
85+
this.color = color;
86+
this.count = count;
87+
this.opacity = opacity;
88+
}
89+
90+
public PaintContext createContext(ColorModel cm,
91+
Rectangle deviceBounds, Rectangle2D userBounds,
92+
AffineTransform xform, RenderingHints hints) {
93+
Point2D t1 = xform.transform(new Point2D.Float(x1, y1), null);
94+
Point2D t2 = xform.transform(new Point2D.Float(x2, y2), null);
95+
return new LinearGradientContext((float) t1.getX(), (float) t1.getY(),
96+
(float) t2.getX(), (float) t2.getY());
97+
}
98+
99+
public int getTransparency() {
100+
return TRANSLUCENT; // why not.. rather than checking each color
101+
}
102+
103+
public class LinearGradientContext implements PaintContext {
104+
int ACCURACY = 2;
105+
float tx1, ty1, tx2, ty2;
106+
107+
public LinearGradientContext(float tx1, float ty1, float tx2, float ty2) {
108+
this.tx1 = tx1;
109+
this.ty1 = ty1;
110+
this.tx2 = tx2;
111+
this.ty2 = ty2;
112+
}
113+
114+
public void dispose() { }
115+
116+
public ColorModel getColorModel() { return ColorModel.getRGBdefault(); }
117+
118+
public Raster getRaster(int x, int y, int w, int h) {
119+
WritableRaster raster =
120+
getColorModel().createCompatibleWritableRaster(w, h);
121+
122+
int[] data = new int[w * h * 4];
123+
124+
// make normalized version of base vector
125+
float nx = tx2 - tx1;
126+
float ny = ty2 - ty1;
127+
float len = (float) Math.sqrt(nx*nx + ny*ny);
128+
if (len != 0) {
129+
nx /= len;
130+
ny /= len;
131+
}
132+
133+
int span = (int) PApplet.dist(tx1, ty1, tx2, ty2) * ACCURACY;
134+
if (span <= 0) {
135+
//System.err.println("span is too small");
136+
// annoying edge case where the gradient isn't legit
137+
int index = 0;
138+
for (int j = 0; j < h; j++) {
139+
for (int i = 0; i < w; i++) {
140+
data[index++] = 0;
141+
data[index++] = 0;
142+
data[index++] = 0;
143+
data[index++] = 255;
144+
}
145+
}
146+
147+
} else {
148+
int[][] interp = new int[span][4];
149+
int prev = 0;
150+
for (int i = 1; i < count; i++) {
151+
int c0 = color[i-1];
152+
int c1 = color[i];
153+
int last = (int) (offset[i] * (span-1));
154+
//System.out.println("last is " + last);
155+
for (int j = prev; j <= last; j++) {
156+
float btwn = PApplet.norm(j, prev, last);
157+
interp[j][0] = (int) PApplet.lerp((c0 >> 16) & 0xff, (c1 >> 16) & 0xff, btwn);
158+
interp[j][1] = (int) PApplet.lerp((c0 >> 8) & 0xff, (c1 >> 8) & 0xff, btwn);
159+
interp[j][2] = (int) PApplet.lerp(c0 & 0xff, c1 & 0xff, btwn);
160+
interp[j][3] = (int) (PApplet.lerp((c0 >> 24) & 0xff, (c1 >> 24) & 0xff, btwn) * opacity);
161+
//System.out.println(j + " " + interp[j][0] + " " + interp[j][1] + " " + interp[j][2]);
162+
}
163+
prev = last;
164+
}
165+
166+
int index = 0;
167+
for (int j = 0; j < h; j++) {
168+
for (int i = 0; i < w; i++) {
169+
//float distance = 0; //PApplet.dist(cx, cy, x + i, y + j);
170+
//int which = PApplet.min((int) (distance * ACCURACY), interp.length-1);
171+
float px = (x + i) - tx1;
172+
float py = (y + j) - ty1;
173+
// distance up the line is the dot product of the normalized
174+
// vector of the gradient start/stop by the point being tested
175+
int which = (int) ((px*nx + py*ny) * ACCURACY);
176+
if (which < 0) which = 0;
177+
if (which > interp.length-1) which = interp.length-1;
178+
//if (which > 138) System.out.println("grabbing " + which);
179+
180+
data[index++] = interp[which][0];
181+
data[index++] = interp[which][1];
182+
data[index++] = interp[which][2];
183+
data[index++] = interp[which][3];
184+
}
185+
}
186+
}
187+
raster.setPixels(0, 0, w, h, data);
188+
189+
return raster;
190+
}
191+
}
192+
}
193+
194+
195+
static class RadialGradientPaint implements Paint {
196+
float cx, cy, radius;
197+
float[] offset;
198+
int[] color;
199+
int count;
200+
float opacity;
201+
202+
public RadialGradientPaint(float cx, float cy, float radius,
203+
float[] offset, int[] color, int count,
204+
float opacity) {
205+
this.cx = cx;
206+
this.cy = cy;
207+
this.radius = radius;
208+
this.offset = offset;
209+
this.color = color;
210+
this.count = count;
211+
this.opacity = opacity;
212+
}
213+
214+
public PaintContext createContext(ColorModel cm,
215+
Rectangle deviceBounds, Rectangle2D userBounds,
216+
AffineTransform xform, RenderingHints hints) {
217+
return new RadialGradientContext();
218+
}
219+
220+
public int getTransparency() {
221+
return TRANSLUCENT;
222+
}
223+
224+
public class RadialGradientContext implements PaintContext {
225+
int ACCURACY = 5;
226+
227+
public void dispose() {}
228+
229+
public ColorModel getColorModel() { return ColorModel.getRGBdefault(); }
230+
231+
public Raster getRaster(int x, int y, int w, int h) {
232+
WritableRaster raster =
233+
getColorModel().createCompatibleWritableRaster(w, h);
234+
235+
int span = (int) radius * ACCURACY;
236+
int[][] interp = new int[span][4];
237+
int prev = 0;
238+
for (int i = 1; i < count; i++) {
239+
int c0 = color[i-1];
240+
int c1 = color[i];
241+
int last = (int) (offset[i] * (span - 1));
242+
for (int j = prev; j <= last; j++) {
243+
float btwn = PApplet.norm(j, prev, last);
244+
interp[j][0] = (int) PApplet.lerp((c0 >> 16) & 0xff, (c1 >> 16) & 0xff, btwn);
245+
interp[j][1] = (int) PApplet.lerp((c0 >> 8) & 0xff, (c1 >> 8) & 0xff, btwn);
246+
interp[j][2] = (int) PApplet.lerp(c0 & 0xff, c1 & 0xff, btwn);
247+
interp[j][3] = (int) (PApplet.lerp((c0 >> 24) & 0xff, (c1 >> 24) & 0xff, btwn) * opacity);
248+
}
249+
prev = last;
250+
}
251+
252+
int[] data = new int[w * h * 4];
253+
int index = 0;
254+
for (int j = 0; j < h; j++) {
255+
for (int i = 0; i < w; i++) {
256+
float distance = PApplet.dist(cx, cy, x + i, y + j);
257+
int which = PApplet.min((int) (distance * ACCURACY), interp.length-1);
258+
259+
data[index++] = interp[which][0];
260+
data[index++] = interp[which][1];
261+
data[index++] = interp[which][2];
262+
data[index++] = interp[which][3];
263+
}
264+
}
265+
raster.setPixels(0, 0, w, h, data);
266+
267+
return raster;
268+
}
269+
}
270+
}
271+
272+
273+
protected Paint calcGradientPaint(Gradient gradient) {
274+
if (gradient instanceof LinearGradient) {
275+
LinearGradient grad = (LinearGradient) gradient;
276+
return new LinearGradientPaint(grad.x1, grad.y1, grad.x2, grad.y2,
277+
grad.offset, grad.color, grad.count,
278+
opacity);
279+
280+
} else if (gradient instanceof RadialGradient) {
281+
RadialGradient grad = (RadialGradient) gradient;
282+
return new RadialGradientPaint(grad.cx, grad.cy, grad.r,
283+
grad.offset, grad.color, grad.count,
284+
opacity);
285+
}
286+
return null;
287+
}
288+
289+
290+
// protected Paint calcGradientPaint(Gradient gradient,
291+
// float x1, float y1, float x2, float y2) {
292+
// if (gradient instanceof LinearGradient) {
293+
// LinearGradient grad = (LinearGradient) gradient;
294+
// return new LinearGradientPaint(x1, y1, x2, y2,
295+
// grad.offset, grad.color, grad.count,
296+
// opacity);
297+
// }
298+
// throw new RuntimeException("Not a linear gradient.");
299+
// }
300+
301+
302+
// protected Paint calcGradientPaint(Gradient gradient,
303+
// float cx, float cy, float r) {
304+
// if (gradient instanceof RadialGradient) {
305+
// RadialGradient grad = (RadialGradient) gradient;
306+
// return new RadialGradientPaint(cx, cy, r,
307+
// grad.offset, grad.color, grad.count,
308+
// opacity);
309+
// }
310+
// throw new RuntimeException("Not a radial gradient.");
311+
// }
312+
313+
314+
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
315+
316+
317+
@Override
318+
protected void styles(PGraphics g) {
319+
super.styles(g);
320+
321+
//if (g instanceof PGraphicsJava2D) {
322+
PGraphicsJava2D p2d = (PGraphicsJava2D) g;
323+
324+
if (strokeGradient != null) {
325+
p2d.strokeGradient = true;
326+
if (strokeGradientPaint == null) {
327+
strokeGradientPaint = calcGradientPaint(strokeGradient);
328+
}
329+
p2d.strokeGradientObject = strokeGradientPaint;
330+
} else {
331+
// need to shut off, in case parent object has a gradient applied
332+
//p2d.strokeGradient = false;
333+
}
334+
if (fillGradient != null) {
335+
p2d.fillGradient = true;
336+
if (fillGradientPaint == null) {
337+
fillGradientPaint = calcGradientPaint(fillGradient);
338+
}
339+
p2d.fillGradientObject = fillGradientPaint;
340+
} else {
341+
// need to shut off, in case parent object has a gradient applied
342+
//p2d.fillGradient = false;
343+
}
344+
//}
345+
}
346+
}

0 commit comments

Comments
 (0)