on the road to hell

This commit is contained in:
benfry
2006-07-19 00:55:11 +00:00
parent adfc974a44
commit 3e7158145c
5 changed files with 636 additions and 697 deletions

View File

@@ -60,11 +60,7 @@ public interface PConstants {
// for better parity between c++ version (at no speed cost)
static final float EPSILON = 0.0001f;
static final float TWO = 2.0f;
static final float ONE = 1.0f;
static final float HALF = 0.5f;
static final float TFF = 255.0f;
static final float MAX_FLOAT = Float.MAX_VALUE;
// useful goodness

View File

@@ -236,8 +236,8 @@ public abstract class PGraphics extends PImage implements PConstants {
-3, 3, 0, 0,
1, 0, 0, 0);
protected float bezier_forward[][]; // = new float[4][4];
protected float bezier_draw[][]; // = new float[4][4];
protected float bezierForwardMatrix[][]; // = new float[4][4];
protected float bezierDrawMatrix[][]; // = new float[4][4];
// ........................................................
@@ -598,8 +598,8 @@ public abstract class PGraphics extends PImage implements PConstants {
public void defaults() { // ignore
//System.out.println("PGraphics.defaults() " + width + " " + height);
colorMode(RGB, TFF);
fill(TFF);
colorMode(RGB, 255);
fill(255);
stroke(0);
// other stroke attributes are set in the initializers
// inside the class (see above, strokeWeight = 1 et al)
@@ -993,6 +993,14 @@ public abstract class PGraphics extends PImage implements PConstants {
}
/**
* Implementation of generic spline vertex, will add coords to
* the splineVertices[] array and emit calls to draw segments
* as needed (every fourth point for bezier or every point starting
* with the fourth for catmull-rom).
* @param z z-coordinate, set to MAX_VALUE if it's 2D
* @param bezier true if it's a bezier instead of catmull-rom
*/
protected void splineVertex(float x, float y, float z, boolean bezier) {
// to improve processing applet load times, don't allocate
// space for the vertex data until actual use
@@ -1053,10 +1061,10 @@ public abstract class PGraphics extends PImage implements PConstants {
if (splineVertexCount > 3) {
if (bezier) {
if ((splineVertexCount % 4) == 0) {
if (!bezierInited) bezier_init();
if (!bezierInited) bezierInit();
splineSegment(splineVertexCount-4,
splineVertexCount-4,
bezier_draw, dimensions,
bezierDrawMatrix, dimensions,
bezierDetail);
}
} else { // catmull-rom curve (!bezier)
@@ -1070,103 +1078,9 @@ public abstract class PGraphics extends PImage implements PConstants {
}
/*
protected void bezier_vertex(float x, float y) {
vertexCount = 0;
if (splineVertices == null) {
splineVertices = new float[DEFAULT_SPLINE_VERTICES][VERTEX_FIELD_COUNT];
}
// if more than 128 points, shift everything back to the beginning
if (splineVertexCount == DEFAULT_SPLINE_VERTICES) {
System.arraycopy(splineVertices[DEFAULT_SPLINE_VERTICES - 3], 0,
splineVertices[0], 0, VERTEX_FIELD_COUNT);
System.arraycopy(splineVertices[DEFAULT_SPLINE_VERTICES - 2], 0,
splineVertices[1], 0, VERTEX_FIELD_COUNT);
splineVertexCount = 3;
}
splineVertices[splineVertexCount][MX] = x;
splineVertices[splineVertexCount][MY] = y;
splineVertexCount++;
switch (shape) {
case LINE_LOOP:
case LINE_STRIP:
case POLYGON:
if (splineVertexCount == 1) {
path.moveTo(x, y);
} else if (splineVertexCount >= 4) {
path.curveTo(splineVertices[splineVertexCount-3][MX],
splineVertices[splineVertexCount-3][MY],
splineVertices[splineVertexCount-2][MX],
splineVertices[splineVertexCount-2][MY],
x, y);
}
break;
default:
throw new RuntimeException("bezierVertex() can only be used with " +
"LINE_LOOP and POLYGON shapes");
}
}
*/
/*
public void bezierVertex(float x1, float y1, float z1,
float x2, float y2, float z2,
float x3, float y3, float z3) {
depthErrorXYZ("bezierVertex");
}
*/
/**
* See notes with the curve() function.
*/
/*
public void curveVertex(float x, float y) {
//throw new RuntimeException("curveVertex() temporarily disabled");
// TODO get matrix setup happening
}
*/
/**
* See notes with the curve() function.
*/
/*
public void curveVertex(float x, float y, float z) {
depthErrorXYZ("curveVertex");
}
*/
abstract public void endShape();
/*
shape = 0;
switch (shape) {
case LINE_STRIP:
stroke_shape(path);
break;
case LINE_LOOP:
path.closePath();
stroke_shape(path);
break;
case POLYGON:
path.closePath();
draw_shape(path);
break;
}
}
*/
//////////////////////////////////////////////////////////////
@@ -1210,43 +1124,6 @@ public abstract class PGraphics extends PImage implements PConstants {
//////////////////////////////////////////////////////////////
// STROKE/FILL/DRAW
/*
//protected void fill_shape(Shape s) {
protected void fill_shape(Path s) {
if (fill) {
//graphics.setColor(fillColorObject);
//graphics.fill(s);
}
}
//protected void stroke_shape(Shape s) {
protected void stroke_shape(Path s) {
if (stroke) {
//graphics.setColor(strokeColorObject);
//graphics.draw(s);
}
}
//protected void draw_shape(Shape s) {
protected void draw_shape(Path s) {
if (fill) {
//graphics.setColor(fillColorObject);
//graphics.fill(s);
}
if (stroke) {
//graphics.setColor(strokeColorObject);
//graphics.draw(s);
}
}
*/
//////////////////////////////////////////////////////////////
// SIMPLE SHAPES WITH ANALOGUES IN beginShape()
@@ -1353,12 +1230,7 @@ public abstract class PGraphics extends PImage implements PConstants {
protected void rectImpl(float x1, float y1, float x2, float y2) {
beginShape(QUADS);
vertex(x1, y1);
vertex(x2, y1);
vertex(x2, y2);
vertex(x1, y2);
endShape();
quad(x1, y1, x2, y1, x2, y2, x1, y2);
}
@@ -1408,8 +1280,76 @@ public abstract class PGraphics extends PImage implements PConstants {
}
protected void ellipseImpl(float x, float y, float w, float h) {
// TODO draw an ellipse
protected void ellipseImpl(float x1, float y1, float w, float h) {
float hradius = w / 2f;
float vradius = h / 2f;
float centerX = x1 + hradius;
float centerY = y1 + vradius;
// adapt accuracy to radii used w/ a minimum of 4 segments [toxi]
// now uses current scale factors to determine "real" transformed radius
//int cAccuracy = (int)(4+Math.sqrt(hradius*abs(m00)+vradius*abs(m11))*2);
//int cAccuracy = (int)(4+Math.sqrt(hradius+vradius)*2);
// notched this up to *3 instead of *2 because things were
// looking a little rough, i.e. the calculate->arctangent example [fry]
// also removed the m00 and m11 because those were causing weirdness
// need an actual measure of magnitude in there [fry]
int accuracy = (int)(4+Math.sqrt(hradius+vradius)*3);
// [toxi031031] adapted to use new lookup tables
float inc = (float)SINCOS_LENGTH / accuracy;
float val = 0;
/*
beginShape(POLYGON);
for (int i = 0; i < cAccuracy; i++) {
vertex(centerX + cosLUT[(int) val] * hradius,
centerY + sinLUT[(int) val] * vradius);
val += inc;
}
endShape();
*/
if (fill) {
boolean savedStroke = stroke;
stroke = false;
beginShape(TRIANGLE_FAN);
normal(0, 0, 1);
vertex(centerX, centerY);
for (int i = 0; i < accuracy; i++) {
vertex(centerX + cosLUT[(int) val] * hradius,
centerY + sinLUT[(int) val] * vradius);
val += inc;
}
// back to the beginning
vertex(centerX + cosLUT[0] * hradius,
centerY + sinLUT[0] * vradius);
endShape();
stroke = savedStroke;
}
if (stroke) {
boolean savedFill = fill;
fill = false;
val = 0;
beginShape(LINE_LOOP);
for (int i = 0; i < accuracy; i++) {
vertex(centerX + cosLUT[(int) val] * hradius,
centerY + sinLUT[(int) val] * vradius);
val += inc;
}
endShape();
fill = savedFill;
}
}
@@ -1457,15 +1397,75 @@ public abstract class PGraphics extends PImage implements PConstants {
}
protected void arcImpl(float x, float y, float w, float h,
/**
* Start and stop are in radians, converted by the parent function.
* Note that the radians can be greater (or less) than TWO_PI.
* This is so that an arc can be drawn that crosses zero mark,
* and the user will still collect $200.
*/
protected void arcImpl(float x1, float y1, float w, float h,
float start, float stop) {
float hr = w / 2f;
float vr = h / 2f;
float centerX = x1 + hr;
float centerY = y1 + vr;
if (fill) {
// shut off stroke for a minute
boolean savedStroke = stroke;
stroke = false;
int startLUT = (int) (0.5f + (start / TWO_PI) * SINCOS_LENGTH);
int stopLUT = (int) (0.5f + (stop / TWO_PI) * SINCOS_LENGTH);
beginShape(TRIANGLE_FAN);
vertex(centerX, centerY);
int increment = 1; // what's a good algorithm? stopLUT - startLUT;
for (int i = startLUT; i < stopLUT; i += increment) {
int ii = i % SINCOS_LENGTH;
vertex(centerX + cosLUT[ii] * hr,
centerY + sinLUT[ii] * vr);
}
// draw last point explicitly for accuracy
vertex(centerX + cosLUT[stopLUT % SINCOS_LENGTH] * hr,
centerY + sinLUT[stopLUT % SINCOS_LENGTH] * vr);
endShape();
stroke = savedStroke;
}
if (stroke) {
// Almost identical to above, but this uses a LINE_STRIP
// and doesn't include the first (center) vertex.
boolean savedFill = fill;
fill = false;
int startLUT = (int) (0.5f + (start / TWO_PI) * SINCOS_LENGTH);
int stopLUT = (int) (0.5f + (stop / TWO_PI) * SINCOS_LENGTH);
beginShape(LINE_STRIP);
int increment = 1; // what's a good algorithm? stopLUT - startLUT;
for (int i = startLUT; i < stopLUT; i += increment) {
int ii = i % SINCOS_LENGTH;
vertex(centerX + cosLUT[ii] * hr,
centerY + sinLUT[ii] * vr);
}
// draw last point explicitly for accuracy
vertex(centerX + cosLUT[stopLUT % SINCOS_LENGTH] * hr,
centerY + sinLUT[stopLUT % SINCOS_LENGTH] * vr);
endShape();
fill = savedFill;
}
}
//////////////////////////////////////////////////////////////
// 3D SHAPES
// BOX & SPHERE
public void box(float size) {
@@ -1488,7 +1488,7 @@ public abstract class PGraphics extends PImage implements PConstants {
//////////////////////////////////////////////////////////////
// CURVES
// BEZIER
/**
@@ -1538,25 +1538,25 @@ public abstract class PGraphics extends PImage implements PConstants {
}
protected void bezier_init() {
protected void bezierInit() {
bezierDetail(bezierDetail);
}
public void bezierDetail(int detail) {
if (bezier_forward == null) {
bezier_forward = new float[4][4];
bezier_draw = new float[4][4];
if (bezierForwardMatrix == null) {
bezierForwardMatrix = new float[4][4];
bezierDrawMatrix = new float[4][4];
}
bezierDetail = detail;
bezierInited = true;
// setup matrix for forward differencing to speed up drawing
setup_spline_forward(detail, bezier_forward);
setup_spline_forward(detail, bezierForwardMatrix);
// multiply the basis and forward diff matrices together
// saves much time since this needn't be done for each curve
mult_spline_matrix(bezier_forward, bezier_basis, bezier_draw, 4);
mult_spline_matrix(bezierForwardMatrix, bezier_basis, bezierDrawMatrix, 4);
}
@@ -1598,12 +1598,20 @@ public abstract class PGraphics extends PImage implements PConstants {
float x2, float y2, float z2,
float x3, float y3, float z3,
float x4, float y4, float z4) {
depthErrorXYZ("bezier");
beginShape(LINE_STRIP);
vertex(x1, y1, z1);
bezierVertex(x2, y2, z2,
x3, y3, z3,
x4, y4, z4);
endShape();
}
//////////////////////////////////////////////////////////////
// CATMULL-ROM CURVE
/**
* Get a location along a catmull-rom curve segment.
@@ -1733,12 +1741,20 @@ public abstract class PGraphics extends PImage implements PConstants {
float x2, float y2, float z2,
float x3, float y3, float z3,
float x4, float y4, float z4) {
depthErrorXYZ("curve");
beginShape(LINE_STRIP);
curveVertex(x1, y1, z1);
curveVertex(x2, y2, z2);
curveVertex(x3, y3, z3);
curveVertex(x4, y4, z4);
endShape();
}
//////////////////////////////////////////////////////////////
// SPLINE UTILITY FUNCTIONS (used by both Bezier and Catmull-Rom)
/**
* Setup forward-differencing matrix to be used for speedy
@@ -1988,12 +2004,57 @@ public abstract class PGraphics extends PImage implements PConstants {
/**
* Expects x1, y1, x2, y2 coordinates where (x2 >= x1) and (y2 >= y1).
* If tint() has been called, the image will be colored.
* <p/>
* The default implementation draws an image as a textured quad.
* The (u, v) coordinates are in image space (they're ints, after all..)
*/
protected void imageImpl(PImage image,
float x1, float y1, float x2, float y2,
int u1, int v1, int u2, int v2) {
// TODO blit an image to the screen
System.err.println("unimplemented imageImpl() in PGraphics");
boolean savedStroke = stroke;
boolean savedFill = fill;
int savedTextureMode = textureMode;
stroke = false;
fill = true;
textureMode = IMAGE;
float savedFillR = fillR;
float savedFillG = fillG;
float savedFillB = fillB;
float savedFillA = fillA;
if (tint) {
fillR = tintR;
fillG = tintG;
fillB = tintB;
fillA = tintA;
} else {
fillR = 1;
fillG = 1;
fillB = 1;
fillA = 1;
}
//System.out.println(fill + " " + fillR + " " + fillG + " " + fillB);
beginShape(QUADS);
texture(image);
vertex(x1, y1, u1, v1);
vertex(x1, y2, u1, v2);
vertex(x2, y2, u2, v2);
vertex(x2, y1, u2, v1);
endShape();
stroke = savedStroke;
fill = savedFill;
textureMode = savedTextureMode;
fillR = savedFillR;
fillG = savedFillG;
fillB = savedFillB;
fillA = savedFillA;
}
@@ -2531,11 +2592,13 @@ public abstract class PGraphics extends PImage implements PConstants {
}
// ........................................................
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
// what was this for?
//font.getStringBounds(text, g2.getFontRenderContext()).getWidth();
protected void textCharImpl(char ch, float x, float y) { //, float z) {
int index = textFont.index(ch);
if (index == -1) return;

View File

@@ -47,7 +47,7 @@ public class PGraphics2D extends PGraphics {
PLine line;
boolean untransformed;
//boolean untransformed;
boolean strokeChanged = true;
boolean fillChanged = true;
@@ -217,7 +217,7 @@ public class PGraphics2D extends PGraphics {
int vertexCount = polygon.vertexCount;
float vertices[][] = polygon.vertices;
if (untransformed) {
if (untransformed()) {
for (int i = 0; i < vertexCount; i++) {
vertices[i][X] = vertices[i][MX];
vertices[i][Y] = vertices[i][MY];
@@ -255,7 +255,7 @@ public class PGraphics2D extends PGraphics {
switch (shape) {
case POINTS:
if (untransformed && (strokeWeight == 1)) {
if (untransformed() && (strokeWeight == 1)) {
if (!strokeChanged) {
for (int i = 0; i < vertexCount; i++) {
thin_point((int) vertices[i][X], (int) vertices[i][Y],
@@ -697,7 +697,7 @@ public class PGraphics2D extends PGraphics {
int x2 = (int) x2f;
int y2 = (int) y2f;
rectImplFillUnRGB(x1, y1, x2, y2);
rectImplFillUntranSolidRGB(x1, y1, x2, y2);
if (stroke) {
if (strokeWeight == 1) {
@@ -732,7 +732,7 @@ public class PGraphics2D extends PGraphics {
/**
* Draw an untransformed rectangle with no alpha.
*/
private void rectImplFillUnRGB(int x1, int y1, int x2, int y2) {
private void rectImplFillUntranSolidRGB(int x1, int y1, int x2, int y2) {
//System.out.println("flat quad");
if (y2 < y1) {
int temp = y1; y1 = y2; y2 = temp;
@@ -744,50 +744,409 @@ public class PGraphics2D extends PGraphics {
if ((x1 > width1) || (x2 < 0) ||
(y1 > height1) || (y2 < 0)) return;
if (fill) {
int fx1 = x1;
int fy1 = y1;
int fx2 = x2;
int fy2 = y2;
// these only affect the fill, not the stroke
// (otherwise strange boogers at edges b/c frame changes shape)
if (fx1 < 0) fx1 = 0;
if (fx2 > width) fx2 = width;
if (fy1 < 0) fy1 = 0;
if (fy2 > height) fy2 = height;
// [toxi 031223]
// on avg. 20-25% faster fill routine using System.arraycopy()
int ww = fx2 - fx1;
int hh = fy2 - fy1;
int[] row = new int[ww];
for (int i = 0; i < ww; i++) row[i] = fillColor;
int idx = fy1 * width + fx1;
for (int y = 0; y < hh; y++) {
System.arraycopy(row, 0, pixels, idx, ww);
idx += width;
}
row = null;
//if (fill) {
int fx1 = x1;
int fy1 = y1;
int fx2 = x2;
int fy2 = y2;
// these only affect the fill, not the stroke
// (otherwise strange boogers at edges b/c frame changes shape)
if (fx1 < 0) fx1 = 0;
if (fx2 > width) fx2 = width;
if (fy1 < 0) fy1 = 0;
if (fy2 > height) fy2 = height;
// [toxi 031223]
// on avg. 20-25% faster fill routine using System.arraycopy()
int ww = fx2 - fx1;
int hh = fy2 - fy1;
int[] row = new int[ww];
for (int i = 0; i < ww; i++) row[i] = fillColor;
int idx = fy1 * width + fx1;
for (int y = 0; y < hh; y++) {
System.arraycopy(row, 0, pixels, idx, ww);
idx += width;
}
row = null;
//}
}
//////////////////////////////////////////////////////////////
// RECT
// ELLIPSE AND ARC
public void ellipseImpl(float x1, float y1, float w, float h) {
if (!smooth && (strokeWeight == 1) &&
!fillAlpha && !strokeAlpha && untransformed()) {
float hradius = w / 2f;
float vradius = h / 2f;
int centerX = (int) (x1 + hradius);
int centerY = (int) (y1 + vradius);
if (hradius == vradius) {
flat_circle(centerX, centerY, (int)hradius);
} else {
flat_ellipse(centerX, centerY, (int)hradius, (int)vradius);
}
} else {
super.ellipseImpl(x1, y1, w, h);
}
}
private void flat_circle(int centerX, int centerY, int radius) {
if (unwarped()) {
float x = m00*centerX + m01*centerY + m02;
float y = m10*centerX + m11*centerY + m12;
centerX = (int)x;
centerY = (int)y;
}
if (fill) flat_circle_fill(centerX, centerY, radius);
if (stroke) flat_circle_stroke(centerX, centerY, radius);
}
/**
* Draw the outline around a flat circle using a bresenham-style
* algorithm. Adapted from drawCircle function in "Computer Graphics
* for Java Programmers" by Leen Ammeraal, p. 110.
* <P/>
* This function is included because the quality is so much better,
* and the drawing significantly faster than with adaptive ellipses
* drawn using the sine/cosine tables.
* <P/>
* Circle quadrants break down like so:
* <PRE>
* |
* \ NNW | NNE /
* \ | /
* WNW \ | / ENE
* -------------------
* WSW / | \ ESE
* / | \
* / SSW | SSE \
* |
* </PRE>
* @param xc x center
* @param yc y center
* @param r radius
*/
private void flat_circle_stroke(int xC, int yC, int r) {
int x = 0, y = r, u = 1, v = 2 * r - 1, E = 0;
while (x < y) {
thin_point(xC + x, yC + y, 0, strokeColor); // NNE
thin_point(xC + y, yC - x, 0, strokeColor); // ESE
thin_point(xC - x, yC - y, 0, strokeColor); // SSW
thin_point(xC - y, yC + x, 0, strokeColor); // WNW
x++; E += u; u += 2;
if (v < 2 * E) {
y--; E -= v; v -= 2;
}
if (x > y) break;
thin_point(xC + y, yC + x, 0, strokeColor); // ENE
thin_point(xC + x, yC - y, 0, strokeColor); // SSE
thin_point(xC - y, yC - x, 0, strokeColor); // WSW
thin_point(xC - x, yC + y, 0, strokeColor); // NNW
}
}
/**
* Heavily adapted version of the above algorithm that handles
* filling the ellipse. Works by drawing from the center and
* outwards to the points themselves. Has to be done this way
* because the values for the points are changed halfway through
* the function, making it impossible to just store a series of
* left and right edges to be drawn more quickly.
*
* @param xc x center
* @param yc y center
* @param r radius
*/
private void flat_circle_fill(int xc, int yc, int r) {
int x = 0, y = r, u = 1, v = 2 * r - 1, E = 0;
while (x < y) {
for (int xx = xc; xx < xc + x; xx++) { // NNE
thin_point(xx, yc + y, 0, fillColor);
}
for (int xx = xc; xx < xc + y; xx++) { // ESE
thin_point(xx, yc - x, 0, fillColor);
}
for (int xx = xc - x; xx < xc; xx++) { // SSW
thin_point(xx, yc - y, 0, fillColor);
}
for (int xx = xc - y; xx < xc; xx++) { // WNW
thin_point(xx, yc + x, 0, fillColor);
}
x++; E += u; u += 2;
if (v < 2 * E) {
y--; E -= v; v -= 2;
}
if (x > y) break;
for (int xx = xc; xx < xc + y; xx++) { // ENE
thin_point(xx, yc + x, 0, fillColor);
}
for (int xx = xc; xx < xc + x; xx++) { // SSE
thin_point(xx, yc - y, 0, fillColor);
}
for (int xx = xc - y; xx < xc; xx++) { // WSW
thin_point(xx, yc - x, 0, fillColor);
}
for (int xx = xc - x; xx < xc; xx++) { // NNW
thin_point(xx, yc + y, 0, fillColor);
}
}
}
// unfortunately this can't handle fill and stroke simultaneously,
// because the fill will later replace some of the stroke points
private final void flat_ellipse_symmetry(int centerX, int centerY,
int ellipseX, int ellipseY,
boolean filling) {
if (filling) {
for (int i = centerX - ellipseX + 1; i < centerX + ellipseX; i++) {
thin_point(i, centerY - ellipseY, 0, fillColor);
thin_point(i, centerY + ellipseY, 0, fillColor);
}
} else {
thin_point(centerX - ellipseX, centerY + ellipseY, 0, strokeColor);
thin_point(centerX + ellipseX, centerY + ellipseY, 0, strokeColor);
thin_point(centerX - ellipseX, centerY - ellipseY, 0, strokeColor);
thin_point(centerX + ellipseX, centerY - ellipseY, 0, strokeColor);
}
}
/**
* Bresenham-style ellipse drawing function, adapted from a posting to
* comp.graphics.algortihms.
*
* This function is included because the quality is so much better,
* and the drawing significantly faster than with adaptive ellipses
* drawn using the sine/cosine tables.
*
* @param centerX x coordinate of the center
* @param centerY y coordinate of the center
* @param a horizontal radius
* @param b vertical radius
*/
private void flat_ellipse_internal(int centerX, int centerY,
int a, int b, boolean filling) {
int x, y, a2, b2, s, t;
a2 = a*a;
b2 = b*b;
x = 0;
y = b;
s = a2*(1-2*b) + 2*b2;
t = b2 - 2*a2*(2*b-1);
flat_ellipse_symmetry(centerX, centerY, x, y, filling);
do {
if (s < 0) {
s += 2*b2*(2*x+3);
t += 4*b2*(x+1);
x++;
} else if (t < 0) {
s += 2*b2*(2*x+3) - 4*a2*(y-1);
t += 4*b2*(x+1) - 2*a2*(2*y-3);
x++;
y--;
} else {
s -= 4*a2*(y-1);
t -= 2*a2*(2*y-3);
y--;
}
flat_ellipse_symmetry(centerX, centerY, x, y, filling);
} while (y > 0);
}
private void flat_ellipse(int centerX, int centerY, int a, int b) {
if (unwarped()) {
float x = m00*centerX + m01*centerY + m02;
float y = m10*centerX + m11*centerY + m12;
centerX = (int)x;
centerY = (int)y;
}
if (fill) flat_ellipse_internal(centerX, centerY, a, b, true);
if (stroke) flat_ellipse_internal(centerX, centerY, a, b, false);
}
// TODO really need a decent arc function in here..
//protected void arcImpl(float x1, float y1, float w, float h,
// float start, float stop)
//////////////////////////////////////////////////////////////
// RENDERING
// BOX & SPHERE
// The PGraphics superclass will throw errors for these fellas
//////////////////////////////////////////////////////////////
// BEZIER & CURVE
public void bezier(float x1, float y1, float z1,
float x2, float y2, float z2,
float x3, float y3, float z3,
float x4, float y4, float z4) {
depthErrorXYZ("bezier");
}
public void curve(float x1, float y1, float z1,
float x2, float y2, float z2,
float x3, float y3, float z3,
float x4, float y4, float z4) {
depthErrorXYZ("curve");
}
//////////////////////////////////////////////////////////////
// IMAGE
protected void imageImpl(PImage image,
float x1, float y1, float x2, float y2,
int u1, int v1, int u2, int v2) {
if ((x2 - x1 == image.width) &&
(y2 - y1 == image.height) &&
!tint && unwarped()) {
flat_image(image, (int) (x1 + m02), (int) (y1 + m12), u1, v1, u2, v2);
} else {
super.imageImpl(image, x1, y1, x2, y2, u1, v1, u2, v2);
}
}
/**
* Image drawn in flat "screen space", with no scaling or warping.
* this is so common that a special routine is included for it,
* because the alternative is much slower.
*
* @param image image to be drawn
* @param sx1 x coordinate of upper-lefthand corner in screen space
* @param sy1 y coordinate of upper-lefthand corner in screen space
*/
private void flat_image(PImage image, int sx1, int sy1,
int ix1, int iy1, int ix2, int iy2) {
/*
int ix1 = 0;
int iy1 = 0;
int ix2 = image.width;
int iy2 = image.height;
*/
if (imageMode == CENTER) {
sx1 -= image.width / 2;
sy1 -= image.height / 2;
}
int sx2 = sx1 + image.width;
int sy2 = sy1 + image.height;
// don't draw if completely offscreen
// (without this check, ArrayIndexOutOfBoundsException)
if ((sx1 > width1) || (sx2 < 0) ||
(sy1 > height1) || (sy2 < 0)) return;
if (sx1 < 0) { // off left edge
ix1 -= sx1;
sx1 = 0;
}
if (sy1 < 0) { // off top edge
iy1 -= sy1;
sy1 = 0;
}
if (sx2 > width) { // off right edge
ix2 -= sx2 - width;
sx2 = width;
}
if (sy2 > height) { // off bottom edge
iy2 -= sy2 - height;
sy2 = height;
}
int source = iy1 * image.width + ix1;
int target = sy1 * width;
if (image.format == ARGB) {
for (int y = sy1; y < sy2; y++) {
int tx = 0;
for (int x = sx1; x < sx2; x++) {
pixels[target + x] =
_blend(pixels[target + x],
image.pixels[source + tx],
image.pixels[source + tx++] >>> 24);
}
source += image.width;
target += width;
}
} else if (image.format == ALPHA) {
for (int y = sy1; y < sy2; y++) {
int tx = 0;
for (int x = sx1; x < sx2; x++) {
pixels[target + x] =
_blend(pixels[target + x],
fillColor,
image.pixels[source + tx++]);
}
source += image.width;
target += width;
}
} else if (image.format == RGB) {
target += sx1;
int tw = sx2 - sx1;
for (int y = sy1; y < sy2; y++) {
System.arraycopy(image.pixels, source, pixels, target, tw);
// should set z coordinate in here
// or maybe not, since dims=0, meaning no relevant z
source += image.width;
target += width;
}
}
}
//////////////////////////////////////////////////////////////
// TEXT/FONTS
// These will be handled entirely by PGraphics.
//////////////////////////////////////////////////////////////
// expects properly clipped coords, hence does
// expects properly clipped coords, hence does
// NOT check if x/y are in bounds [toxi]
private void thin_pointAt(int x, int y, float z, int color) {
int index = y*width+x; // offset values are pre-calced in constructor
@@ -1158,7 +1517,7 @@ public class PGraphics2D extends PGraphics {
} else { // use old line code for thickness > 1
if ((strokeWeight < TWO) && !strokeChanged) {
if ((strokeWeight < 2) && !strokeChanged) {
// need to set color at least once?
// THIS PARTICULAR CASE SHOULD NO LONGER BE REACHABLE
@@ -1231,277 +1590,8 @@ public class PGraphics2D extends PGraphics {
zbuffer[index] = z;
}
private void flat_circle(int centerX, int centerY, int radius) {
if (translateNoScale()) {
centerX = (int) screenX(centerX, centerY, 0);
centerY = (int) screenY(centerX, centerY, 0);
}
if (fill) flat_circle_fill(centerX, centerY, radius);
if (stroke) flat_circle_stroke(centerX, centerY, radius);
}
/**
* Draw the outline around a flat circle using a bresenham-style
* algorithm. Adapted from drawCircle function in "Computer Graphics
* for Java Programmers" by Leen Ammeraal, p. 110
*
* This function is included because the quality is so much better,
* and the drawing significantly faster than with adaptive ellipses
* drawn using the sine/cosine tables.
*
* Circle quadrants break down like so:
* |
* \ NNW | NNE /
* \ | /
* WNW \ | / ENE
* -------------------
* WSW / | \ ESE
* / | \
* / SSW | SSE \
* |
*
* @param xc x center
* @param yc y center
* @param r radius
*/
private void flat_circle_stroke(int xC, int yC, int r) {
int x = 0, y = r, u = 1, v = 2 * r - 1, E = 0;
while (x < y) {
thin_point(xC + x, yC + y, 0, strokeColor); // NNE
thin_point(xC + y, yC - x, 0, strokeColor); // ESE
thin_point(xC - x, yC - y, 0, strokeColor); // SSW
thin_point(xC - y, yC + x, 0, strokeColor); // WNW
x++; E += u; u += 2;
if (v < 2 * E) {
y--; E -= v; v -= 2;
}
if (x > y) break;
thin_point(xC + y, yC + x, 0, strokeColor); // ENE
thin_point(xC + x, yC - y, 0, strokeColor); // SSE
thin_point(xC - y, yC - x, 0, strokeColor); // WSW
thin_point(xC - x, yC + y, 0, strokeColor); // NNW
}
}
/**
* Heavily adapted version of the above algorithm that handles
* filling the ellipse. Works by drawing from the center and
* outwards to the points themselves. Has to be done this way
* because the values for the points are changed halfway through
* the function, making it impossible to just store a series of
* left and right edges to be drawn more quickly.
*
* @param xc x center
* @param yc y center
* @param r radius
*/
private void flat_circle_fill(int xc, int yc, int r) {
int x = 0, y = r, u = 1, v = 2 * r - 1, E = 0;
while (x < y) {
for (int xx = xc; xx < xc + x; xx++) { // NNE
thin_point(xx, yc + y, 0, fillColor);
}
for (int xx = xc; xx < xc + y; xx++) { // ESE
thin_point(xx, yc - x, 0, fillColor);
}
for (int xx = xc - x; xx < xc; xx++) { // SSW
thin_point(xx, yc - y, 0, fillColor);
}
for (int xx = xc - y; xx < xc; xx++) { // WNW
thin_point(xx, yc + x, 0, fillColor);
}
x++; E += u; u += 2;
if (v < 2 * E) {
y--; E -= v; v -= 2;
}
if (x > y) break;
for (int xx = xc; xx < xc + y; xx++) { // ENE
thin_point(xx, yc + x, 0, fillColor);
}
for (int xx = xc; xx < xc + x; xx++) { // SSE
thin_point(xx, yc - y, 0, fillColor);
}
for (int xx = xc - y; xx < xc; xx++) { // WSW
thin_point(xx, yc - x, 0, fillColor);
}
for (int xx = xc - x; xx < xc; xx++) { // NNW
thin_point(xx, yc + y, 0, fillColor);
}
}
}
// unfortunately this can't handle fill and stroke simultaneously,
// because the fill will later replace some of the stroke points
private final void flat_ellipse_symmetry(int centerX, int centerY,
int ellipseX, int ellipseY,
boolean filling) {
if (filling) {
for (int i = centerX - ellipseX + 1; i < centerX + ellipseX; i++) {
thin_point(i, centerY - ellipseY, 0, fillColor);
thin_point(i, centerY + ellipseY, 0, fillColor);
}
} else {
thin_point(centerX - ellipseX, centerY + ellipseY, 0, strokeColor);
thin_point(centerX + ellipseX, centerY + ellipseY, 0, strokeColor);
thin_point(centerX - ellipseX, centerY - ellipseY, 0, strokeColor);
thin_point(centerX + ellipseX, centerY - ellipseY, 0, strokeColor);
}
}
/**
* Bresenham-style ellipse drawing function, adapted from a posting to
* comp.graphics.algortihms.
*
* This function is included because the quality is so much better,
* and the drawing significantly faster than with adaptive ellipses
* drawn using the sine/cosine tables.
*
* @param centerX x coordinate of the center
* @param centerY y coordinate of the center
* @param a horizontal radius
* @param b vertical radius
*/
private void flat_ellipse_internal(int centerX, int centerY,
int a, int b, boolean filling) {
int x, y, a2, b2, s, t;
a2 = a*a;
b2 = b*b;
x = 0;
y = b;
s = a2*(1-2*b) + 2*b2;
t = b2 - 2*a2*(2*b-1);
flat_ellipse_symmetry(centerX, centerY, x, y, filling);
do {
if (s < 0) {
s += 2*b2*(2*x+3);
t += 4*b2*(x+1);
x++;
} else if (t < 0) {
s += 2*b2*(2*x+3) - 4*a2*(y-1);
t += 4*b2*(x+1) - 2*a2*(2*y-3);
x++;
y--;
} else {
s -= 4*a2*(y-1);
t -= 2*a2*(2*y-3);
y--;
}
flat_ellipse_symmetry(centerX, centerY, x, y, filling);
} while (y > 0);
}
private void flat_ellipse(int centerX, int centerY, int a, int b) {
if (translateNoScale()) {
centerX = (int) screenX(centerX, centerY, 0);
centerY = (int) screenY(centerX, centerY, 0);
}
if (fill) flat_ellipse_internal(centerX, centerY, a, b, true);
if (stroke) flat_ellipse_internal(centerX, centerY, a, b, false);
}
/**
* Image drawn in flat "screen space", with no scaling or warping.
* this is so common that a special routine is included for it,
* because the alternative is much slower.
*
* @param image image to be drawn
* @param sx1 x coordinate of upper-lefthand corner in screen space
* @param sy1 y coordinate of upper-lefthand corner in screen space
*/
public void flat_image(PImage image, int sx1, int sy1) {
int ix1 = 0;
int iy1 = 0;
int ix2 = image.width;
int iy2 = image.height;
if (imageMode == CENTER) {
sx1 -= image.width / 2;
sy1 -= image.height / 2;
}
int sx2 = sx1 + image.width;
int sy2 = sy1 + image.height;
// don't draw if completely offscreen
// (without this check, ArrayIndexOutOfBoundsException)
if ((sx1 > width1) || (sx2 < 0) ||
(sy1 > height1) || (sy2 < 0)) return;
if (sx1 < 0) { // off left edge
ix1 -= sx1;
sx1 = 0;
}
if (sy1 < 0) { // off top edge
iy1 -= sy1;
sy1 = 0;
}
if (sx2 > width) { // off right edge
ix2 -= sx2 - width;
sx2 = width;
}
if (sy2 > height) { // off bottom edge
iy2 -= sy2 - height;
sy2 = height;
}
int source = iy1 * image.width + ix1;
int target = sy1 * width;
if (image.format == ARGB) {
for (int y = sy1; y < sy2; y++) {
int tx = 0;
for (int x = sx1; x < sx2; x++) {
pixels[target + x] =
_blend(pixels[target + x],
image.pixels[source + tx],
image.pixels[source + tx++] >>> 24);
}
source += image.width;
target += width;
}
} else if (image.format == ALPHA) {
for (int y = sy1; y < sy2; y++) {
int tx = 0;
for (int x = sx1; x < sx2; x++) {
pixels[target + x] =
_blend(pixels[target + x],
fillColor,
image.pixels[source + tx++]);
}
source += image.width;
target += width;
}
} else if (image.format == RGB) {
target += sx1;
int tw = sx2 - sx1;
for (int y = sy1; y < sy2; y++) {
System.arraycopy(image.pixels, source, pixels, target, tw);
// should set z coordinate in here
// or maybe not, since dims=0, meaning no relevant z
source += image.width;
target += width;
}
}
}
//////////////////////////////////////////////////////////////
// INTERNAL SCHIZZLE
@@ -1512,7 +1602,8 @@ public class PGraphics2D extends PGraphics {
(m10 == 0) && (m11 == 1) && (m12 == 0));
}
private boolean translateNoScale() {
private boolean unwarped() {
return ((m00 == 1) && (m01 == 0) && (m10 == 0) && (m11 == 1));
}

View File

@@ -2105,20 +2105,9 @@ public class PGraphics3D extends PGraphics {
*/
public void line(float x1, float y1, float x2, float y2) {
line(x1, y1, 0, x2, y2, 0);
}
public void line(float x1, float y1, float z1,
float x2, float y2, float z2) {
beginShape(LINES);
vertex(x1, y1, z1);
vertex(x2, y2, z2);
endShape();
}
/**
* Compared to the implementation in PGraphics, this adds normal().
*/
public void triangle(float x1, float y1, float x2, float y2,
float x3, float y3) {
beginShape(TRIANGLES);
@@ -2130,6 +2119,9 @@ public class PGraphics3D extends PGraphics {
}
/**
* Compared to the implementation in PGraphics, this adds normal().
*/
public void quad(float x1, float y1, float x2, float y2,
float x3, float y3, float x4, float y4) {
beginShape(QUADS);
@@ -2145,156 +2137,7 @@ public class PGraphics3D extends PGraphics {
//////////////////////////////////////////////////////////////
// PLACED SHAPES
protected void rectImpl(float x1, float y1, float x2, float y2) {
quad(x1, y1, x2, y1, x2, y2, x1, y2);
}
protected void ellipseImpl(float x1, float y1, float w, float h) {
float hradius = w / 2f;
float vradius = h / 2f;
float centerX = x1 + hradius;
float centerY = y1 + vradius;
// adapt accuracy to radii used w/ a minimum of 4 segments [toxi]
// now uses current scale factors to determine "real" transformed radius
//int cAccuracy = (int)(4+Math.sqrt(hradius*abs(m00)+vradius*abs(m11))*2);
//int cAccuracy = (int)(4+Math.sqrt(hradius+vradius)*2);
// notched this up to *3 instead of *2 because things were
// looking a little rough, i.e. the calculate->arctangent example [fry]
// also removed the m00 and m11 because those were causing weirdness
// need an actual measure of magnitude in there [fry]
int cAccuracy = (int)(4+Math.sqrt(hradius+vradius)*3);
// [toxi031031] adapted to use new lookup tables
float inc = (float)SINCOS_LENGTH / cAccuracy;
float val = 0;
/*
beginShape(POLYGON);
for (int i = 0; i < cAccuracy; i++) {
vertex(centerX + cosLUT[(int) val] * hradius,
centerY + sinLUT[(int) val] * vradius);
val += inc;
}
endShape();
*/
if (fill) {
boolean savedStroke = stroke;
stroke = false;
beginShape(TRIANGLE_FAN);
normal(0, 0, 1);
vertex(centerX, centerY);
for (int i = 0; i < cAccuracy; i++) {
vertex(centerX + cosLUT[(int) val] * hradius,
centerY + sinLUT[(int) val] * vradius);
val += inc;
}
// back to the beginning
vertex(centerX + cosLUT[0] * hradius,
centerY + sinLUT[0] * vradius);
endShape();
stroke = savedStroke;
}
if (stroke) {
boolean savedFill = fill;
fill = false;
val = 0;
beginShape(LINE_LOOP);
for (int i = 0; i < cAccuracy; i++) {
vertex(centerX + cosLUT[(int) val] * hradius,
centerY + sinLUT[(int) val] * vradius);
val += inc;
}
endShape();
fill = savedFill;
}
}
/**
* Start and stop are in radians, converted by the parent function.
* Note that the radians can be greater (or less) than TWO_PI.
* This is so that an arc can be drawn that crosses zero mark,
* and the user will still collect $200.
*/
protected void arcImpl(float x1, float y1, float w, float h,
float start, float stop) {
float hr = w / 2f;
float vr = h / 2f;
float centerX = x1 + hr;
float centerY = y1 + vr;
if (fill) {
// shut off stroke for a minute
boolean savedStroke = stroke;
stroke = false;
int startLUT = (int) (0.5f + (start / TWO_PI) * SINCOS_LENGTH);
int stopLUT = (int) (0.5f + (stop / TWO_PI) * SINCOS_LENGTH);
beginShape(TRIANGLE_FAN);
vertex(centerX, centerY);
int increment = 1; // what's a good algorithm? stopLUT - startLUT;
for (int i = startLUT; i < stopLUT; i += increment) {
int ii = i % SINCOS_LENGTH;
vertex(centerX + cosLUT[ii] * hr,
centerY + sinLUT[ii] * vr);
}
// draw last point explicitly for accuracy
vertex(centerX + cosLUT[stopLUT % SINCOS_LENGTH] * hr,
centerY + sinLUT[stopLUT % SINCOS_LENGTH] * vr);
endShape();
stroke = savedStroke;
}
if (stroke) {
// Almost identical to above, but this uses a LINE_STRIP
// and doesn't include the first (center) vertex.
boolean savedFill = fill;
fill = false;
int startLUT = (int) (0.5f + (start / TWO_PI) * SINCOS_LENGTH);
int stopLUT = (int) (0.5f + (stop / TWO_PI) * SINCOS_LENGTH);
beginShape(LINE_STRIP);
int increment = 1; // what's a good algorithm? stopLUT - startLUT;
for (int i = startLUT; i < stopLUT; i += increment) {
int ii = i % SINCOS_LENGTH;
vertex(centerX + cosLUT[ii] * hr,
centerY + sinLUT[ii] * vr);
}
// draw last point explicitly for accuracy
vertex(centerX + cosLUT[stopLUT % SINCOS_LENGTH] * hr,
centerY + sinLUT[stopLUT % SINCOS_LENGTH] * vr);
endShape();
fill = savedFill;
}
}
//////////////////////////////////////////////////////////////
// 3D BOX
// BOX
public void box(float size) {
@@ -2369,7 +2212,7 @@ public class PGraphics3D extends PGraphics {
//////////////////////////////////////////////////////////////
// 3D SPHERE
// SPHERE
// [toxi031031] used by the new sphere code below
@@ -2517,6 +2360,7 @@ public class PGraphics3D extends PGraphics {
// CURVES
/*
public void bezier(float x1, float y1,
float x2, float y2,
@@ -2564,63 +2408,8 @@ public class PGraphics3D extends PGraphics {
curveVertex(x4, y4, z4);
endShape();
}
//////////////////////////////////////////////////////////////
protected void imageImpl(PImage image,
float x1, float y1, float x2, float y2,
int u1, int v1, int u2, int v2) {
//float x2 = x1 + w;
//float y2 = y1 + h;
boolean savedStroke = stroke;
boolean savedFill = fill;
int savedTextureMode = textureMode;
stroke = false;
fill = true;
textureMode = IMAGE;
float savedFillR = fillR;
float savedFillG = fillG;
float savedFillB = fillB;
float savedFillA = fillA;
if (tint) {
fillR = tintR;
fillG = tintG;
fillB = tintB;
fillA = tintA;
} else {
fillR = 1;
fillG = 1;
fillB = 1;
fillA = 1;
}
//System.out.println(fill + " " + fillR + " " + fillG + " " + fillB);
beginShape(QUADS);
texture(image);
vertex(x1, y1, u1, v1);
vertex(x1, y2, u1, v2);
vertex(x2, y2, u2, v2);
vertex(x2, y1, u2, v1);
endShape();
stroke = savedStroke;
fill = savedFill;
textureMode = savedTextureMode;
fillR = savedFillR;
fillG = savedFillG;
fillB = savedFillB;
fillA = savedFillA;
}
*/
@@ -3782,7 +3571,7 @@ public class PGraphics3D extends PGraphics {
super.background(image);
for (int i = 0; i < pixelCount; i++) {
zbuffer[i] = MAX_FLOAT;
zbuffer[i] = Float.MAX_VALUE;
stencil[i] = 0;
}
}
@@ -3798,7 +3587,7 @@ public class PGraphics3D extends PGraphics {
// PApplet.hex(backgroundColor) + ")");
for (int i = 0; i < pixelCount; i++) {
pixels[i] = backgroundColor;
zbuffer[i] = MAX_FLOAT;
zbuffer[i] = Float.MAX_VALUE;
stencil[i] = 0;
}
}

View File

@@ -644,7 +644,7 @@ public class PPolygon implements PConstants {
float p[], float dp[], int y) {
float delta = p2[Y] - p1[Y];
if (delta == 0) delta = ONE;
float fraction = y + HALF - p1[Y];
float fraction = y + 0.5f - p1[Y];
if (interpX) {
dp[X] = (p2[X] - p1[X]) / delta;
@@ -687,7 +687,7 @@ public class PPolygon implements PConstants {
float p[], float dp[], int x) {
float delta = p2[X] - p1[X];
if (delta == 0) delta = ONE;
float fraction = x + HALF - p1[X];
float fraction = x + 0.5f - p1[X];
if (smooth) {
delta /= SUBXRES;
fraction /= SUBXRES;