diff --git a/processing/core/PGraphics.java b/processing/core/PGraphics.java index eba1aacf2..5dbbae756 100644 --- a/processing/core/PGraphics.java +++ b/processing/core/PGraphics.java @@ -1373,6 +1373,15 @@ public class PGraphics extends PImage implements PConstants { // this probably needs to be broken into affine/non-affine versions // since affine w/ smoothing is a fairly easy case to handle and // with better quality and speed than using the full texture mapping. + + /** + * u, v coordinates are always of the form x1, y1, x2, y2, or the + * same as imageMode(CORNERS), even if the imageMode is something else. + * + * when drawing without depth(), the coordinates for u, v are + * always done in IMAGE_SPACE, because the textureMode() option + * is not available in 2D. + */ public void image(PImage image, float x1, float y1, float x2, float y2, float u1, float v1, float u2, float v2) { diff --git a/processing/core/PGraphics2.java b/processing/core/PGraphics2.java index d565ca9cf..53794d12d 100644 --- a/processing/core/PGraphics2.java +++ b/processing/core/PGraphics2.java @@ -44,6 +44,10 @@ public class PGraphics2 extends PGraphics { new AffineTransform[MATRIX_STACK_DEPTH]; double transform[] = new double[6]; + Elipse2D.Float ellipse = new Ellipse2D.Float(); + Rectangle2D.Float rect = new Rectangle2D.Float(); + Arc2D.Float arc = new Arc2D.Float(); + ////////////////////////////////////////////////////////////// @@ -142,6 +146,10 @@ public class PGraphics2 extends PGraphics { case POINTS: { + for (int i = 0; i < vertexCount; i++) { + + point(vertices[i][VX], vertices[i][VY]); + } stop = vertex_end; for (int i = vertex_start; i < stop; i++) { add_path(); // total overkill for points @@ -372,9 +380,22 @@ public class PGraphics2 extends PGraphics { // SHAPES + protected void draw_shape(Shape s) { + if (fill) { + graphics.setColor(fillColorObject); + graphics.fill(s); + } + if (stroke) { + graphics.setColor(strokeColorObject); + graphics.draw(s); + } + } + + public void point(float x, float y) { - graphics.setColor(strokeColorObject); - graphics.drawLine(x1, y1, x2, y2); + //graphics.setColor(strokeColorObject); + //graphics.drawLine(x1, y1, x2, y2); + line(x, y, x, y); } @@ -386,68 +407,100 @@ public class PGraphics2 extends PGraphics { public void triangle(float x1, float y1, float x2, float y2, float x3, float y3) { - // TODO + GeneralPath gp = new GeneralPath(); + gp.moveTo(x1, y1); + gp.lineTo(x2, y2); + gp.lineTo(x3, y3); + gp.closePath(); + + draw_shape(gp); } public void rect(float x1, float y1, float x2, float y2) { - if (fill) { - graphics.setColor(fillColorObject); - graphics.fillRect(x1, y1, x2, y2); - } - if (stroke) { - graphics.setColor(strokeColorObject); - graphics.drawRect(x1, y1, x2, y2); + switch (rectMode) { + case CORNERS: + rect.setFrameFromDiagonal(x1, y1, x2, y2); + break; + case CORNER: + rect.setFrame(x1, y1, x2, y2); + break; + case CENTER_RADIUS: + rect.setFrame(x1 - x2, y1 - y2, x1 + x2, y1 + y2); + break; + case CENTER: + rect.setFrame(x1 - x2/2.0f, y1 - y2/2.0f, x1 + x2/2.0f, y1 + y2/2.0f); + break; } + draw_shape(rect); } public void quad(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) { + GeneralPath gp = new GeneralPath(); + gp.moveTo(x1, y1); + gp.lineTo(x2, y2); + gp.lineTo(x3, y3); + gp.lineTo(x4, y4); + gp.closePath(); + draw_shape(gp); } - public void image(PImage image, float x1, float y1) { - } - - public void image(PImage image, - float x1, float y1, float x2, float y2) { - } - - public void image(PImage image, - float x1, float y1, float x2, float y2, - float u1, float v1, float u2, float v2) { - } - - //public void cache(PImage image) { - //} - - //public void cache(PImage images[]) { - //} - - //public void arcMode(int mode) { - //} public void arc(float start, float stop, float x, float y, float radius) { + arc(start, stop, x, y, radius, radius); } + public void arc(float start, float stop, - float x, float y, float hr, float vr) { + float x, float y, float w, float h) { + if (arcMode == CORNERS) { + w -= x; + h -= y; + + } else if (arcMode == CENTER_RADIUS) { + x -= w; + y -= h; + w *= 2; + h *= 2; + + } else if (arcMode == CENTER) { + x -= w; + y -= h; + } + + arc.setArc(x, y, w, h, start, stop-start, Arc2D.PIE); + draw_shape(arc); } + public void ellipse(float x, float y, float hradius, float vradius) { + ellipse.setFrame(x, y, hradius, vradius); + draw_shape(ellipse); } + public void circle(float x, float y, float radius) { + ellipse(x, y, radius, radius); } + public void bezier(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) { + GeneralPath gp = new GeneralPath(); + gp.moveTo(x1, y1); + gp.quadTo(x2, y2, x3, y3, x4, y4); + gp.closePath(); + + draw_shape(gp); } + public void bezierDetail(int detail) { // ignored in java2d } @@ -456,18 +509,91 @@ public class PGraphics2 extends PGraphics { // ignored in java2d } + public void curveTightness(float tightness) { // TODO } + public void curve(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) { - // TODO + // TODO need inverse catmull rom to bezier matrix } + ////////////////////////////////////////////////////////////// + + // IMAGES + + + public void image(PImage image, float x1, float y1) { + image(image, x1, y1, image.width, image.height); + } + + + public void image(PImage image, + float x1, float y1, float x2, float y2) { + if (imageMode == CORNER) { + x2 += x1; // x2 is width, need to add x1 + y2 += y1; + + } else if ((imageMode == CENTER) || + (imageMode == CENTER_RADIUS)) { + x1 -= image.width /2f; + y1 -= image.height / 2f; + } + check_image_cache(); + graphics.drawImage((Image) image.cache, x1, y1, x2, y2, null); + } + + + public void image(PImage image, + float x1, float y1, float x2, float y2, + float u1, float v1, float u2, float v2) { + if (imageMode == CORNER) { + x2 += x1; // x2 is width, need to add x1 + y2 += y1; + + } else if ((imageMode == CENTER) || + (imageMode == CENTER_RADIUS)) { + x1 -= image.width /2f; + y1 -= image.height / 2f; + } + check_image_cache(); + graphics.drawImage((Image) image.cache, + (int)x1, (int)y1, (int)x2, (int)y2, + (int)u1, (int)v1, (int)u2, (int)v2, + null); + } + + + protected void check_image_cache(PImage what) { + if (image.cache == null) { + cache = new BufferedImage(image.width, image.height, + BufferedImage.TYPE_INT_ARGB); + image.modified(); // mark the whole thing for update + } + + if (image.modified) { + // update the sub-portion of the image as necessary + BufferedImage bi = (BufferedImage) image.cache; + + bi.setRGB(image.mx1, image.my1, + image.mx2 - image.mx1 + 1, + image.my2 - image.my1 + 1, + image.pixels, + image.my1*image.width + image.mx1, // offset for copy + image.width); // scan size + image.resetModified(); + } + } + + + ////////////////////////////////////////////////////////////// + + /* public void textFont(PFont which); @@ -503,7 +629,6 @@ public class PGraphics2 extends PGraphics { */ - ////////////////////////////////////////////////////////////// // MATRIX @@ -645,7 +770,7 @@ public class PGraphics2 extends PGraphics { protected void calc_tint() { super.calc_tint(); - // ??? how to do this + // TODO actually implement tinted images tintColorObject = new Color(tintColor); } @@ -662,18 +787,6 @@ public class PGraphics2 extends PGraphics { } - /* - public void noTint() { - } - - public void noFill() { - } - - public void noStroke() { - } - */ - - public void background(PImage image) { if ((image.width != width) || (image.height != height)) { die("background image must be the same size " + @@ -683,8 +796,10 @@ public class PGraphics2 extends PGraphics { die("background images should be RGB or ARGB"); } + // make sure it's been properly updated + check_image_cache(image); + // blit image to the screen - //System.arraycopy(image.pixels, 0, pixels, 0, pixels.length); graphics.drawImage((BufferedImage) image.cache, 0, 0); } @@ -709,11 +824,11 @@ public class PGraphics2 extends PGraphics { public void alpha(int alpha[]) { - // TODO + // does nothing in PGraphics } public void alpha(PImage alpha) { - // TODO + // does nothing in PGraphics } public void filter(int kind) { @@ -784,13 +899,27 @@ public class PGraphics2 extends PGraphics { } + /** + * This is used to both set the pixels[] array so that it can be + * manipulated, and it also returns a PImage object that can be + * messed with directly. + */ public PImage get() { - // TODO + //PImage outgoing = new PImage(width, height); + // int[] getRGB(int startX, int startY, int w, int h, + // int[] rgbArray, int offset, int scansize) + if (pixels == null) { + pixels = new int[width * height]; + } + image.getRGB(0, 0, width, height, pixels, 0, width); + return new PImage(pixels, width, height, RGB); } public void save(String filename) { - // TODO + //static boolean write(RenderedImage im, String formatName, File output) + // maybe use ImageIO.save(File file) here if it's available? + get().save(filename); } @@ -804,4 +933,4 @@ public class PGraphics2 extends PGraphics { graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); } -} \ No newline at end of file +} diff --git a/processing/core/PImage.java b/processing/core/PImage.java index bf65f6c35..bc568872d 100644 --- a/processing/core/PImage.java +++ b/processing/core/PImage.java @@ -84,9 +84,13 @@ public class PImage implements PConstants, Cloneable { public int imageMode = CORNER; public boolean smooth = false; - /** for gl subclass / hardware accel */ + /** for subclasses that need to store info about the image */ public Object cache; + /** modified portion of the image */ + public boolean modified; + public int mx1, my1, mx2, my2; + // private fields private int fracU, ifU, fracV, ifV, u1, u2, v1, v2, sX, sY, iw, iw1, ih1; private int ul, ll, ur, lr, cUL, cLL, cUR, cLR; @@ -175,6 +179,44 @@ public class PImage implements PConstants, Cloneable { } + public void modified() { + mx1 = 0; + my1 = 0; + mx2 = width; + my2 = height; + modified = true; + } + + public void modified(int x, int y) { + if (x < mx1) mx1 = x; + if (x > mx2) mx2 = x; + if (y < my1) my1 = y; + if (y > my2) my2 = y; + modified = true; + } + + public void modified(int x1, int y1, int x2, int y2) { + if (x1 < mx1) mx1 = x1; + if (x1 > mx2) mx2 = x1; + if (y1 < my1) my1 = y1; + if (y1 > my2) my2 = y1; + + if (x2 < mx1) mx1 = x2; + if (x2 > mx2) mx2 = x2; + if (y2 < my1) my1 = y2; + if (y2 > my2) my2 = y2; + + modified = true; + } + + public void resetModified() { + mx1 = -Integer.MAX_VALUE; + my1 = -Integer.MAX_VALUE; + mx2 = Integer.MAX_VALUE; + my2 = Integer.MAX_VALUE; + } + + /** * Set alpha channel for an image. */