From 3e7158145c3c04d2c1b9ecb9c7df9e3f01ac8a58 Mon Sep 17 00:00:00 2001 From: benfry Date: Wed, 19 Jul 2006 00:55:11 +0000 Subject: [PATCH] on the road to hell --- core/src/processing/core/PConstants.java | 4 - core/src/processing/core/PGraphics.java | 387 +++++++----- core/src/processing/core/PGraphics2D.java | 701 ++++++++++++---------- core/src/processing/core/PGraphics3D.java | 237 +------- core/src/processing/core/PPolygon.java | 4 +- 5 files changed, 636 insertions(+), 697 deletions(-) diff --git a/core/src/processing/core/PConstants.java b/core/src/processing/core/PConstants.java index 641b1285b..5bf963fc8 100644 --- a/core/src/processing/core/PConstants.java +++ b/core/src/processing/core/PConstants.java @@ -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 diff --git a/core/src/processing/core/PGraphics.java b/core/src/processing/core/PGraphics.java index 9141f4903..4253abbcb 100644 --- a/core/src/processing/core/PGraphics.java +++ b/core/src/processing/core/PGraphics.java @@ -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. + *

+ * 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; diff --git a/core/src/processing/core/PGraphics2D.java b/core/src/processing/core/PGraphics2D.java index 79bc93cb6..dd6613277 100644 --- a/core/src/processing/core/PGraphics2D.java +++ b/core/src/processing/core/PGraphics2D.java @@ -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. + *

+ * 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 (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)); } diff --git a/core/src/processing/core/PGraphics3D.java b/core/src/processing/core/PGraphics3D.java index bfce112d1..fe5869b8f 100644 --- a/core/src/processing/core/PGraphics3D.java +++ b/core/src/processing/core/PGraphics3D.java @@ -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; } } diff --git a/core/src/processing/core/PPolygon.java b/core/src/processing/core/PPolygon.java index 4f4ab8fb1..499bae713 100644 --- a/core/src/processing/core/PPolygon.java +++ b/core/src/processing/core/PPolygon.java @@ -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;