diff --git a/build/shared/revisions.txt b/build/shared/revisions.txt index 320f4a7d6..0581a5e77 100644 --- a/build/shared/revisions.txt +++ b/build/shared/revisions.txt @@ -9,17 +9,57 @@ releases will be super crusty. ABOUT REV 0116 - ?? ?? 2006 -+ the flag in PApplet.main() formerly called --present-stop-color +This is a major release. It contains a large number of bug fixes, +as well as several API changes as we try to firm up the API for 1.0. + + *** PLEASE READ ALL THESE NOTES CAREFULLY *** + ++ Threading has been modified signficantly. + ++ The OpenGL library has been updated to use the "final" release + of JOGL 1.0, released September 2006, rather than beta 4, found + in release 0115. + ++ The flag in PApplet.main() formerly called --present-stop-color is now simply --stop-color. A flag named --hide-stop has also been added, to prevent users from quitting out of a present mode application. see the faq on details for capturing ESC as well. -+ altered mouse behavior so that mouse positions update only on ++ Altered mouse behavior so that mouse positions update only on mouseMoved and mouseDragged. this also fixes a macosx bug that caused mouseX/Y values to be bizarre because mouseExited() gave weird positions (workaround for apple bug). +[ Major changes to the use of PGraphics and its subclasses ] + ++ The PGraphics classes have all been reworked and renamed. + + - PGraphics is an abstract class on which additional PGraphics + subclasses can be built. It is an abstract class, and therefore + cannot be invoked directly. + + - PGraphics2D (P2D) contains the former contents of PGraphics that + are specific to 2D rendering. This will be P2D once it is complete. + + - PGraphics3D (P3D), formerly PGraphics3, remains mostly unchanged. + + - PGraphicsJava2D (JAVA2D), formerly PGraphics2, is the renderer + used when you call for size(width, height, JAVA2D). It remains + the default renderer when none is specified. It is slower but + more accurate than the others. + ++ Do not use new PGraphics(...) to create PGraphics objects. + Instead, use createGraphics(), which will properly handle connecting + the new graphics object to its parent sketch, and will enable save() + to work properly. See the reference for createGraphics: + http://processing.org/reference/createGraphics_.html + ++ For the same reasons as above, createImage(width, height, format) + should be used instead of new PImage(...) when creating images: + http://test.processing.org/reference/createImage_.html + + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . diff --git a/core/src/processing/core/PApplet.java b/core/src/processing/core/PApplet.java index a1f9cb8a5..13bf8b9f3 100644 --- a/core/src/processing/core/PApplet.java +++ b/core/src/processing/core/PApplet.java @@ -38,6 +38,78 @@ import java.util.zip.*; /** * Base class for all sketches that use processing.core. + *

+ * Note that you should not use AWT or Swing components inside a Processing + * applet. The surface is made to automatically update itself, and will cause + * problems with redraw of components drawn above it. If you'd like to + * integrate other Java components, see below. + *

+ * This class extends Applet instead of JApplet because 1) we will eventually + * be returning Java 1.1 support, which does not include Swing (without an + * additional, sizable, download), and 2) Swing is a bloated piece of crap. + * A Processing applet is a heavyweight AWT component, and can be used the + * same as any other AWT component. + *

+ * Similarly, Processing runs in a Frame and not a JFrame. However, there's + * nothing to prevent you from embedding a PApplet into a JFrame, it's just + * that the base version uses a regular AWT frame because there's simply + * no need for swing in that context. If people want to use Swing, they can + * embed themselves as they wish. + *

+ * It is possible to use PApplet, along with core.jar in other projects. + * In addition to enabling you to use Java 1.5+ features with your sketch, + * this also allows you to embed a Processing drawing area into another Java + * application. This means you can use standard GUI controls with a Processing + * sketch. Because AWT and Swing GUI components cannot be used on top of a + * PApplet, you can instead embed the Component inside another GUI the way + * you would any other Component. + *

+ * By default, the animation thread will run at 60 frames per second, + * which can make the parent applet sluggish. If you want to only update the + * sketch intermittently, use noLoop() inside setup(), and redraw() whenever + * the screen needs to be updated once, or loop() to re-enable the animation + * thread. The following example embeds a sketch and also uses the noLoop() + * and redraw() methods. You need not use noLoop() and redraw() when embedding + * if you want your application to animate continuously. + *

+ * public class ExampleFrame extends Frame {
+ *
+ *     public ExampleFrame() {
+ *         super("Embedded PApplet");
+ *
+ *         setLayout(new BorderLayout());
+ *         PApplet embed = new Embedded();
+ *         add(embed, BorderLayout.CENTER);
+ *
+ *         // important to call this whenever embedding a PApplet.
+ *         // It ensures that the animation thread is started and
+ *         // that other internal variables are properly set.
+ *         embed.init();
+ *     }
+ * }
+ *
+ * public class Embedded extends PApplet {
+ *
+ *     public void setup() {
+ *         // original setup code here ...
+ *         size(400, 400);
+ *
+ *         // prevent thread from starving everything else
+ *         noLoop();
+ *     }
+ *
+ *     public void draw() {
+ *         // drawing code goes here
+ *     }
+ *
+ *     public void mousePressed() {
+ *         // do something based on mouse movement
+ *
+ *         // update the screen (run draw once)
+ *         redraw();
+ *     }
+ * }
+ * 
*/ public class PApplet extends Applet implements PConstants, Runnable, @@ -797,6 +869,7 @@ public class PApplet extends Applet // otherwise ok to fall through and create renderer below // the renderer is changing, so need to create a new object g = createGraphics(iwidth, iheight, irenderer, ipath); + g.setMainDrawingSurface(); //if (g != null) { updateSize(iwidth, iheight); //} @@ -809,6 +882,7 @@ public class PApplet extends Applet } } else { // none exists, just create a freshy g = createGraphics(iwidth, iheight, irenderer, ipath); + g.setMainDrawingSurface(); updateSize(iwidth, iheight); } @@ -864,6 +938,9 @@ public class PApplet extends Applet /* + // these constructors removed because they were silly + + public PGraphics createGraphics(String renderer) { return createGraphics(width, height, renderer); } @@ -872,29 +949,29 @@ public class PApplet extends Applet public PGraphics createGraphics(int iwidth, int iheight) { return createGraphics(iwidth, iheight, g.getClass().getName()); } - */ public PGraphics createGraphics(String irenderer, String ipath) { return createGraphics(width, height, irenderer, this, ipath); } + */ public PGraphics createGraphics(int iwidth, int iheight, String irenderer) { - return createGraphics(iwidth, iheight, irenderer, this, null); + return createGraphics(iwidth, iheight, irenderer, null, this); } public PGraphics createGraphics(int iwidth, int iheight, String irenderer, String ipath) { - return createGraphics(iwidth, iheight, irenderer, this, ipath); + return createGraphics(iwidth, iheight, irenderer, ipath, this); } static public PGraphics createGraphics(int iwidth, int iheight, - String irenderer, PApplet applet, - String ipath) { + String irenderer, String ipath, + PApplet applet) { /* // ok when calling size, but not really with createGraphics() if (renderer.equals(OPENGL)) { @@ -933,9 +1010,8 @@ public class PApplet extends Applet Constructor constructor = rendererClass.getConstructor(constructorParams); - // create the actual PGraphics object for rendering - return (PGraphics) constructor.newInstance(constructorValues); - //updateSize(iwidth, iheight); + PGraphics pg = (PGraphics) constructor.newInstance(constructorValues); + return pg; } catch (InvocationTargetException ite) { String msg = ite.getTargetException().getMessage(); @@ -977,28 +1053,23 @@ public class PApplet extends Applet } else { if (platform == MACOSX) e.printStackTrace(System.out); - //System.err.flush(); - //return null; throw new RuntimeException(e.getMessage()); - //die("Could not create " + irenderer); } - - /* - } catch (Exception e) { - e.printStackTrace(); - die("Could not start because of a problem with size()", e); - */ } - - // clear things out to get started - //outgoing.defaults(); - // tell people to use beginDraw/endDraw - - // and send 'em off - //return outgoing; } + /** + * Preferred method of creating new PImage objects, ensures that a + * reference to the parent PApplet is included, which makes save() work + * without needing an absolute path. + */ + public PImage createImage(int width, int height, int format) { + PImage image = new PImage(width, height, format); + image.parent = this; // make save() work + return image; + } + public void update(Graphics screen) { //System.out.println("PApplet.update()"); if (THREAD_DEBUG) println(Thread.currentThread().getName() + @@ -2280,9 +2351,9 @@ public class PApplet extends Applet // - int cursor_type = ARROW; // cursor type - boolean cursor_visible = true; // cursor visibility flag - PImage invisible_cursor; + int cursorType = ARROW; // cursor type + boolean cursorVisible = true; // cursor visibility flag + PImage invisibleCursor; /** @@ -2290,8 +2361,8 @@ public class PApplet extends Applet */ public void cursor(int _cursor_type) { setCursor(Cursor.getPredefinedCursor(_cursor_type)); - cursor_visible = true; - cursor_type = _cursor_type; + cursorVisible = true; + cursorType = _cursor_type; } @@ -2330,7 +2401,7 @@ public class PApplet extends Applet hotspot, "no cursor" }); setCursor(cursor); - cursor_visible = true; + cursorVisible = true; } catch (NoSuchMethodError e) { System.err.println("cursor() is not available " + @@ -2353,9 +2424,9 @@ public class PApplet extends Applet // it's likely that java will set the cursor to something // else on its own, and the applet will be stuck b/c bagel // thinks that the cursor is set to one particular thing - if (!cursor_visible) { - cursor_visible = true; - setCursor(Cursor.getPredefinedCursor(cursor_type)); + if (!cursorVisible) { + cursorVisible = true; + setCursor(Cursor.getPredefinedCursor(cursorType)); } } @@ -2365,15 +2436,15 @@ public class PApplet extends Applet * and using it as a custom cursor. */ public void noCursor() { - if (!cursor_visible) return; // don't hide if already hidden. + if (!cursorVisible) return; // don't hide if already hidden. - if (invisible_cursor == null) { - invisible_cursor = new PImage(16, 16, ARGB); + if (invisibleCursor == null) { + invisibleCursor = new PImage(16, 16, ARGB); } // was formerly 16x16, but the 0x0 was added by jdf as a fix // for macosx, which didn't wasn't honoring the invisible cursor - cursor(invisible_cursor, 0, 0); - cursor_visible = false; + cursor(invisibleCursor, 0, 0); + cursorVisible = false; } @@ -3107,14 +3178,88 @@ public class PApplet extends Applet * work that will be posted on the web. To get a list of possible * image formats for use with Java 1.4 and later, use the following: * println(javax.imageio.ImageIO.getReaderFormatNames()) + *

+ * Images are loaded via a byte array that is passed to + * Toolkit.createImage(). Unfortunately, we cannot use Applet.getImage() + * because it takes a URL argument, which would be a pain in the a-- + * to make work consistently for online and local sketches. + * Sometimes this causes problems, resulting in issues like + * Bug 279 + * and + * Bug 305. + * In release 0115, everything was instead run through javax.imageio, + * but that turned out to be very slow, see + * Bug 392. + * As a result, starting with 0116, the following happens: + *

+ * For releases 0116 and later, if you have problems such as those seen + * in Bugs 279 and 305, use Applet.getImage() instead. You'll be stuck + * with the limitations of getImage() (the headache of dealing with + * online/offline use). Set up your own MediaTracker, and pass the resulting + * java.awt.Image to the PImage constructor that takes an AWT image. + * You can also use the loadImageSync() function (added in 0116) that + * takes an AWT image and loads it synchronously inside PApplet. + * This isn't much fun, but this will have to do unless we find the + * actual culprit, which may still be a threading issue. + *
+   * public PImage loadImageAlt(String filename) {
+   *   java.awt.Image img = getImage(getCodeBase(), filename);
+   *   return loadImageSync(img);
+   * }
+   * 
*/ public PImage loadImage(String filename) { - // it's not clear whether this method is more efficient for - // loading gif, jpeg, and png data than the standard toolkit function, - // in fact it may even be identical. but who knows, with any luck - // it may even fix the image loading problems from bug #279. - // http://dev.processing.org/bugs/show_bug.cgi?id=279 - // (if anyone reading this knows for certain, please post) + String lower = filename.toLowerCase(); + + if (lower.endsWith(".tga")) { + try { + return loadImageTGA(filename); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + if (lower.endsWith(".tif") || lower.endsWith(".tiff")) { + byte bytes[] = loadBytes(filename); + return (bytes == null) ? null : PImage.loadTIFF(bytes); + } + + // Make sure that PNG images aren't being loaded by Java 1.1 + if (lower.endsWith(".png") && PApplet.javaVersion < 1.3f) { + System.err.println("PNG images can only be loaded when " + + "using Java 1.3 and later."); + return null; + } + + // For jpeg, gif, and png, load them using createImage(), + // because the javax.imageio code was found to be much slower, see + // Bug 392. + try { + if (lower.endsWith(".jpg") || lower.endsWith(".jpeg") || + lower.endsWith(".gif") || lower.endsWith(".png")) { + byte bytes[] = loadBytes(filename); + if (bytes == null) { + return null; + } else { + Image awtImage = Toolkit.getDefaultToolkit().createImage(bytes); + PImage image = loadImageSync(awtImage); + // if it's a .gif image, test to see if it has transparency + if ((lower.endsWith(".gif")) || (lower.endsWith(".png"))) { + image.checkAlpha(); + } + return image; + } + } + } catch (Exception e) { + // show error, but move on to the stuff below, see if it'll work + e.printStackTrace(); + } + if (PApplet.javaVersion >= 1.4f) { if (loadImageFormats == null) { //loadImageFormats = javax.imageio.ImageIO.getReaderFormatNames(); @@ -3137,42 +3282,25 @@ public class PApplet extends Applet } } - if (filename.toLowerCase().endsWith(".tga")) { - try { - return loadImageTGA(filename); - } catch (IOException e) { - e.printStackTrace(); - return null; - } - } + // failed, could not load image after all those attempts + return null; + } - byte bytes[] = loadBytes(filename); - if (bytes == null) return null; - - if (filename.toLowerCase().endsWith(".tif") || - filename.toLowerCase().endsWith(".tiff")) { - return PImage.loadTIFF(bytes); - } - - Image awtImage = Toolkit.getDefaultToolkit().createImage(bytes); + /** + * Load an AWT image synchronously. + */ + public PImage loadImageSync(Image awtImage) { MediaTracker tracker = new MediaTracker(this); tracker.addImage(awtImage, 0); try { tracker.waitForAll(); } catch (InterruptedException e) { - // don't bother, since this may be interrupted by draw - // or noLoop or something like that //e.printStackTrace(); // non-fatal, right? } PImage image = new PImage(awtImage); - - // if it's a .gif image, test to see if it has transparency - if ((filename.toLowerCase().endsWith(".gif")) || - (filename.toLowerCase().endsWith(".png"))) { - image.checkAlpha(); - } + image.parent = this; return image; } @@ -3216,6 +3344,7 @@ public class PApplet extends Applet // with the old method. PImage outgoing = new PImage(wi.intValue(), hi.intValue()); + outgoing.parent = this; Method getRgbMethod = biClass.getMethod("getRGB", new Class[] { @@ -3283,6 +3412,7 @@ public class PApplet extends Applet int w = ((header[13] & 0xff) << 8) + (header[12] & 0xff); int h = ((header[15] & 0xff) << 8) + (header[14] & 0xff); PImage outgoing = new PImage(w, h, format); + outgoing.parent = this; int index = 0; int px[] = outgoing.pixels; @@ -3337,31 +3467,7 @@ public class PApplet extends Applet } } return outgoing; - - /* - // targa's are written upside down, so we need to parse it in reverse - int index = (h-1) * w; - // actual bitmap data starts at byte 18 - int offset = 18; - - // read out line by line - for (int y = h-1; y >= 0; y--) { - for (int x = 0; x < w; x++) { - img.pixels[index + x] = - (buffer[offset++] & 0xff) | - ((buffer[offset++] & 0xff) << 8) | - ((buffer[offset++] & 0xff) << 16) | - (hasAlpha ? ((buffer[offset++] & 0xff) << 24) : 0xff000000); - } - index -= w; - } - return img; - } - - System.err.println("loadImage(): bad targa image format"); - return null; - */ -} + } @@ -3621,14 +3727,14 @@ public class PApplet extends Applet * I want to read lines from a file. I have RSI from typing these * eight lines of code so many times. */ - public BufferedReader reader(String filename) { + public BufferedReader createReader(String filename) { try { InputStream is = openStream(filename); if (is == null) { System.err.println(filename + " does not exist or could not be read"); return null; } - return reader(is); + return createReader(is); } catch (Exception e) { if (filename == null) { @@ -3644,9 +3750,9 @@ public class PApplet extends Applet /** * I want to read lines from a file. And I'm still annoyed. */ - static public BufferedReader reader(File file) { + static public BufferedReader createReader(File file) { try { - return reader(new FileInputStream(file)); + return createReader(new FileInputStream(file)); } catch (Exception e) { if (file == null) { @@ -3665,7 +3771,7 @@ public class PApplet extends Applet * I want to read lines from a stream. If I have to type the * following lines any more I'm gonna send Sun my medical bills. */ - static public BufferedReader reader(InputStream input) { + static public BufferedReader createReader(InputStream input) { InputStreamReader isr = new InputStreamReader(input); return new BufferedReader(isr); } @@ -3702,9 +3808,9 @@ public class PApplet extends Applet /** * I want to print lines to a file. Why can't I? */ - public PrintWriter writer(String filename) { + public PrintWriter createWriter(String filename) { try { - return writer(new FileOutputStream(savePath(filename))); + return createWriter(new FileOutputStream(savePath(filename))); } catch (Exception e) { if (filename == null) { @@ -3721,9 +3827,9 @@ public class PApplet extends Applet * I want to print lines to a file. I have RSI from typing these * eight lines of code so many times. */ - static public PrintWriter writer(File file) { + static public PrintWriter createWriter(File file) { try { - return writer(new FileOutputStream(file)); + return createWriter(new FileOutputStream(file)); } catch (Exception e) { if (file == null) { @@ -3742,7 +3848,7 @@ public class PApplet extends Applet * I want to print lines to a file. Why am I always explaining myself? * It's the JavaSoft API engineers who need to explain themselves. */ - static public PrintWriter writer(OutputStream output) { + static public PrintWriter createWriter(OutputStream output) { OutputStreamWriter osw = new OutputStreamWriter(output); return new PrintWriter(osw); } @@ -6542,21 +6648,13 @@ public class PApplet extends Applet } - static public int blend(int c1, int c2, int mode) { - return PGraphics.blend(c1, c2, mode); + static public int blendColor(int c1, int c2, int mode) { + return PGraphics.blendColor(c1, c2, mode); } - public void blend(int sx, int sy, int dx, int dy, int mode) { - if (recorder != null) recorder.blend(sx, sy, dx, dy, mode); - g.blend(sx, sy, dx, dy, mode); - } - - - public void blend(PImage src, - int sx, int sy, int dx, int dy, int mode) { - if (recorder != null) recorder.blend(src, sx, sy, dx, dy, mode); - g.blend(src, sx, sy, dx, dy, mode); + static public int lerpColor(int c1, int c2, float amt) { + return PGraphics.lerpColor(c1, c2, amt); } @@ -6575,6 +6673,12 @@ public class PApplet extends Applet } + public void setMainDrawingSurface() { + if (recorder != null) recorder.setMainDrawingSurface(); + g.setMainDrawingSurface(); + } + + public void hint(int which) { if (recorder != null) recorder.hint(which); g.hint(which); diff --git a/core/src/processing/core/PGraphics.java b/core/src/processing/core/PGraphics.java index 50cedd1f9..be854fb24 100644 --- a/core/src/processing/core/PGraphics.java +++ b/core/src/processing/core/PGraphics.java @@ -36,12 +36,6 @@ import java.awt.image.*; */ public abstract class PGraphics extends PImage implements PConstants { - /*** - * Parent applet as passed in by the constructor. If null, then - * no MemoryImageSource will be used or updated, saving memory. - */ - PApplet parent; - /// width minus one (useful for many calculations) public int width1; @@ -60,6 +54,16 @@ public abstract class PGraphics extends PImage implements PConstants { /// true if in the midst of resize (no drawing can take place) boolean insideResize; + // ........................................................ + + /** + * true if this is the main drawing surface for a particular sketch. + * This would be set to false for an offscreen buffer or if it were + * created any other way than size(). When this is set, the listeners + * are also added to the sketch. + */ + protected boolean mainDrawingSurface; + // ........................................................ // specifics for java memoryimagesource @@ -488,10 +492,10 @@ public abstract class PGraphics extends PImage implements PConstants { * @param iwidth viewport width * @param iheight viewport height */ - public PGraphics(int iwidth, int iheight) { - this(iwidth, iheight, null); + //public PGraphics(int iwidth, int iheight) { + //this(iwidth, iheight, null); //resize(iwidth, iheight); - } + //} /** @@ -503,11 +507,14 @@ public abstract class PGraphics extends PImage implements PConstants { * @param iwidth viewport width * @param iheight viewport height */ - public PGraphics(int iwidth, int iheight, PApplet applet) { + public PGraphics(int iwidth, int iheight, PApplet parent) { + /* if (applet != null) { this.parent = applet; applet.addListeners(); } + */ + this.parent = parent; resize(iwidth, iheight); } @@ -535,10 +542,25 @@ public abstract class PGraphics extends PImage implements PConstants { /** - * Parent thread has requested that visual action be taken. + * Set this as the main drawing surface. Meaning that it can safely be + * set to opaque (given a default gray background) and listeners for + * the mouse and keyboard added. + *

+ * This should only be used by subclasses of PGraphics. */ - public void requestDisplay(PApplet parent) { // ignore - parent.handleDisplay(); + public void setMainDrawingSurface() { + mainDrawingSurface = true; + parent.addListeners(); + } + + + /** + * Parent thread has requested that visual action be taken. + * This is broken out like this because the OpenGL library + * handles updates in a very different way. + */ + public void requestDisplay(PApplet pa) { // ignore + pa.handleDisplay(); } @@ -629,7 +651,7 @@ public abstract class PGraphics extends PImage implements PConstants { // they have to call background() themselves, otherwise everything gets // a gray background (when just a transparent surface or an empty pdf // is what's desired) - if (parent != null) { + if (mainDrawingSurface) { background(204); } diff --git a/core/src/processing/core/PGraphics2D.java b/core/src/processing/core/PGraphics2D.java index d1b846f54..6932703b0 100644 --- a/core/src/processing/core/PGraphics2D.java +++ b/core/src/processing/core/PGraphics2D.java @@ -62,17 +62,22 @@ public class PGraphics2D extends PGraphics { protected PGraphics2D() { } + /* public PGraphics2D(int iwidth, int iheight) { this(iwidth, iheight, null); } + */ public PGraphics2D(int iwidth, int iheight, PApplet applet) { + super(iwidth, iheight, applet); + /* if (applet != null) { this.parent = applet; applet.addListeners(); } resize(iwidth, iheight); + */ } @@ -93,7 +98,8 @@ public class PGraphics2D extends PGraphics { for (int i = 0; i < pixelCount; i++) pixels[i] = backgroundColor; //for (int i = 0; i < pixelCount; i++) pixels[i] = 0xffffffff; - if (parent != null) { + //if (parent != null) { + if (mainDrawingSurface) { cm = new DirectColorModel(32, 0x00ff0000, 0x0000ff00, 0x000000ff);; mis = new MemoryImageSource(width, height, pixels, 0, width); mis.setFullBufferUpdates(true); diff --git a/core/src/processing/core/PGraphics3D.java b/core/src/processing/core/PGraphics3D.java index 4876b01b0..89054dca6 100644 --- a/core/src/processing/core/PGraphics3D.java +++ b/core/src/processing/core/PGraphics3D.java @@ -186,9 +186,11 @@ public class PGraphics3D extends PGraphics { } + /* public PGraphics3D(int iwidth, int iheight) { this(iwidth, iheight, null); } + */ /** diff --git a/core/src/processing/core/PGraphicsJava2D.java b/core/src/processing/core/PGraphicsJava2D.java index 73f9ffeba..1af40614f 100644 --- a/core/src/processing/core/PGraphicsJava2D.java +++ b/core/src/processing/core/PGraphicsJava2D.java @@ -1253,6 +1253,7 @@ public class PGraphicsJava2D extends PGraphics { ////////////////////////////////////////////////////////////// + /* public void blend(PImage src, int sx, int sy, int dx, int dy, int mode) { loadPixels(); super.blend(src, sx, sy, dx, dy, mode); @@ -1265,6 +1266,7 @@ public class PGraphicsJava2D extends PGraphics { super.blend(sx, sy, dx, dy, mode); updatePixels(); } + */ public void blend(int sx1, int sy1, int sx2, int sy2, diff --git a/core/src/processing/core/PImage.java b/core/src/processing/core/PImage.java index d25d55469..09f116556 100644 --- a/core/src/processing/core/PImage.java +++ b/core/src/processing/core/PImage.java @@ -28,8 +28,6 @@ import java.awt.image.*; import java.io.*; import java.lang.reflect.*; -//import javax.imageio.*; - /** * Storage class for pixel data. This is the base class for most image and @@ -52,6 +50,12 @@ public class PImage implements PConstants, Cloneable { public int width, height; // would scan line be useful? maybe for pow of 2 gl textures + /** + * Path to parent object that will be used with save(). + * This prevents users from needing savePath() to use PImage.save(). + */ + public PApplet parent; + // note! inherited by PGraphics public int imageMode = CORNER; public boolean smooth = false; @@ -107,6 +111,7 @@ public class PImage implements PConstants, Cloneable { */ public PImage(int width, int height) { init(width, height, RGB); + //init(width, height, RGB); //this(new int[width * height], width, height, ARGB); // toxi: is it maybe better to init the image with max alpha enabled? //for(int i=0; i */ - static public int blend(int c1, int c2, int mode) { + static public int blendColor(int c1, int c2, int mode) { switch (mode) { case BLEND: return blend_multiply(c1, c2); case ADD: return blend_add_pin(c1, c2); @@ -1197,10 +1098,28 @@ public class PImage implements PConstants, Cloneable { return 0; } + + static public int lerpColor(int c1, int c2, float amt) { + float a1 = ((c1 >> 24) & 0xff); + float r1 = (c1 >> 16) & 0xff; + float g1 = (c1 >> 8) & 0xff; + float b1 = c1 & 0xff; + float a2 = (c2 >> 24) & 0xff; + float r2 = (c2 >> 16) & 0xff; + float g2 = (c2 >> 8) & 0xff; + float b2 = c2 & 0xff; + + return (((int) (a1 + (a2-a1)*amt) << 24) | + ((int) (r1 + (r2-r1)*amt) << 16) | + ((int) (g1 + (g2-g1)*amt) << 8) | + ((int) (b1 + (b2-b1)*amt))); + } /** * Copies and blends 1 pixel with MODE to pixel in this image. + * Removing this function, the blend() command above can be used instead. */ + /* public void blend(int sx, int sy, int dx, int dy, int mode) { if ((dx >= 0) && (dx < width) && (sx >= 0) && (sx < width) && (dy >= 0) && (dy < height) && (sy >= 0) && (sy < height)) { @@ -1208,11 +1127,13 @@ public class PImage implements PConstants, Cloneable { blend(pixels[dy * width + dx], pixels[sy * width + sx], mode); } } + */ /** * Copies and blends 1 pixel with MODE to pixel in another image */ + /* public void blend(PImage src, int sx, int sy, int dx, int dy, int mode) { if ((dx >= 0) && (dx < width) && (sx >= 0) && (sx < src.width) && @@ -1222,6 +1143,7 @@ public class PImage implements PConstants, Cloneable { src.pixels[sy * src.width + sx], mode); } } + */ /** @@ -1305,7 +1227,10 @@ public class PImage implements PConstants, Cloneable { /** * Duplicate an image, returns new PImage object. * The pixels[] array for the new object will be unique - * and recopied from the source image. + * and recopied from the source image. This is implemented as an + * override of Object.clone(). We recommend using get() instead, + * because it prevents you from needing to catch the + * CloneNotSupportedException, and from doing a cast from the result. */ public Object clone() throws CloneNotSupportedException { // ignore PImage c = (PImage) super.clone(); @@ -1618,19 +1543,6 @@ public class PImage implements PConstants, Cloneable { } - /** - * returns the fractional portion of a number: frac(2.3) = .3; - */ - /* - private static float frac(float x) { - return (x - (int) x); - } - */ - - - /** - * generic linear interpolation - */ private static int mix(int a, int b, int f) { return a + (((b - a) * f) >> 8); } @@ -1812,7 +1724,7 @@ public class PImage implements PConstants, Cloneable { protected boolean saveTIFF(OutputStream output) { if (format != RGB) { System.err.println("Warning: only RGB information is saved with " + - ".tif files. Use .tga or .png if you want alpha."); + ".tif files. Use .tga or .png for ARGB images and others."); } try { byte tiff[] = new byte[768]; @@ -1849,7 +1761,7 @@ public class PImage implements PConstants, Cloneable { /** * Creates a Targa32 formatted byte sequence of specified - * pixel buffer now using RLE compression. + * pixel buffer using RLE compression. *

* Also figured out how to avoid parsing the image upside-down * (there's a header flag to set the image origin to top-left) @@ -1860,7 +1772,7 @@ public class PImage implements PConstants, Cloneable { *
  • RGB → 24 bits *
  • ARGB → 32 bits * - * all versions are RLE compressed + * All versions are RLE compressed. *

    * Contributed by toxi 8-10 May 2005, based on this RLE * specification @@ -2087,15 +1999,23 @@ public class PImage implements PConstants, Cloneable { * The ImageIO API claims to support wbmp files, however they probably * require a black and white image. Basic testing produced a zero-length * file with no error. + *

    + * As of revision 0116, savePath() is not needed if this object has been + * created (as recommended) via createImage() or createGraphics() or + * one of its neighbors. */ - public void save(String filename) { // ignore + public void save(String path) { // ignore boolean success = false; - File file = new File(filename); + File file = new File(path); if (!file.isAbsolute()) { - System.err.println("PImage.save() requires an absolute path, " + - "you might need to use savePath()."); - return; + if (parent != null) { + //file = new File(parent.savePath(filename)); + path = parent.savePath(path); + } else { + throw new RuntimeException("PImage.save() requires an absolute path. Or you can " + + "use createImage() instead or pass savePath() to save()."); + } } try { @@ -2116,26 +2036,25 @@ public class PImage implements PConstants, Cloneable { } if (saveImageFormats != null) { for (int i = 0; i < saveImageFormats.length; i++) { - //System.out.println(saveImageFormats[i]); - if (filename.endsWith("." + saveImageFormats[i])) { - saveImageIO(filename); + if (path.endsWith("." + saveImageFormats[i])) { + saveImageIO(path); return; } } } } - if (filename.toLowerCase().endsWith(".tga")) { - os = new BufferedOutputStream(new FileOutputStream(filename), 32768); + if (path.toLowerCase().endsWith(".tga")) { + os = new BufferedOutputStream(new FileOutputStream(path), 32768); success = saveTGA(os); //, pixels, width, height, format); } else { - if (!filename.toLowerCase().endsWith(".tif") && - !filename.toLowerCase().endsWith(".tiff")) { + if (!path.toLowerCase().endsWith(".tif") && + !path.toLowerCase().endsWith(".tiff")) { // if no .tif extension, add it.. - filename += ".tif"; + path += ".tif"; } - os = new BufferedOutputStream(new FileOutputStream(filename), 32768); + os = new BufferedOutputStream(new FileOutputStream(path), 32768); success = saveTIFF(os); //, pixels, width, height); } os.flush(); diff --git a/core/todo.txt b/core/todo.txt index 3a8df4434..1b582a4c7 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -43,7 +43,10 @@ X remove image(filename) and textFont(filename) et al. X revision 115 may be saving raw files as TIFF format X may be a bug specific to java 1.5 (nope) X http://dev.processing.org/bugs/show_bug.cgi?id=378 +X saveFrame() not working for casey +X problem with tiff loading in photoshop etc X hint(DISABLE_NATIVE_FONTS) to disable the built-in stuff? +_ or maybe this should be hint(ENABLE_NATIVE_FONTS) instead? X check http:// stuff to see if it's a url first on openStream() X it's the most harmless, since prolly just a MFUEx X fix problem where root of exported sketch won't be checked @@ -61,6 +64,26 @@ X fix dxf to use begin/endDraw instead of begin/endFrame X fixes axel's bug with dxf export X set default frameRate cap at 60 X otherwise really thrashing the cpu when not necessary +X jpeg loading may be extremely slow (loadBytes?) +X seems specific to 0115 versus the others +X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1158111639 +X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1154714548 +X http://dev.processing.org/bugs/show_bug.cgi?id=392 +X loadImage() problems with png and jpg +X actually it's an issue with some types of jpeg files +X http://dev.processing.org/bugs/show_bug.cgi?id=279 +X java.lang.IllegalArgumentException: +X Width (-1) and height (-1) cannot be <= 0 +X identical to what happens when the image data is bad +X for instance, trying to load a tiff image with the jpg loader +X http://dev.processing.org/bugs/show_bug.cgi?id=305 +o blend() mode param should be moved to the front +X nah, works better with the other format +X make sure there's parity with the copy() functions +X remove single pixel blend functions +o blend() should prolly have its mode be the first param +X move blend() to blendColor() when applying it to a color +X added lerpColor(), though it needs a new name more recent X only update mouse pos on moved and dragged @@ -111,11 +134,8 @@ _ for a PGraphics2D, should its image cache object be the memoryimagesource? _ is the texture[] array in PGraphics3D causing the problems with memory? _ actually it's a PGraphicsGL problem.. _ maybe the image binding not getting unbound? - -_ jpeg loading may be extremely slow (loadBytes?) -_ seems specific to 0115 versus the others -_ http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1158111639 -_ http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1154714548 +_ loading lots of images is a problem, describe how to unload +_ is it possible? necessary to call delay(5) or something? api issues _ remove LINE_LOOP and LINE_STRIP @@ -187,27 +207,10 @@ _ since camera functions don't even look at it or set it _ file for 2.0.. stroke on type -_ saveFrame() not working for casey -_ problem with tiff loading in photoshop etc -void setup() { -size(400, 400); -noLoop(); -} -void draw() { -line(0, 0, width, height); -line(0, width, height, 0); -saveFrame(); -} - _ fonts in java 1.5 have changed again _ appears that asking for the postscript name no longer works _ fix "create font" and associated font stuff to straighten it out -_ blend() mode param should be moved to the front -_ make sure there's parity with the copy() functions -_ remove single pixel blend functions -_ blend() should prolly have its mode be the first param - _ add to docs: save() on a PImage needs savePath() added _ background() with an image ignores the tint.. it's basically like set() @@ -230,9 +233,6 @@ _ textAlign(CENTER | TOP); _ could even have textAlign(CENTER) and textAlign(TOP) not replace each other _ or textAlign(LEFT, MIDDLE); -> this one seems best -_ loading lots of images is a problem, describe how to unload -_ is it possible? necessary to call delay(5) or something? - _ AIOOBE on PLine 757.. halts renderer X begin/endPixels.. change has been made @@ -865,15 +865,6 @@ _ http://dev.processing.org/bugs/show_bug.cgi?id=103 CORE / PImage -_ loadImage(url) having trouble with jpeg -_ actually it's an issue with some types of jpeg files -_ http://dev.processing.org/bugs/show_bug.cgi?id=279 -_ java.lang.IllegalArgumentException: -_ Width (-1) and height (-1) cannot be <= 0 -_ identical to what happens when the image data is bad -_ for instance, trying to load a tiff image with the jpg loader -_ png image loading problems -_ http://dev.processing.org/bugs/show_bug.cgi?id=305 _ don't grab pixels of java2d images unless asked _ this is the difference between a lot of loadPixels() and not _ so important to have it in before beta if that's the change diff --git a/opengl/src/processing/opengl/PGraphicsOpenGL.java b/opengl/src/processing/opengl/PGraphicsOpenGL.java index acdf81e14..005f3cb97 100644 --- a/opengl/src/processing/opengl/PGraphicsOpenGL.java +++ b/opengl/src/processing/opengl/PGraphicsOpenGL.java @@ -41,9 +41,9 @@ import com.sun.opengl.util.*; * JOGL requires Java 1.4 or higher, so there are no restrictions on this * code to be compatible with Java 1.1 or Java 1.3. *

    - * This code relies on PGraphics3 for all lighting and transformations. + * This code relies on PGraphics3D for all lighting and transformations. * Meaning that translate(), rotate(), and any lighting will be done in - * PGraphics3, and OpenGL is only used to blit lines and triangles as fast + * PGraphics3D, and OpenGL is only used to blit lines and triangles as fast * as it possibly can. *

    * For this reason, OpenGL may not be accelerated as far as it could be, @@ -98,15 +98,16 @@ public class PGraphicsOpenGL extends PGraphics3D { * be null for this renderer because OpenGL uses a special Canvas * object that must be added to a component (the host PApplet, in this case) * that is visible on screen in order to work properly. - * @param applet the host applet + * @param parent the host applet */ - public PGraphicsOpenGL(int width, int height, PApplet applet) { + public PGraphicsOpenGL(int width, int height, PApplet iparent) { //System.out.println("creating PGraphicsGL"); - if (applet == null) { + if (iparent == null) { throw new RuntimeException("The applet passed to PGraphicsGL " + "cannot be null"); } + this.parent = iparent; //System.out.println("creating PGraphicsGL 2"); @@ -115,13 +116,10 @@ public class PGraphicsOpenGL extends PGraphics3D { canvas = new GLCanvas(); //System.out.println("creating PGraphicsGL 3"); - - final PApplet parent = applet; canvas.addGLEventListener(new GLEventListener() { public void display(GLAutoDrawable drawable) { // need to get a fresh opengl object here - //gl = canvas.getGL(); gl = drawable.getGL(); parent.handleDisplay(); // this means it's time to go } @@ -138,16 +136,16 @@ public class PGraphicsOpenGL extends PGraphics3D { //System.out.println("creating PGraphicsGL 4"); - applet.setLayout(null); - applet.add(canvas); + parent.setLayout(null); + parent.add(canvas); canvas.setBounds(0, 0, width, height); //System.out.println("creating PGraphicsGL 5"); //System.out.println("adding canvas listeners"); - canvas.addMouseListener(applet); - canvas.addMouseMotionListener(applet); - canvas.addKeyListener(applet); - canvas.addFocusListener(applet); + canvas.addMouseListener(parent); + canvas.addMouseMotionListener(parent); + canvas.addKeyListener(parent); + canvas.addFocusListener(parent); //System.out.println("creating PGraphicsGL 6"); @@ -184,8 +182,17 @@ public class PGraphicsOpenGL extends PGraphics3D { //System.out.println("done creating gl"); } + + + /** + * Overridden from base PGraphics, because this PGraphics will set its own listeners. + */ + public void setMainDrawingSurface() { + mainDrawingSurface = true; + //parent.addListeners(); + } - + //protected boolean displayed = false; // main applet thread requests an update, @@ -1791,7 +1798,7 @@ public class PGraphicsOpenGL extends PGraphics3D { ////////////////////////////////////////////////////////////// - public void beginPixels() { + public void loadPixels() { if ((pixels == null) || (pixels.length != width*height)) { pixels = new int[width * height]; pixelBuffer = BufferUtil.newIntBuffer(pixels.length); @@ -2080,7 +2087,7 @@ public class PGraphicsOpenGL extends PGraphics3D { } - public void endPixels() { + public void updatePixels() { // flip vertically (opengl stores images upside down), int index = 0; @@ -2152,14 +2159,7 @@ public class PGraphicsOpenGL extends PGraphics3D { GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, pixelBuffer); } - - public void endPixels(int x, int y, int c, int d) { - //throw new RuntimeException("endPixels() not available with OpenGL"); - // TODO make this actually work for a smaller region - // problem is, it gets pretty messy with the y reflection, etc - endPixels(); - } - + ////////////////////////////////////////////////////////////// @@ -2310,9 +2310,9 @@ public class PGraphicsOpenGL extends PGraphics3D { public void copy(int sx1, int sy1, int sx2, int sy2, int dx1, int dy1, int dx2, int dy2) { //throw new RuntimeException("copy() not available with OpenGL"); - beginPixels(); + loadPixels(); super.copy(sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2); - endPixels(); + updatePixels(); } @@ -2324,9 +2324,9 @@ public class PGraphicsOpenGL extends PGraphics3D { public void copy(PImage src, int sx1, int sy1, int sx2, int sy2, int dx1, int dy1, int dx2, int dy2) { - beginPixels(); + loadPixels(); super.copy(src, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2); - endPixels(); + updatePixels(); } @@ -2334,13 +2334,13 @@ public class PGraphicsOpenGL extends PGraphics3D { public void blend(int sx, int sy, int dx, int dy, int mode) { - set(dx, dy, PImage.blend(get(sx, sy), get(dx, dy), mode)); + set(dx, dy, PImage.blendColor(get(sx, sy), get(dx, dy), mode)); } public void blend(PImage src, int sx, int sy, int dx, int dy, int mode) { - set(dx, dy, PImage.blend(src.get(sx, sy), get(dx, dy), mode)); + set(dx, dy, PImage.blendColor(src.get(sx, sy), get(dx, dy), mode)); } @@ -2351,9 +2351,9 @@ public class PGraphicsOpenGL extends PGraphics3D { */ public void blend(int sx1, int sy1, int sx2, int sy2, int dx1, int dy1, int dx2, int dy2, int mode) { - beginPixels(); + loadPixels(); super.blend(sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2, mode); - endPixels(); + updatePixels(); } @@ -2365,9 +2365,9 @@ public class PGraphicsOpenGL extends PGraphics3D { public void blend(PImage src, int sx1, int sy1, int sx2, int sy2, int dx1, int dy1, int dx2, int dy2, int mode) { - beginPixels(); + loadPixels(); super.blend(src, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2, mode); - endPixels(); + updatePixels(); } @@ -2375,7 +2375,7 @@ public class PGraphicsOpenGL extends PGraphics3D { public void save(String filename) { - beginPixels(); + loadPixels(); super.save(filename); } diff --git a/todo.txt b/todo.txt index c77ad8ba1..8810546ec 100644 --- a/todo.txt +++ b/todo.txt @@ -75,9 +75,9 @@ _ under the memory section, getting free/total memory _ long allocated = Runtime.getRuntime().totalMemory() (-Xms usually) _ long allocatedButFree = Runtime.getRuntime().freeMemory() (-Xms minus used) _ long maximum = Runtime.getRuntime().maxMemory() (-Xmx setting) -_ remove the memory setting stuff from the faq -_ add more information about setting the memory -_ move memory setting to troubleshooting page on bugs db +X remove the memory setting stuff from the faq +X add more information about setting the memory +X move memory setting to troubleshooting page on bugs db mac faq X windows, may need to install new version of video drivers diff --git a/video/src/processing/video/Capture.java b/video/src/processing/video/Capture.java index 59b46312f..e9fca28fb 100755 --- a/video/src/processing/video/Capture.java +++ b/video/src/processing/video/Capture.java @@ -51,7 +51,9 @@ public class Capture extends PImage implements Runnable { static public final int PAL = StdQTConstants.palIn; static public final int SECAM = StdQTConstants.secamIn; - PApplet parent; + // no longer needed because parent field added to PImage + //PApplet parent; + Method captureEventMethod; String name; // keep track for error messages (unused) Thread runner; @@ -129,7 +131,7 @@ public class Capture extends PImage implements Runnable { *

    * If the following function: *

    public void captureEvent(Capture c)
    - * is defined int the host PApplet, then it will be called every + * is defined in the host PApplet, then it will be called every * time a new frame is available from the capture device. */ public Capture(PApplet parent, String name, diff --git a/video/src/processing/video/Movie.java b/video/src/processing/video/Movie.java index 42bd9f552..a0419adcc 100644 --- a/video/src/processing/video/Movie.java +++ b/video/src/processing/video/Movie.java @@ -40,7 +40,9 @@ import quicktime.util.RawEncodedImage; public class Movie extends PImage implements PConstants, Runnable { - PApplet parent; + // no longer needing a reference to the parent because PImage has one + //PApplet parent; + Method movieEventMethod; String filename; Thread runner; @@ -90,7 +92,7 @@ public class Movie extends PImage implements PConstants, Runnable { public Movie(PApplet parent, String filename, int ifps) { // this creates a fake image so that the first time this // attempts to draw, something happens that's not an exception - super.init(1, 1, RGB); + super(1, 1, RGB); this.parent = parent; @@ -417,8 +419,7 @@ public class Movie extends PImage implements PConstants, Runnable { if (dataWidth != movieWidth) { if (removeBorders) { - int bpixels[] = new int[dataWidth * movieHeight]; - borderImage = new PImage(bpixels, dataWidth, movieHeight, RGB); + borderImage = new PImage(dataWidth, movieHeight, RGB); } else { movieWidth = dataWidth; }