/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* Part of the Processing project - http://processing.org Copyright (c) 2004-06 Ben Fry and Casey Reas Copyright (c) 2001-04 Massachusetts Institute of Technology This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package processing.core; import java.applet.*; import java.awt.*; import java.awt.event.*; import java.awt.image.*; import java.io.*; import java.lang.reflect.*; import java.net.*; import java.text.*; import java.util.*; 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, with or without Swing. * * 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 PApplet inside another GUI the wayyou * would any other Component. * * Because the default animation thread will run at 60 frames per second, * an embedded PApplet can make the parent sluggish. You can use frameRate() * to make it update less often, or you can use noLoop() and loop() to disable * and then re-enable looping. 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(); * } * } ** *
I was asked about Processing with multiple displays, and for lack of a * better place to document it, things will go here.
*You can address both screens by making a window the width of both, * and the height of the maximum of both screens. In this case, do not use * present mode, because that's exclusive to one screen. Basically it'll * give you a PApplet that spans both screens. If using one half to control * and the other half for graphics, you'd just have to put the 'live' stuff * on one half of the canvas, the control stuff on the other. This works * better in windows because on the mac we can't get rid of the menu bar * unless it's running in present mode.
*For more control, you need to write straight java code that uses p5. * You can create two windows, that are shown on two separate screens, * that have their own PApplet. this is just one of the tradeoffs of one of * the things that we don't support in p5 from within the environment * itself (we must draw the line somewhere), because of how messy it would * get to start talking about multiple screens. It's also not that tough to * do by hand w/ some Java code.
*/ public class PApplet extends Applet implements PConstants, Runnable, MouseListener, MouseMotionListener, KeyListener, FocusListener { /** * Full name of the Java version (i.e. 1.5.0_11). * Prior to 0125, this was only the first three digits. */ public static final String javaVersionName = System.getProperty("java.version"); /** * Version of Java that's in use, whether 1.1 or 1.3 or whatever, * stored as a float. ** Note that because this is stored as a float, the values may * not be exactly 1.3 or 1.4. Instead, make sure you're * comparing against 1.3f or 1.4f, which will have the same amount * of error (i.e. 1.40000001). This could just be a double, but * since Processing only uses floats, it's safer for this to be a float * because there's no good way to specify a double with the preproc. */ public static final float javaVersion = new Float(javaVersionName.substring(0, 3)).floatValue(); /** * Current platform in use, one of the * PConstants WINDOWS, MACOSX, MACOS9, LINUX or OTHER. */ static public int platform; /** * Current platform in use. *
* Equivalent to System.getProperty("os.name"), just used internally. */ static public String platformName = System.getProperty("os.name"); static { // figure out which operating system // this has to be first, since editor needs to know if (platformName.toLowerCase().indexOf("mac") != -1) { // can only check this property if running on a mac // on a pc it throws a security exception and kills the applet // (but on the mac it does just fine) if (System.getProperty("mrj.version") != null) { // running on a mac platform = (platformName.equals("Mac OS X")) ? MACOSX : MACOS9; } } else { String osname = System.getProperty("os.name"); if (osname.indexOf("Windows") != -1) { platform = WINDOWS; } else if (osname.equals("Linux")) { // true for the ibm vm platform = LINUX; } else { platform = OTHER; } } } /** The PGraphics renderer associated with this PApplet */ public PGraphics g; //protected Object glock = new Object(); // for sync /** The frame containing this applet (if any) */ public Frame frame; /** * Message of the Exception thrown when size() is called the first time. *
* This is used internally so that setup() is forced to run twice * when the renderer is changed. This is the only way for us to handle * invoking the new renderer while also in the midst of rendering. */ static final String NEW_RENDERER = "new renderer"; /** * The screen size when the applet was started. *
* Access this via screen.width and screen.height. To make an applet * run at full screen, use size(screen.width, screen.height). *
* If you have multiple displays, this will be the size of the main * display. Running full screen across multiple displays isn't * particularly supported, and requires more monkeying with the values. * This probably can't/won't be fixed until/unless I get a dual head * system. *
* Note that this won't update if you change the resolution * of your screen once the the applet is running. */ public Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); /** * A leech graphics object that is echoing all events. */ public PGraphics recorder; /** * Command line options passed in from main(). *
* This does not include the arguments passed in to PApplet itself. */ public String args[]; /** Path to sketch folder */ public String sketchPath; //folder; /** When debugging headaches */ static final boolean THREAD_DEBUG = false; private Object blocker = new Object(); /** Default width and height for applet when not specified */ static public final int DEFAULT_WIDTH = 100; static public final int DEFAULT_HEIGHT = 100; /** * Minimum dimensions for the window holding an applet. * This varies between platforms, Mac OS X 10.3 can do any height * but requires at least 128 pixels width. Windows XP has another * set of limitations. And for all I know, Linux probably lets you * make windows with negative sizes. */ static public final int MIN_WINDOW_WIDTH = 128; static public final int MIN_WINDOW_HEIGHT = 128; /** * true if no size() command has been executed. This is used to wait until * a size has been set before placing in the window and showing it. */ public boolean defaultSize; /** * Pixel buffer from this applet's PGraphics. *
* When used with OpenGL or Java2D, this value will * be null until loadPixels() has been called. */ public int pixels[]; /** width of this applet's associated PGraphics */ public int width; /** height of this applet's associated PGraphics */ public int height; /** current x position of the mouse */ public int mouseX; /** current y position of the mouse */ public int mouseY; /** * Previous x/y position of the mouse. This will be a different value * when inside a mouse handler (like the mouseMoved() method) versus * when inside draw(). Inside draw(), pmouseX is updated once each * frame, but inside mousePressed() and friends, it's updated each time * an event comes through. Be sure to use only one or the other type of * means for tracking pmouseX and pmouseY within your sketch, otherwise * you're gonna run into trouble. */ public int pmouseX, pmouseY; /** * previous mouseX/Y for the draw loop, separated out because this is * separate from the pmouseX/Y when inside the mouse event handlers. */ protected int dmouseX, dmouseY; /** * pmouseX/Y for the event handlers (mousePressed(), mouseDragged() etc) * these are different because mouse events are queued to the end of * draw, so the previous position has to be updated on each event, * as opposed to the pmouseX/Y that's used inside draw, which is expected * to be updated once per trip through draw(). */ protected int emouseX, emouseY; /** * Used to set pmouseX/Y to mouseX/Y the first time mouseX/Y are used, * otherwise pmouseX/Y are always zero, causing a nasty jump. *
* Just using (frameCount == 0) won't work since mouseXxxxx() * may not be called until a couple frames into things. */ public boolean firstMouse; /** * Last mouse button pressed, one of LEFT, CENTER, or RIGHT. *
* If running on Mac OS, a ctrl-click will be interpreted as * the righthand mouse button (unlike Java, which reports it as * the left mouse). */ public int mouseButton; public boolean mousePressed; public MouseEvent mouseEvent; /** * Last key pressed. *
* If it's a coded key, i.e. UP/DOWN/CTRL/SHIFT/ALT, * this will be set to CODED (0xffff or 65535). */ public char key; /** * When "key" is set to CODED, this will contain a Java key code. *
* For the arrow keys, keyCode will be one of UP, DOWN, LEFT and RIGHT. * Also available are ALT, CONTROL and SHIFT. A full set of constants * can be obtained from java.awt.event.KeyEvent, from the VK_XXXX variables. */ public int keyCode; /** * true if the mouse is currently pressed. */ public boolean keyPressed; /** * the last KeyEvent object passed into a mouse function. */ public KeyEvent keyEvent; /** * Gets set to true/false as the applet gains/loses focus. */ public boolean focused = false; /** * true if the applet is online. *
* This can be used to test how the applet should behave * since online situations are different (no file writing, etc). */ public boolean online = false; /** * Time in milliseconds when the applet was started. *
* Used by the millis() function. */ long millisOffset; /** * The current value of frames per second. *
* The initial value will be 10 fps, and will be updated with each * frame thereafter. The value is not instantaneous (since that * wouldn't be very useful since it would jump around so much), * but is instead averaged (integrated) over several frames. * As such, this value won't be valid until after 5-10 frames. */ public float frameRate = 10; protected long frameRateLastMillis = 0; /** Last time in milliseconds that a frameRate delay occurred */ protected long frameRateLastDelayTime = 0; /** As of release 0116, frameRate(60) is called as a default */ protected float frameRateTarget = 60; protected boolean looping; /** flag set to true when a redraw is asked for by the user */ protected boolean redraw; /** * How many frames have been displayed since the applet started. *
* This value is read-only do not attempt to set it, * otherwise bad things will happen. *
* Inside setup(), frameCount is 0. * For the first iteration of draw(), frameCount will equal 1. */ public int frameCount; /** * true if this applet has had it. */ public boolean finished; /** * true if exit() has been called so that things shut down * once the main thread kicks off. */ protected boolean exit; Thread thread; /** * Set to the an exception that occurs inside run() and is not * caught.
Used by PdeRuntime to determine what happened and * report back to the user. */ public Exception exception; //public Throwable exception; protected RegisteredMethods sizeMethods; protected RegisteredMethods preMethods, drawMethods, postMethods; protected RegisteredMethods mouseEventMethods, keyEventMethods; protected RegisteredMethods disposeMethods; // this text isn't seen unless PApplet is used on its // own and someone takes advantage of leechErr.. not likely static public final String LEECH_WAKEUP = "Error while running applet."; public PrintStream leechErr; // messages to send if attached as an external vm /** * Position of the upper-lefthand corner of the editor window * that launched this applet. */ static public final String ARGS_EDITOR_LOCATION = "--editor-location"; /** * Location for where to position the applet window on screen. *
* This is used by the editor to when saving the previous applet * location, or could be used by other classes to launch at a * specific position on-screen. */ static public final String ARGS_EXTERNAL = "--external"; static public final String ARGS_LOCATION = "--location"; static public final String ARGS_DISPLAY = "--display"; static public final String ARGS_BGCOLOR = "--bgcolor"; static public final String ARGS_PRESENT = "--present"; static public final String ARGS_STOP_COLOR = "--stop-color"; static public final String ARGS_HIDE_STOP = "--hide-stop"; /** * Allows the user or PdeEditor to set a specific sketch folder path. *
* Used by PdeEditor to pass in the location where saveFrame() * and all that stuff should write things. */ static public final String ARGS_SKETCH_FOLDER = "--sketch-path"; /** * Message from parent editor (when run as external) to quit. */ static public final char EXTERNAL_STOP = 's'; /** * When run externally to a PdeEditor, * this is sent by the applet when it quits. */ static public final String EXTERNAL_QUIT = "__QUIT__"; /** * When run externally to a PdeEditor, this is sent by the applet * whenever the window is moved. *
* This is used so that the editor can re-open the sketch window * in the same position as the user last left it. */ static public final String EXTERNAL_MOVE = "__MOVE__"; // during rev 0100 dev cycle, working on new threading model, // but need to disable and go conservative with changes in order // to get pdf and audio working properly first. // for 0116, the CRUSTY_THREADS are being disabled to fix lots of bugs. static final boolean CRUSTY_THREADS = false; //true; public void init() { // first get placed size in case it's non-zero Dimension initialSize = getSize(); // send tab keys through to the PApplet try { if (javaVersion >= 1.4f) { //setFocusTraversalKeysEnabled(false); // 1.4-only function Method defocus = Component.class.getMethod("setFocusTraversalKeysEnabled", new Class[] { Boolean.TYPE }); defocus.invoke(this, new Object[] { Boolean.FALSE }); } } catch (Exception e) { } // oh well millisOffset = System.currentTimeMillis(); finished = false; // just for clarity // this will be cleared by draw() if it is not overridden looping = true; redraw = true; // draw this guy once firstMouse = true; // these need to be inited before setup sizeMethods = new RegisteredMethods(); preMethods = new RegisteredMethods(); drawMethods = new RegisteredMethods(); postMethods = new RegisteredMethods(); mouseEventMethods = new RegisteredMethods(); keyEventMethods = new RegisteredMethods(); disposeMethods = new RegisteredMethods(); try { getAppletContext(); online = true; } catch (NullPointerException e) { online = false; } if (javaVersion < 1.3f) { addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { link("http://java.com/"); } }); // no init to do, so don't cause no trouble, boy return; // call this after making the methods to minimize the // number of places needing the javaVersion crap // (also needs to check online first and create empty // stop method register list) } try { if (sketchPath == null) { sketchPath = System.getProperty("user.dir"); } } catch (Exception e) { } // may be a security problem // create a dummy graphics context if ((initialSize.width != 0) && (initialSize.height != 0)) { size(initialSize.width, initialSize.height); } else { //System.out.println("setting default"); size(DEFAULT_WIDTH, DEFAULT_HEIGHT); this.defaultSize = true; //System.out.println("zeroing"); //this.width = 0; // use this to flag whether the width/height are valid //this.height = 0; // need to set width/height otherwise // they won't work for static mode apps //defaultSize = true; } // this is automatically called in applets // though it's here for applications anyway start(); } /** * Called by the browser or applet viewer to inform this applet that it * should start its execution. It is called after the init method and * each time the applet is revisited in a Web page. *
* Called explicitly via the first call to PApplet.paint(), because * PAppletGL needs to have a usable screen before getting things rolling. */ public void start() { if (javaVersion < 1.3f) return; if (thread != null) return; thread = new Thread(this); thread.start(); } /** * Called by the browser or applet viewer to inform * this applet that it should stop its execution. * * Unfortunately, there are no guarantees from the Java spec * when or if stop() will be called (i.e. on browser quit, * or when moving between web pages), and it's not always called. */ public void stop() { // maybe start should also be used as the method for kicking // the thread on, instead of doing it inside paint() // bringing this back for 0111, hoping it'll help opengl shutdown finished = true; // why did i comment this out? //System.out.println("stopping applet " + thread); // don't run stop and disposers twice if (thread == null) return; thread = null; // call to shut down renderer, in case it needs it (pdf does) if (g != null) g.dispose(); // maybe this should be done earlier? might help ensure it gets called // before the vm just craps out since 1.5 craps out so aggressively. disposeMethods.handle(); } /** * Called by the browser or applet viewer to inform this applet * that it is being reclaimed and that it should destroy * any resources that it has allocated. * * This also attempts to call PApplet.stop(), in case there * was an inadvertent override of the stop() function by a user. * * destroy() supposedly gets called as the applet viewer * is shutting down the applet. stop() is called * first, and then destroy() to really get rid of things. * no guarantees on when they're run (on browser quit, or * when moving between pages), though. */ public void destroy() { ((PApplet)this).stop(); } /** * This returns the last width and height specified by the user * via the size() command. */ public Dimension getPreferredSize() { return new Dimension(width, height); } ////////////////////////////////////////////////////////////// public class RegisteredMethods { int count; Object objects[]; Method methods[]; // convenience version for no args public void handle() { handle(new Object[] { }); } public void handle(Object oargs[]) { for (int i = 0; i < count; i++) { try { //System.out.println(objects[i] + " " + args); methods[i].invoke(objects[i], oargs); } catch (Exception e) { e.printStackTrace(); } } } public void add(Object object, Method method) { if (objects == null) { objects = new Object[5]; methods = new Method[5]; } if (count == objects.length) { Object otemp[] = new Object[count << 1]; System.arraycopy(objects, 0, otemp, 0, count); objects = otemp; Method mtemp[] = new Method[count << 1]; System.arraycopy(methods, 0, mtemp, 0, count); methods = mtemp; } objects[count] = object; methods[count] = method; count++; } } public void registerSize(Object o) { Class methodArgs[] = new Class[] { Integer.TYPE, Integer.TYPE }; registerWithArgs(sizeMethods, "size", o, methodArgs); } public void registerPre(Object o) { registerNoArgs(preMethods, "pre", o); } public void registerDraw(Object o) { registerNoArgs(drawMethods, "draw", o); } public void registerPost(Object o) { registerNoArgs(postMethods, "post", o); } public void registerMouseEvent(Object o) { Class methodArgs[] = new Class[] { MouseEvent.class }; registerWithArgs(mouseEventMethods, "mouseEvent", o, methodArgs); } public void registerKeyEvent(Object o) { Class methodArgs[] = new Class[] { KeyEvent.class }; registerWithArgs(keyEventMethods, "keyEvent", o, methodArgs); } public void registerDispose(Object o) { registerNoArgs(disposeMethods, "dispose", o); } protected void registerNoArgs(RegisteredMethods meth, String name, Object o) { Class c = o.getClass(); try { Method method = c.getMethod(name, new Class[] {}); meth.add(o, method); } catch (Exception e) { die("Could not register " + name + " + () for " + o, e); } } protected void registerWithArgs(RegisteredMethods meth, String name, Object o, Class cargs[]) { Class c = o.getClass(); try { Method method = c.getMethod(name, cargs); meth.add(o, method); } catch (Exception e) { die("Could not register " + name + " + () for " + o, e); } } ////////////////////////////////////////////////////////////// public void setup() { } public void draw() { // if no draw method, then shut things down //System.out.println("no draw method, goodbye"); finished = true; } ////////////////////////////////////////////////////////////// /** * Starts up and creates a two-dimensional drawing surface, * or resizes the current drawing surface. ** This should be the first thing called inside of setup(). *
* If using Java 1.3 or later, this will default to using * PGraphics2, the Java2D-based renderer. If using Java 1.1, * or if PGraphics2 is not available, then PGraphics will be used. * To set your own renderer, use the other version of the size() * method that takes a renderer as its last parameter. *
* If called once a renderer has already been set, this will * use the previous renderer and simply resize it. */ public void size(int iwidth, int iheight) { if (g != null) { // just resize the current renderer size(iwidth, iheight, g.getClass().getName()); } else { // create a JAVA2D renderer (the current default) size(iwidth, iheight, JAVA2D); /* if (PApplet.javaVersion >= 1.3f) { try { Class c = Class.forName(JAVA2D); size(iwidth, iheight, JAVA2D); return; } catch (ClassNotFoundException e) { } size(iwidth, iheight, P2D); // fall-through case } */ } } public void size(int iwidth, int iheight, String irenderer) { size(iwidth, iheight, irenderer, null); } /** * Creates a new PGraphics object and sets it to the specified size. *
* Note that you cannot change the renderer once outside of setup(). * In most cases, you can call size() to give it a new size, * but you need to always ask for the same renderer, otherwise * you're gonna run into trouble. *
* XXXX Also note that this calls defaults(), which will reset any * XXXX settings for the font, stroke, fill, colorMode, lights, etc. */ public void size(int iwidth, int iheight, String irenderer, String ipath) { String currentRenderer = (g == null) ? null : g.getClass().getName(); // ensure that this is an absolute path if (ipath != null) ipath = savePath(ipath); if (currentRenderer != null) { if (currentRenderer.equals(irenderer)) { if ((iwidth == g.width) && (iheight == g.height)) { // in this case, size() is being called a second time because // setup() is being called a second time, since the first time // that setup was called, the renderer was changed so an // exception was thrown and setup() didn't complete. but this // time around, g is the proper size and the proper class. // that or size() is being called again for no good reason, // in which case we just ignore it anyway. // so all that needs to be done is to set the defaults // (clear the background, set default strokeWeight, etc). //g.defaults(); // removed this in favor of calling defaults() from beginDraw() // this will happen when P3D or OPENGL are used with size() // inside of setup. it's also safe to call defaults() now, // because it's happening inside setup, which is just frame 0, // meaning that the graphics context is proper and visible. } else { // just resizing, no need to create new graphics object g.resize(iwidth, iheight); updateSize(iwidth, iheight); redraw(); // changed for rev 0100 } // in either case, the renderer is unchanged, so return //return; } else { // renderer is being changed if (frameCount > 0) { throw new RuntimeException("size() cannot be called to change " + "the renderer outside of setup()"); } // otherwise ok to fall through and create renderer below // the renderer is changing, so need to create a new object g = PApplet.createGraphics(iwidth, iheight, irenderer, ipath, this); //g.setMainDrawingSurface(); //if (g != null) { updateSize(iwidth, iheight); //} // throw an exception so that setup() is called again // but with a properly sized render // this is for opengl, which needs a valid, properly sized // display before calling anything inside setup(). throw new RuntimeException(NEW_RENDERER); } } else { // none exists, just create a freshy g = PApplet.createGraphics(iwidth, iheight, irenderer, ipath, this); //g.setMainDrawingSurface(); updateSize(iwidth, iheight); } /* // the renderer is changing, so need to create a new object g = createGraphics(iwidth, iheight, irenderer); //if (g != null) { updateSize(iwidth, iheight); //} //if ((currentRenderer != null) && // !currentRenderer.equals(irenderer)) { if (currentRenderer != null) { // throw an exception so that setup() is called again // but with a properly sized render // this is for opengl, which needs a valid, properly sized // display before calling anything inside setup(). throw new RuntimeException(NEW_RENDERER); } */ } /** * Sets this.width and this.height, unsets defaultSize, and calls * the size() methods inside any libraries. */ protected void updateSize(int iwidth, int iheight) { this.width = iwidth; this.height = iheight; defaultSize = false; // make the applet itself larger.. it's a subclass of Component, // so this is important for when it's embedded inside another app. setSize(width, height); // probably needs to mess with the parent frame here? // TODO wait for a "legitimate size" flag to be set // (meaning that setup has finished properly) // at which time the parent frame will do its thing. // if the default renderer is just being resized, // restore it to its default values //g.defaults(); // no, otherwise fonts that were set in setup() will go away // this has to be called after the exception is thrown, // otherwise the supporting libs won't have a valid context to draw to Object methodArgs[] = new Object[] { new Integer(width), new Integer(height) }; sizeMethods.handle(methodArgs); } /** * Create an offscreen PGraphics object for drawing. This can be used * for bitmap or vector images drawing or rendering. * *
* * PGraphics big; * * void setup() { * big = createGraphics(3000, 3000, P3D); * * big.beginDraw(); * big.background(128); * big.line(20, 1800, 1800, 900); * // etc.. * big.endDraw(); * * // make sure the file is written to the sketch folder * big.save("big.tif"); * } * **
* Examples for key handling: * (Tested on Windows XP, please notify if different on other * platforms, I have a feeling Mac OS and Linux may do otherwise) *
* 1. Pressing 'a' on the keyboard: * keyPressed with key == 'a' and keyCode == 'A' * keyTyped with key == 'a' and keyCode == 0 * keyReleased with key == 'a' and keyCode == 'A' * * 2. Pressing 'A' on the keyboard: * keyPressed with key == 'A' and keyCode == 'A' * keyTyped with key == 'A' and keyCode == 0 * keyReleased with key == 'A' and keyCode == 'A' * * 3. Pressing 'shift', then 'a' on the keyboard (caps lock is off): * keyPressed with key == CODED and keyCode == SHIFT * keyPressed with key == 'A' and keyCode == 'A' * keyTyped with key == 'A' and keyCode == 0 * keyReleased with key == 'A' and keyCode == 'A' * keyReleased with key == CODED and keyCode == SHIFT * * 4. Holding down the 'a' key. * The following will happen several times, * depending on your machine's "key repeat rate" settings: * keyPressed with key == 'a' and keyCode == 'A' * keyTyped with key == 'a' and keyCode == 0 * When you finally let go, you'll get: * keyReleased with key == 'a' and keyCode == 'A' * * 5. Pressing and releasing the 'shift' key * keyPressed with key == CODED and keyCode == SHIFT * keyReleased with key == CODED and keyCode == SHIFT * (note there is no keyTyped) * * 6. Pressing the tab key in an applet with Java 1.4 will * normally do nothing, but PApplet dynamically shuts * this behavior off if Java 1.4 is in use (tested 1.4.2_05 Windows). * Java 1.1 (Microsoft VM) passes the TAB key through normally. * Not tested on other platforms or for 1.3. **/ public void keyPressed() { } /** * See keyPressed(). */ public void keyReleased() { } /** * Only called for "regular" keys like letters, * see keyPressed() for full documentation. */ public void keyTyped() { } ////////////////////////////////////////////////////////////// // i am focused man, and i'm not afraid of death. // and i'm going all out. i circle the vultures in a van // and i run the block. public void focusGained() { } public void focusGained(FocusEvent e) { focused = true; focusGained(); } public void focusLost() { } public void focusLost(FocusEvent e) { focused = false; focusLost(); } ////////////////////////////////////////////////////////////// // getting the time /** * Get the number of milliseconds since the applet started. *
* This is a function, rather than a variable, because it may * change multiple times per frame. */ public int millis() { return (int) (System.currentTimeMillis() - millisOffset); } /** Seconds position of the current time. */ static public int second() { return Calendar.getInstance().get(Calendar.SECOND); } /** Minutes position of the current time. */ static public int minute() { return Calendar.getInstance().get(Calendar.MINUTE); } /** * Hour position of the current time in international format (0-23). *
* To convert this value to American time:
*
int yankeeHour = (hour() % 12); * if (yankeeHour == 0) yankeeHour = 12;*/ static public int hour() { return Calendar.getInstance().get(Calendar.HOUR_OF_DAY); } /** * Get the current day of the month (1 through 31). *
* If you're looking for the day of the week (M-F or whatever)
* or day of the year (1..365) then use java's Calendar.get()
*/
static public int day() {
return Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
}
/**
* Get the current month in range 1 through 12.
*/
static public int month() {
// months are number 0..11 so change to colloquial 1..12
return Calendar.getInstance().get(Calendar.MONTH) + 1;
}
/**
* Get the current year.
*/
static public int year() {
return Calendar.getInstance().get(Calendar.YEAR);
}
//////////////////////////////////////////////////////////////
// controlling time (playing god)
/**
* The delay() function causes the program to halt for a specified time.
* Delay times are specified in thousandths of a second. For example,
* running delay(3000) will stop the program for three seconds and
* delay(500) will stop the program for a half-second. Remember: the
* display window is updated only at the end of draw(), so putting more
* than one delay() inside draw() will simply add them together and the new
* frame will be drawn when the total delay is over.
*
* I'm not sure if this is even helpful anymore, as the screen isn't
* updated before or after the delay, meaning which means it just
* makes the app lock up temporarily.
*/
public void delay(int napTime) {
if (frameCount == 0) return;
if (napTime > 0) {
try {
if (CRUSTY_THREADS) {
Thread.sleep(napTime);
} else {
wait(napTime);
}
} catch (InterruptedException e) { }
}
}
/**
* Set a target frameRate. This will cause delay() to be called
* after each frame so that the sketch synchronizes to a particular speed.
* Note that this only sets the maximum frame rate, it cannot be used to
* make a slow sketch go faster. Sketches have no default frame rate
* setting, and will attempt to use maximum processor power to achieve
* maximum speed.
*/
public void frameRate(float newRateTarget) {
this.frameRateTarget = newRateTarget;
}
//////////////////////////////////////////////////////////////
/**
* Get a param from the web page, or (eventually)
* from a properties file.
*/
public String param(String what) {
if (online) {
return getParameter(what);
} else {
System.err.println("param() only works inside a web browser");
}
return null;
}
/**
* Show status in the status bar of a web browser, or in the
* System.out console. Eventually this might show status in the
* p5 environment itself, rather than relying on the console.
*/
public void status(String what) {
if (online) {
showStatus(what);
} else {
System.out.println(what); // something more interesting?
}
}
public void link(String here) {
link(here, null);
}
/**
* Link to an external page without all the muss.
*
* When run with an applet, uses the browser to open the url, * for applications, attempts to launch a browser with the url. *
* Works on Mac OS X and Windows. For Linux, use: *
open(new String[] { "firefox", url });* or whatever you want as your browser, since Linux doesn't * yet have a standard method for launching URLs. */ public void link(String url, String frameTitle) { if (online) { try { if (frameTitle == null) { getAppletContext().showDocument(new URL(url)); } else { getAppletContext().showDocument(new URL(url), frameTitle); } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("Could not open " + url); } } else { try { if (platform == WINDOWS) { // the following uses a shell execute to launch the .html file // note that under cygwin, the .html files have to be chmodded +x // after they're unpacked from the zip file. i don't know why, // and don't understand what this does in terms of windows // permissions. without the chmod, the command prompt says // "Access is denied" in both cygwin and the "dos" prompt. //Runtime.getRuntime().exec("cmd /c " + currentDir + "\\reference\\" + // referenceFile + ".html"); // replace ampersands with control sequence for DOS. // solution contributed by toxi on the bugs board. url = url.replaceAll("&","^&"); // open dos prompt, give it 'start' command, which will // open the url properly. start by itself won't work since // it appears to need cmd Runtime.getRuntime().exec("cmd /c start " + url); } else if ((platform == MACOSX) || (platform == MACOS9)) { //com.apple.mrj.MRJFileUtils.openURL(url); try { Class mrjFileUtils = Class.forName("com.apple.mrj.MRJFileUtils"); Method openMethod = mrjFileUtils.getMethod("openURL", new Class[] { String.class }); openMethod.invoke(null, new Object[] { url }); } catch (Exception e) { e.printStackTrace(); } } else { //throw new RuntimeException("Can't open URLs for this platform"); // Just pass it off to open() and hope for the best open(url); } } catch (IOException e) { e.printStackTrace(); throw new RuntimeException("Could not open " + url); } } } /** * Attempt to open a file using the platform's shell. */ public void open(String filename) { open(new String[] { filename }); } static String openLauncher; /** * Launch a process using a platforms shell. This version uses an array * to make it easier to deal with spaces in the individual elements. * (This avoids the situation of trying to put single or double quotes * around different bits). */ static public Process open(String argv[]) { String[] params = null; if (platform == WINDOWS) { // just launching the .html file via the shell works // but make sure to chmod +x the .html files first // also place quotes around it in case there's a space // in the user.dir part of the url params = new String[] { "cmd", "/c" }; } else if (platform == MACOSX) { params = new String[] { "open" }; } else if (platform == LINUX) { if (openLauncher == null) { // Attempt to use gnome-open try { Process p = Runtime.getRuntime().exec(new String[] { "gnome-open" }); /*int result =*/ p.waitFor(); // Not installed will throw an IOException (JDK 1.4.2, Ubuntu 7.04) openLauncher = "gnome-open"; } catch (Exception e) { } } if (openLauncher == null) { // Attempt with kde-open try { Process p = Runtime.getRuntime().exec(new String[] { "kde-open" }); /*int result =*/ p.waitFor(); openLauncher = "kde-open"; } catch (Exception e) { } } if (openLauncher == null) { System.err.println("Could not find gnome-open or kde-open, " + "the open() command may not work."); } if (openLauncher != null) { params = new String[] { openLauncher }; } //} else { // give up and just pass it to Runtime.exec() //open(new String[] { filename }); //params = new String[] { filename }; } if (params != null) { // If the 'open', 'gnome-open' or 'cmd' are already included if (params[0].equals(argv[0])) { // then don't prepend those params again return exec(argv); } else { params = concat(params, argv); return exec(params); } } else { return exec(argv); } } static public Process exec(String[] argv) { try { return Runtime.getRuntime().exec(argv); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("Could not open " + join(argv, ' ')); } } /* try { Runtime.getRuntime().exec("cmd /c \"" + filename + "\""); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException("Could not open " + filename); } try { return Runtime.getRuntime().exec(argv); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("Could not open " + join(argv, ' ')); } } /* static protected String findLinuxLauncher() { if (linuxLauncher == null) { // Attempt to use gnome-open try { Process p = Runtime.getRuntime().exec(new String[] { "gnome-open" }); int result = p.waitFor(); // Not installed will throw an IOException (JDK 1.4.2, Ubuntu 7.04) linuxLauncher = "gnome-open"; } catch (Exception e) { } // Attempt with kde-open try { Process p = Runtime.getRuntime().exec(new String[] { "kde-open" }); int result = p.waitFor(); linuxLauncher = "kde-open"; } catch (Exception e) { } } if (linuxLauncher == null) { System.err.println("Could not find gnome-open or kde-open, " + "the open() command may not work."); } return linuxLauncher; } */ ////////////////////////////////////////////////////////////// /** * Function for an applet/application to kill itself and * display an error. Mostly this is here to be improved later. */ public void die(String what) { stop(); throw new RuntimeException(what); /* if (online) { System.err.println("i'm dead.. " + what); } else { System.err.println(what); System.exit(1); } */ } /** * Same as above but with an exception. Also needs work. */ public void die(String what, Exception e) { if (e != null) e.printStackTrace(); die(what); } /** * Call to safely exit the sketch when finished. For instance, * to render a single frame, save it, and quit. */ public void exit() { if (thread == null) { // exit immediately, stop() has already been called, // meaning that the main thread has long since exited if ((leechErr == null) && !online) { // don't want to call System.exit() when an applet, // or running inside the PDE (would kill the PDE) System.exit(0); } } else { finished = true; // stop() will be called as the thread exits //stop(); exit = true; } } ////////////////////////////////////////////////////////////// // SCREEN GRABASS /** * Intercepts any relative paths to make them absolute (relative * to the sketch folder) before passing to save() in PImage. * (Changed in 0100) */ public void save(String filename) { g.save(savePath(filename)); } /** * Grab an image of what's currently in the drawing area and save it * as a .tif or .tga file. *
* Best used just before endDraw() at the end of your draw(). * This can only create .tif or .tga images, so if neither extension * is specified it defaults to writing a tiff and adds a .tif suffix. */ public void saveFrame() { if (online) { System.err.println("Can't use saveFrame() when running in a browser."); return; } //File file = new File(folder, "screen-" + nf(frame, 4) + ".tif"); //save(savePath("screen-" + nf(frameCount, 4) + ".tif")); //save("screen-" + nf(frame, 4) + ".tif"); g.save(savePath("screen-" + nf(frameCount, 4) + ".tif")); } /** * Save the current frame as a .tif or .tga image. *
* The String passed in can contain a series of # signs * that will be replaced with the screengrab number. *
* i.e. saveFrame("blah-####.tif"); * // saves a numbered tiff image, replacing the * // #### signs with zeros and the frame number*/ public void saveFrame(String what) { if (online) { System.err.println("Can't use saveFrame() when running in a browser."); return; } g.save(savePath(insertFrame(what))); /* int first = what.indexOf('#'); int last = what.lastIndexOf('#'); if (first == -1) { g.save(savePath(what)); } else { String prefix = what.substring(0, first); int count = last - first + 1; String suffix = what.substring(last + 1); g.save(savePath(prefix + nf(frameCount, count) + suffix)); } */ } ////////////////////////////////////////////////////////////// // CURSOR // int cursorType = ARROW; // cursor type boolean cursorVisible = true; // cursor visibility flag PImage invisibleCursor; /** * Set the cursor type */ public void cursor(int _cursor_type) { setCursor(Cursor.getPredefinedCursor(_cursor_type)); cursorVisible = true; cursorType = _cursor_type; } /** * Replace the cursor with the specified PImage. The x- and y- * coordinate of the center will be the center of the image. */ public void cursor(PImage image) { cursor(image, image.width/2, image.height/2); } /** * Set a custom cursor to an image with a specific hotspot. * Only works with JDK 1.2 and later. * Currently seems to be broken on Java 1.4 for Mac OS X *
* Based on code contributed by Amit Pitaru, plus additional * code to handle Java versions via reflection by Jonathan Feinberg. */ public void cursor(PImage image, int hotspotX, int hotspotY) { if (javaVersion < 1.2f) { System.err.println("Java 1.2 or higher is required to use cursor()"); System.err.println("(You're using version " + javaVersionName + ")"); return; } // don't set this as cursor type, instead use cursor_type // to save the last cursor used in case cursor() is called //cursor_type = Cursor.CUSTOM_CURSOR; Image jimage = createImage(new MemoryImageSource(image.width, image.height, image.pixels, 0, image.width)); Point hotspot = new Point(hotspotX, hotspotY); try { Method mCustomCursor = Toolkit.class.getMethod("createCustomCursor", new Class[] { Image.class, Point.class, String.class, }); Cursor cursor = (Cursor)mCustomCursor.invoke(Toolkit.getDefaultToolkit(), new Object[] { jimage, hotspot, "no cursor" }); setCursor(cursor); cursorVisible = true; } catch (NoSuchMethodError e) { System.err.println("cursor() is not available " + "when using Java " + javaVersionName); } catch (IndexOutOfBoundsException e) { System.err.println("cursor() error: the hotspot " + hotspot + " is out of bounds for the given image."); } catch (Exception e) { System.err.println(e); } } /** * Show the cursor after noCursor() was called. * Notice that the program remembers the last set cursor type */ public void cursor() { // maybe should always set here? seems dangerous, since // 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 (!cursorVisible) { cursorVisible = true; setCursor(Cursor.getPredefinedCursor(cursorType)); } } /** * Hide the cursor by creating a transparent image * and using it as a custom cursor. */ public void noCursor() { if (!cursorVisible) return; // don't hide if already hidden. 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(invisibleCursor, 0, 0); cursorVisible = false; } ////////////////////////////////////////////////////////////// static public void print(byte what) { System.out.print(what); System.out.flush(); } static public void print(boolean what) { System.out.print(what); System.out.flush(); } static public void print(char what) { System.out.print(what); System.out.flush(); } static public void print(int what) { System.out.print(what); System.out.flush(); } static public void print(float what) { System.out.print(what); System.out.flush(); } /* static public void print(double what) { System.out.print(what); System.out.flush(); } */ static public void print(String what) { System.out.print(what); System.out.flush(); } static public void print(Object what) { if (what == null) { // special case since this does fuggly things on > 1.1 System.out.print("null"); } else { System.out.println(what.toString()); } /* String name = what.getClass().getName(); if (name.charAt(0) == '[') { switch (name.charAt(1)) { case '[': // don't even mess with multi-dimensional arrays (case '[') // or anything else that's not int, float, boolean, char System.out.print(what); System.out.print(' '); break; case 'L': // print a 1D array of objects as individual elements Object poo[] = (Object[]) what; for (int i = 0; i < poo.length; i++) { System.out.print(poo[i]); System.out.print(' '); } break; case 'Z': // boolean boolean zz[] = (boolean[]) what; for (int i = 0; i < zz.length; i++) { System.out.print(zz[i]); System.out.print(' '); } break; case 'B': // byte byte bb[] = (byte[]) what; for (int i = 0; i < bb.length; i++) { System.out.print(bb[i]); System.out.print(' '); } break; case 'C': // char char cc[] = (char[]) what; for (int i = 0; i < cc.length; i++) { System.out.print(cc[i]); System.out.print(' '); } break; case 'I': // int int ii[] = (int[]) what; for (int i = 0; i < ii.length; i++) { System.out.print(ii[i]); System.out.print(' '); } break; case 'F': // float float ff[] = (float[]) what; for (int i = 0; i < ff.length; i++) { System.out.print(ff[i]); System.out.print(' '); } break; case 'D': // double double dd[] = (double[]) what; for (int i = 0; i < dd.length; i++) { System.out.print(dd[i]); System.out.print(' '); } break; default: System.out.print(what); } } else { System.out.print(what); //.toString()); } */ } // static public void println() { System.out.println(); } // static public void println(byte what) { print(what); System.out.println(); } static public void println(boolean what) { print(what); System.out.println(); } static public void println(char what) { print(what); System.out.println(); } static public void println(int what) { print(what); System.out.println(); } static public void println(float what) { print(what); System.out.println(); } /* static public void println(double what) { print(what); System.out.println(); } */ static public void println(String what) { print(what); System.out.println(); } static public void println(Object what) { if (what == null) { // special case since this does fuggly things on > 1.1 System.out.println("null"); } else { String name = what.getClass().getName(); if (name.charAt(0) == '[') { switch (name.charAt(1)) { case '[': // don't even mess with multi-dimensional arrays (case '[') // or anything else that's not int, float, boolean, char System.out.println(what); break; case 'L': // print a 1D array of objects as individual elements Object poo[] = (Object[]) what; for (int i = 0; i < poo.length; i++) { if (poo[i] instanceof String) { System.out.println("[" + i + "] \"" + poo[i] + "\""); } else { System.out.println("[" + i + "] " + poo[i]); } } break; case 'Z': // boolean boolean zz[] = (boolean[]) what; for (int i = 0; i < zz.length; i++) { System.out.println("[" + i + "] " + zz[i]); } break; case 'B': // byte byte bb[] = (byte[]) what; for (int i = 0; i < bb.length; i++) { System.out.println("[" + i + "] " + bb[i]); } break; case 'C': // char char cc[] = (char[]) what; for (int i = 0; i < cc.length; i++) { System.out.println("[" + i + "] '" + cc[i] + "'"); } break; case 'I': // int int ii[] = (int[]) what; for (int i = 0; i < ii.length; i++) { System.out.println("[" + i + "] " + ii[i]); } break; case 'F': // float float ff[] = (float[]) what; for (int i = 0; i < ff.length; i++) { System.out.println("[" + i + "] " + ff[i]); } break; /* case 'D': // double double dd[] = (double[]) what; for (int i = 0; i < dd.length; i++) { System.out.println("[" + i + "] " + dd[i]); } break; */ default: System.out.println(what); } } else { // not an array System.out.println(what); } } } // /* // not very useful, because it only works for public (and protected?) // fields of a class, not local variables to methods public void printvar(String name) { try { Field field = getClass().getDeclaredField(name); println(name + " = " + field.get(this)); } catch (Exception e) { e.printStackTrace(); } } */ ////////////////////////////////////////////////////////////// // MATH // lots of convenience methods for math with floats. // doubles are overkill for processing applets, and casting // things all the time is annoying, thus the functions below. static public final float abs(float n) { return (n < 0) ? -n : n; } static public final int abs(int n) { return (n < 0) ? -n : n; } static public final float sq(float a) { return a*a; } static public final float sqrt(float a) { return (float)Math.sqrt(a); } static public final float log(float a) { return (float)Math.log(a); } static public final float exp(float a) { return (float)Math.exp(a); } static public final float pow(float a, float b) { return (float)Math.pow(a, b); } static public final int max(int a, int b) { return (a > b) ? a : b; } static public final float max(float a, float b) { return (a > b) ? a : b; } static public final int max(int a, int b, int c) { return (a > b) ? ((a > c) ? a : c) : ((b > c) ? b : c); } static public final float max(float a, float b, float c) { return (a > b) ? ((a > c) ? a : c) : ((b > c) ? b : c); } /** * Find the maximum value in an array. * @param list the source array * @return The maximum value, or 0 if the array is length zero. */ static public final int max(int[] list) { if (list.length == 0) { return 0; } int max = list[0]; for (int i = 1; i < list.length; i++) { if (list[i] > max) max = list[i]; } return max; } /** * Find the maximum value in an array. * @param list the source array * @return The maximum value, or Float.NaN if the array is length zero. */ static public final float max(float[] list) { if (list.length == 0) { return Float.NaN; } float max = list[0]; for (int i = 1; i < list.length; i++) { if (list[i] > max) max = list[i]; } return max; } static public final int min(int a, int b) { return (a < b) ? a : b; } static public final float min(float a, float b) { return (a < b) ? a : b; } static public final int min(int a, int b, int c) { return (a < b) ? ((a < c) ? a : c) : ((b < c) ? b : c); } static public final float min(float a, float b, float c) { return (a < b) ? ((a < c) ? a : c) : ((b < c) ? b : c); } /** * Find the minimum value in an array. * @param list the source array * @return The minimum value, or 0 if the array is length zero. */ static public final int min(int[] list) { if (list.length == 0) { return 0; } int min = list[0]; for (int i = 1; i < list.length; i++) { if (list[i] < min) min = list[i]; } return min; } /** * Find the minimum value in an array. * @param list the source array * @return The minimum value, or Float.NaN if the array is length zero. */ static public final float min(float[] list) { if (list.length == 0) { return Float.NaN; } float min = list[0]; for (int i = 1; i < list.length; i++) { if (list[i] < min) min = list[i]; } return min; } static public final int constrain(int amt, int low, int high) { return (amt < low) ? low : ((amt > high) ? high : amt); } static public final float constrain(float amt, float low, float high) { return (amt < low) ? low : ((amt > high) ? high : amt); } static public final float sin(float angle) { return (float)Math.sin(angle); } static public final float cos(float angle) { return (float)Math.cos(angle); } static public final float tan(float angle) { return (float)Math.tan(angle); } static public final float asin(float value) { return (float)Math.asin(value); } static public final float acos(float value) { return (float)Math.acos(value); } static public final float atan(float value) { return (float)Math.atan(value); } static public final float atan2(float a, float b) { return (float)Math.atan2(a, b); } static public final float degrees(float radians) { return radians * RAD_TO_DEG; } static public final float radians(float degrees) { return degrees * DEG_TO_RAD; } static public final int ceil(float what) { return (int) Math.ceil(what); } static public final int floor(float what) { return (int) Math.floor(what); } static public final int round(float what) { return (int) Math.round(what); } static public final float mag(float a, float b) { return (float)Math.sqrt(a*a + b*b); } static public final float mag(float a, float b, float c) { return (float)Math.sqrt(a*a + b*b + c*c); } static public final float dist(float x1, float y1, float x2, float y2) { return sqrt(sq(x2-x1) + sq(y2-y1)); } static public final float dist(float x1, float y1, float z1, float x2, float y2, float z2) { return sqrt(sq(x2-x1) + sq(y2-y1) + sq(z2-z1)); } static public final float lerp(float start, float stop, float amt) { return start + (stop-start) * amt; } /** * Normalize a value to exist between 0 and 1 (inclusive). * Mathematically the opposite of lerp(), figures out what proportion * a particular value is relative to start and stop coordinates. */ static public final float norm(float value, float start, float stop) { return (value - start) / (stop - start); } /** * Convenience function to map a variable from one coordinate space * to another. Equivalent to unlerp() followed by lerp(). */ static public final float map(float value, float istart, float istop, float ostart, float ostop) { return ostart + (ostop - ostart) * ((value - istart) / (istop - istart)); } ////////////////////////////////////////////////////////////// // RANDOM NUMBERS Random internalRandom; /** * Return a random number in the range [0, howbig). *
* The number returned will range from zero up to * (but not including) 'howbig'. */ public final float random(float howbig) { // for some reason (rounding error?) Math.random() * 3 // can sometimes return '3' (once in ~30 million tries) // so a check was added to avoid the inclusion of 'howbig' // avoid an infinite loop if (howbig == 0) return 0; // internal random number object if (internalRandom == null) internalRandom = new Random(); float value = 0; do { //value = (float)Math.random() * howbig; value = internalRandom.nextFloat() * howbig; } while (value == howbig); return value; } /** * Return a random number in the range [howsmall, howbig). *
* The number returned will range from 'howsmall' up to * (but not including 'howbig'. *
* If howsmall is >= howbig, howsmall will be returned,
* meaning that random(5, 5) will return 5 (useful)
* and random(7, 4) will return 7 (not useful.. better idea?)
*/
public final float random(float howsmall, float howbig) {
if (howsmall >= howbig) return howsmall;
float diff = howbig - howsmall;
return random(diff) + howsmall;
}
public final void randomSeed(long what) {
// internal random number object
if (internalRandom == null) internalRandom = new Random();
internalRandom.setSeed(what);
}
//////////////////////////////////////////////////////////////
// PERLIN NOISE
// [toxi 040903]
// octaves and amplitude amount per octave are now user controlled
// via the noiseDetail() function.
// [toxi 030902]
// cleaned up code and now using bagel's cosine table to speed up
// [toxi 030901]
// implementation by the german demo group farbrausch
// as used in their demo "art": http://www.farb-rausch.de/fr010src.zip
static final int PERLIN_YWRAPB = 4;
static final int PERLIN_YWRAP = 1<
* Generally, loadImage() should only be used during setup, because
* re-loading images inside draw() is likely to cause a significant
* delay while memory is allocated and the thread blocks while waiting
* for the image to load because loading is not asynchronous.
*
* To load several images asynchronously, see more information in the
* FAQ about writing your own threaded image loading method.
*
* As of 0096, returns null if no image of that name is found,
* rather than an error.
*
* Release 0115 also provides support for reading TIFF and RLE-encoded
* Targa (.tga) files written by Processing via save() and saveFrame().
* Other TIFF and Targa files will probably not load, use a different
* format (gif, jpg and png are safest bets) when creating images with
* another application to use with Processing.
*
* Also in release 0115, more image formats (BMP and others) can
* be read when using Java 1.4 and later. Because many people still
* use Java 1.1 and 1.3, these formats are not recommended for
* 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:
*
* Rewritten for 0115 to read/write RLE-encoded targa images.
* For 0125, non-RLE encoded images are now supported, along with
* images whose y-order is reversed (which is standard for TGA files).
*/
protected PImage loadImageTGA(String filename) throws IOException {
InputStream is = openStream(filename);
if (is == null) return null;
byte header[] = new byte[18];
int offset = 0;
do {
int count = is.read(header, offset, header.length - offset);
if (count == -1) return null;
offset += count;
} while (offset < 18);
/*
header[2] image type code
2 (0x02) - Uncompressed, RGB images.
3 (0x03) - Uncompressed, black and white images.
10 (0x0A) - Runlength encoded RGB images.
11 (0x0B) - Compressed, black and white images. (grayscale?)
header[16] is the bit depth (8, 24, 32)
header[17] image descriptor (packed bits)
0x20 is 32 = origin upper-left
0x28 is 32 + 8 = origin upper-left + 32 bits
7 6 5 4 3 2 1 0
128 64 32 16 8 4 2 1
*/
int format = 0;
if (((header[2] == 3) || (header[2] == 11)) && // B&W, plus RLE or not
(header[16] == 8) && // 8 bits
((header[17] == 0x8) || (header[17] == 0x28))) { // origin, 32 bit
format = ALPHA;
} else if (((header[2] == 2) || (header[2] == 10)) && // RGB, RLE or not
(header[16] == 24) && // 24 bits
((header[17] == 0x20) || (header[17] == 0))) { // origin
format = RGB;
} else if (((header[2] == 2) || (header[2] == 10)) &&
(header[16] == 32) &&
((header[17] == 0x8) || (header[17] == 0x28))) { // origin, 32
format = ARGB;
}
if (format == 0) {
System.err.println("Unknown .tga file format for " + filename);
//" (" + header[2] + " " +
//(header[16] & 0xff) + " " +
//hex(header[17], 2) + ")");
return null;
}
int w = ((header[13] & 0xff) << 8) + (header[12] & 0xff);
int h = ((header[15] & 0xff) << 8) + (header[14] & 0xff);
PImage outgoing = createImage(w, h, format);
boolean reversed = (header[17] & 0x20) != 0;
if ((header[2] == 2) || (header[2] == 3)) { // not RLE encoded
if (reversed) {
int index = (h-1) * w;
switch (format) {
case ALPHA:
for (int y = h-1; y >= 0; y--) {
for (int x = 0; x < w; x++) {
outgoing.pixels[index + x] = is.read();
}
index -= w;
}
break;
case RGB:
for (int y = h-1; y >= 0; y--) {
for (int x = 0; x < w; x++) {
outgoing.pixels[index + x] =
is.read() | (is.read() << 8) | (is.read() << 16) |
0xff000000;
}
index -= w;
}
break;
case ARGB:
for (int y = h-1; y >= 0; y--) {
for (int x = 0; x < w; x++) {
outgoing.pixels[index + x] =
is.read() | (is.read() << 8) | (is.read() << 16) |
(is.read() << 24);
}
index -= w;
}
}
} else { // not reversed
int count = w * h;
switch (format) {
case ALPHA:
for (int i = 0; i < count; i++) {
outgoing.pixels[i] = is.read();
}
break;
case RGB:
for (int i = 0; i < count; i++) {
outgoing.pixels[i] =
is.read() | (is.read() << 8) | (is.read() << 16) |
0xff000000;
}
break;
case ARGB:
for (int i = 0; i < count; i++) {
outgoing.pixels[i] =
is.read() | (is.read() << 8) | (is.read() << 16) |
(is.read() << 24);
}
break;
}
}
} else { // header[2] is 10 or 11
int index = 0;
int px[] = outgoing.pixels;
while (index < px.length) {
int num = is.read();
boolean isRLE = (num & 0x80) != 0;
if (isRLE) {
num -= 127; // (num & 0x7F) + 1
int pixel = 0;
switch (format) {
case ALPHA:
pixel = is.read();
break;
case RGB:
pixel = 0xFF000000 |
is.read() | (is.read() << 8) | (is.read() << 16);
//(is.read() << 16) | (is.read() << 8) | is.read();
break;
case ARGB:
pixel = is.read() |
(is.read() << 8) | (is.read() << 16) | (is.read() << 24);
break;
}
for (int i = 0; i < num; i++) {
px[index++] = pixel;
if (index == px.length) break;
}
} else { // write up to 127 bytes as uncompressed
num += 1;
switch (format) {
case ALPHA:
for (int i = 0; i < num; i++) {
px[index++] = is.read();
}
break;
case RGB:
for (int i = 0; i < num; i++) {
px[index++] = 0xFF000000 |
is.read() | (is.read() << 8) | (is.read() << 16);
//(is.read() << 16) | (is.read() << 8) | is.read();
}
break;
case ARGB:
for (int i = 0; i < num; i++) {
px[index++] = is.read() | //(is.read() << 24) |
(is.read() << 8) | (is.read() << 16) | (is.read() << 24);
//(is.read() << 16) | (is.read() << 8) | is.read();
}
break;
}
}
}
if (reversed) {
int[] temp = new int[w];
for (int y = 0; y < h/2; y++) {
int z = (h-1) - y;
System.arraycopy(px, y*w, temp, 0, w);
System.arraycopy(px, z*w, px, y*w, w);
System.arraycopy(temp, 0, px, z*w, w);
}
}
}
return outgoing;
}
//////////////////////////////////////////////////////////////
// FONT I/O
/*
Hashtable fontTable;
*/
/**
* Set the font based on its filename. This is less than efficient
* than using loadFont because there's no way to unload it from memory,
* but it's useful for beginners.
*/
/*
public void textFont(String filename) {
if (filename.toLowerCase().indexOf(".vlw") == -1) {
System.err.println("textFont() needs the filename of a .vlw font");
} else {
textFont(tableFont(filename));
}
}
*/
/**
* Set the font based on its filename. This is less than efficient
* than using loadFont because there's no way to unload it from memory,
* but it's useful for beginners.
*/
/*
public void textFont(String filename, float size) {
if (filename.toLowerCase().indexOf(".vlw") == -1) {
System.err.println("textFont() needs the filename of a .vlw font");
} else {
textFont(tableFont(filename), size);
}
}
*/
/*
protected PFont tableFont(String filename) {
if (fontTable == null) fontTable = new Hashtable();
PFont font = (PFont) fontTable.get(filename);
if (font != null) return font;
font = loadFont(filename);
return font;
}
*/
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public PFont loadFont(String filename) {
//if (g == null) { // just for good measure
//die("loadFont() only be used inside setup() or draw()");
//}
try {
String lower = filename.toLowerCase();
InputStream input = openStream(filename);
// For compatability with earlier releases of Processing
if (lower.endsWith(".vlw.gz")) {
input = new GZIPInputStream(input);
} else if (!lower.endsWith(".vlw")) {
// this gets thrown down below
throw new IOException("I don't know how to load a font named " +
filename);
}
return new PFont(input);
} catch (Exception e) {
die("Could not load font " + filename + ". " +
"Make sure that the font has been copied " +
"to the data folder of your sketch.", e);
}
return null;
}
public PFont createFont(String name, float size) {
return createFont(name, size, true, PFont.DEFAULT_CHARSET);
}
public PFont createFont(String name, float size, boolean smooth) {
return createFont(name, size, smooth, PFont.DEFAULT_CHARSET);
}
/**
* Create a .vlw font on the fly from either a font name that's
* installed on the system, or from a .ttf or .otf that's inside
* the data folder of this sketch.
*
* The parentFrame is the Frame that will guide the placement of
* the prompt window. If no Frame is available, just pass in null.
*/
// can't be static because it wants a host component
static public File inputFile(String prompt, Frame parentFrame) {
if (parentFrame == null) parentFrame = new Frame();
FileDialog fd = new FileDialog(parentFrame, prompt, FileDialog.LOAD);
fd.setVisible(true);
String directory = fd.getDirectory();
String filename = fd.getFile();
if (filename == null) return null;
return new File(directory, filename);
}
public File outputFile() {
return outputFile("Save as...");
}
public File outputFile(String prompt) {
Frame parentFrame = null;
Component comp = getParent();
while (comp != null) {
//System.out.println(comp + " " + comp.getClass());
if (comp instanceof Frame) {
parentFrame = (Frame) comp;
break;
}
comp = comp.getParent();
}
return outputFile(prompt, parentFrame);
}
static public File outputFile(Frame parentFrame) {
return outputFile("Save as...", parentFrame);
}
/**
* static version of outputFile usable by external classes.
*
* The parentFrame is the Frame that will guide the placement of
* the prompt window. If no Frame is available, just pass in null.
*/
static public File outputFile(String prompt, Frame parentFrame) {
if (parentFrame == null) parentFrame = new Frame();
FileDialog fd = new FileDialog(parentFrame, prompt, FileDialog.SAVE);
fd.setVisible(true);
String directory = fd.getDirectory();
String filename = fd.getFile();
if (filename == null) return null;
return new File(directory, filename);
}
/**
* I want to read lines from a file. I have RSI from typing these
* eight lines of code so many times.
*/
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 createReader(is);
} catch (Exception e) {
if (filename == null) {
System.err.println("Filename passed to reader() was null");
} else {
System.err.println("Couldn't create a reader for " + filename);
}
}
return null;
}
/**
* I want to read lines from a file. And I'm still annoyed.
*/
static public BufferedReader createReader(File file) {
try {
return createReader(new FileInputStream(file));
} catch (Exception e) {
if (file == null) {
throw new RuntimeException("File passed to reader() was null");
} else {
e.printStackTrace();
throw new RuntimeException("Couldn't create a reader for " +
file.getAbsolutePath());
}
}
//return null;
}
/**
* 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 createReader(InputStream input) {
InputStreamReader isr = new InputStreamReader(input);
return new BufferedReader(isr);
}
/**
* decode a gzip input stream
*/
static public InputStream gzipInput(InputStream input) {
try {
return new GZIPInputStream(input);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("Problem with gzip input");
}
//return null;
}
/**
* decode a gzip output stream
*/
static public OutputStream gzipOutput(OutputStream output) {
try {
return new GZIPOutputStream(output);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("Problem with gzip output");
}
//return null;
}
/**
* I want to print lines to a file. Why can't I?
*/
public PrintWriter createWriter(String filename) {
try {
return createWriter(new FileOutputStream(savePath(filename)));
} catch (Exception e) {
if (filename == null) {
die("Filename passed to writer() was null", e);
} else {
die("Couldn't create a writer for " + filename, e);
}
}
return null;
}
/**
* I want to print lines to a file. I have RSI from typing these
* eight lines of code so many times.
*/
static public PrintWriter createWriter(File file) {
try {
return createWriter(new FileOutputStream(file));
} catch (Exception e) {
if (file == null) {
throw new RuntimeException("File passed to writer() was null");
} else {
e.printStackTrace();
throw new RuntimeException("Couldn't create a writer for " +
file.getAbsolutePath());
}
}
//return null;
}
/**
* 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 createWriter(OutputStream output) {
OutputStreamWriter osw = new OutputStreamWriter(output);
return new PrintWriter(osw);
}
/**
* Simplified method to open a Java InputStream.
*
* This method is useful if you want to use the facilities provided
* by PApplet to easily open things from the data folder or from a URL,
* but want an InputStream object so that you can use other Java
* methods to take more control of how the stream is read.
*
* If the requested item doesn't exist, null is returned.
* (Prior to 0096, die() would be called, killing the applet)
*
* For 0096+, the "data" folder is exported intact with subfolders,
* and openStream() properly handles subdirectories from the data folder
*
* If not online, this will also check to see if the user is asking
* for a file whose name isn't properly capitalized. This helps prevent
* issues when a sketch is exported to the web, where case sensitivity
* matters, as opposed to Windows and the Mac OS default where
* case sensitivity is preserved but ignored.
*
* It is strongly recommended that libraries use this method to open
* data files, so that the loading sequence is handled in the same way
* as functions like loadBytes(), loadImage(), etc.
*
* The filename passed in can be:
*
* Exceptions are handled internally, when an error, occurs, an
* exception is printed to the console and 'null' is returned,
* but the program continues running. This is a tradeoff between
* 1) showing the user that there was a problem but 2) not requiring
* that all i/o code is contained in try/catch blocks, for the sake
* of new users (or people who are just trying to get things done
* in a "scripting" fashion. If you want to handle exceptions,
* use Java methods for I/O.
*/
public String[] loadStrings(String filename) {
InputStream is = openStream(filename);
if (is != null) return loadStrings(is);
System.err.println("The file \"" + filename + "\" " +
"is missing or inaccessible, make sure " +
"the URL is valid or that the file has been " +
"added to your sketch and is readable.");
return null;
}
static public String[] loadStrings(InputStream input) {
try {
BufferedReader reader =
new BufferedReader(new InputStreamReader(input));
String lines[] = new String[100];
int lineCount = 0;
String line = null;
while ((line = reader.readLine()) != null) {
if (lineCount == lines.length) {
String temp[] = new String[lineCount << 1];
System.arraycopy(lines, 0, temp, 0, lineCount);
lines = temp;
}
lines[lineCount++] = line;
}
reader.close();
if (lineCount == lines.length) {
return lines;
}
// resize array to appropriate amount for these lines
String output[] = new String[lineCount];
System.arraycopy(lines, 0, output, 0, lineCount);
return output;
} catch (IOException e) {
e.printStackTrace();
//throw new RuntimeException("Error inside loadStrings()");
}
return null;
}
//////////////////////////////////////////////////////////////
// FILE OUTPUT
/**
* Save the contents of a stream to a file in the sketch folder.
* This is basically saveBytes(loadBytes(), blah), but done
* in a less confusing manner.
*/
public void saveStream(String filename, String stream) {
saveBytes(filename, loadBytes(stream));
}
/**
* Identical to the other saveStream(), but writes to a File
* object, for greater control over the file location.
*/
public void saveStream(File file, String stream) {
saveBytes(file, loadBytes(stream));
}
/**
* Saves bytes to a file to inside the sketch folder.
* The filename can be a relative path, i.e. "poo/bytefun.txt"
* would save to a file named "bytefun.txt" to a subfolder
* called 'poo' inside the sketch folder. If the in-between
* subfolders don't exist, they'll be created.
*/
public void saveBytes(String filename, byte buffer[]) {
try {
String location = savePath(filename);
FileOutputStream fos = new FileOutputStream(location);
saveBytes(fos, buffer);
fos.close();
} catch (IOException e) {
System.err.println("error saving bytes to " + filename);
e.printStackTrace();
}
}
/**
* Saves bytes to a specific File location specified by the user.
*/
static public void saveBytes(File file, byte buffer[]) {
try {
String filename = file.getAbsolutePath();
createPath(filename);
FileOutputStream fos = new FileOutputStream(file);
saveBytes(fos, buffer);
fos.close();
} catch (IOException e) {
System.err.println("error saving bytes to " + file);
e.printStackTrace();
}
}
/**
* Spews a buffer of bytes to an OutputStream.
*/
static public void saveBytes(OutputStream output, byte buffer[]) {
try {
//BufferedOutputStream bos = new BufferedOutputStream(output);
output.write(buffer);
output.flush();
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("Couldn't save bytes");
}
}
//
public void saveStrings(String filename, String strings[]) {
try {
String location = savePath(filename);
FileOutputStream fos = new FileOutputStream(location);
saveStrings(fos, strings);
fos.close();
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("saveStrings() failed: " + e.getMessage());
}
}
static public void saveStrings(File file, String strings[]) {
try {
String location = file.getAbsolutePath();
createPath(location);
FileOutputStream fos = new FileOutputStream(location);
saveStrings(fos, strings);
fos.close();
} catch (IOException e) {
System.err.println("error while saving strings");
e.printStackTrace();
}
}
static public void saveStrings(OutputStream output, String strings[]) {
PrintWriter writer =
new PrintWriter(new OutputStreamWriter(output));
for (int i = 0; i < strings.length; i++) {
writer.println(strings[i]);
}
writer.flush();
}
//////////////////////////////////////////////////////////////
/**
* Prepend the sketch folder path to the filename (or path) that is
* passed in. External libraries should use this function to save to
* the sketch folder.
*
* In this method, the data path is defined not as the applet's actual
* data path, but a folder titled "data" in the sketch's working
* directory. This is because in an application, the "data" folder is
* exported as part of the jar file, and it's not as though you're gonna
* write into the jar file itself. If you need to get things out of
* the jar file, you should use openStream().
*/
public String dataPath(String where) {
// isAbsolute() could throw an access exception, but so will writing
// to the local disk using the sketch path, so this is safe here.
if (new File(where).isAbsolute()) return where;
return sketchPath + File.separator + "data" + File.separator + where;
}
/**
* Takes a path and creates any in-between folders if they don't
* already exist. Useful when trying to save to a subfolder that
* may not actually exist.
*/
static public void createPath(String filename) {
File file = new File(filename);
String parent = file.getParent();
if (parent != null) {
File unit = new File(parent);
if (!unit.exists()) unit.mkdirs();
}
}
//////////////////////////////////////////////////////////////
// SORT
int sort_mode;
static final int BYTES = 1;
static final int CHARS = 2;
static final int INTS = 3;
static final int FLOATS = 4;
static final int STRINGS = 5;
static final int OBJECTS = 6;
byte sort_bytes[];
char sort_chars[];
int sort_ints[];
float sort_floats[];
String sort_strings[];
Object sortObject;
Method swapMethod;
Method compareMethod;
public byte[] sort(byte what[]) {
return sort(what, what.length);
}
public char[] sort(char what[]) {
return sort(what, what.length);
}
public int[] sort(int what[]) {
return sort(what, what.length);
}
public float[] sort(float what[]) {
return sort(what, what.length);
}
public String[] sort(String what[]) {
return sort(what, what.length);
}
//
public byte[] sort(byte what[], int count) {
if (count == 0) return null;
sort_mode = BYTES;
sort_bytes = new byte[count];
System.arraycopy(what, 0, sort_bytes, 0, count);
sort_internal(0, count-1);
return sort_bytes;
}
public char[] sort(char what[], int count) {
if (count == 0) return null;
sort_mode = CHARS;
sort_chars = new char[count];
System.arraycopy(what, 0, sort_chars, 0, count);
sort_internal(0, count-1);
return sort_chars;
}
public int[] sort(int what[], int count) {
if (count == 0) return null;
sort_mode = INTS;
sort_ints = new int[count];
System.arraycopy(what, 0, sort_ints, 0, count);
sort_internal(0, count-1);
return sort_ints;
}
public float[] sort(float what[], int count) {
if (count == 0) return null;
sort_mode = FLOATS;
sort_floats = new float[count];
System.arraycopy(what, 0, sort_floats, 0, count);
sort_internal(0, count-1);
return sort_floats;
}
public String[] sort(String what[], int count) {
if (count == 0) return null;
sort_mode = STRINGS;
sort_strings = new String[count];
System.arraycopy(what, 0, sort_strings, 0, count);
sort_internal(0, count-1);
return sort_strings;
}
/*
public void sort(Object what, int count) {
if (count == 0) return null;
sort_mode = OBJECTS;
sort_strings = new String[count];
System.arraycopy(what, 0, sort_strings, 0, count);
sort_internal(0, count-1);
return sort_strings;
}
*/
//
protected void sort_internal(int i, int j) {
int pivotIndex = (i+j)/2;
sort_swap(pivotIndex, j);
int k = sort_partition(i-1, j);
sort_swap(k, j);
if ((k-i) > 1) sort_internal(i, k-1);
if ((j-k) > 1) sort_internal(k+1, j);
}
protected int sort_partition(int left, int right) {
int pivot = right;
do {
while (sort_compare(++left, pivot) < 0) { }
while ((right != 0) && (sort_compare(--right, pivot) > 0)) { }
sort_swap(left, right);
} while (left < right);
sort_swap(left, right);
return left;
}
protected void sort_swap(int a, int b) {
switch (sort_mode) {
case BYTES:
byte btemp = sort_bytes[a];
sort_bytes[a] = sort_bytes[b];
sort_bytes[b] = btemp;
break;
case CHARS:
char ctemp = sort_chars[a];
sort_chars[a] = sort_chars[b];
sort_chars[b] = ctemp;
break;
case INTS:
int itemp = sort_ints[a];
sort_ints[a] = sort_ints[b];
sort_ints[b] = itemp;
break;
case FLOATS:
float ftemp = sort_floats[a];
sort_floats[a] = sort_floats[b];
sort_floats[b] = ftemp;
break;
case STRINGS:
String stemp = sort_strings[a];
sort_strings[a] = sort_strings[b];
sort_strings[b] = stemp;
break;
case OBJECTS:
try {
Object[] params = new Object[] { new Integer(a), new Integer(b) };
swapMethod.invoke(sortObject, params);
} catch (Exception e) {
e.printStackTrace();
}
}
}
protected float sort_compare(int a, int b) {
switch (sort_mode) {
case BYTES:
return sort_bytes[a] - sort_bytes[b];
case CHARS:
return sort_chars[a] - sort_chars[b];
case INTS:
return sort_ints[a] - sort_ints[b];
case FLOATS:
// can't just cast to an int because 0.2 and 0.4 would
// just appear to be the same thing. no good.
//if (sort_floats[a] < sort_floats[b]) return -1;
//return (sort_floats[a] == sort_floats[b]) ? 0 : 1;
return sort_floats[a] - sort_floats[b];
case STRINGS:
return sort_strings[a].compareTo(sort_strings[b]);
case OBJECTS:
try {
Object[] params = new Object[] { new Integer(a), new Integer(b) };
Float output = (Float) compareMethod.invoke(sortObject, params);
return output.floatValue();
} catch (Exception e) {
e.printStackTrace();
}
}
return 0;
}
//////////////////////////////////////////////////////////////
public void sort(Object o, int count) {
Class c = o.getClass();
try {
Class[] params = new Class[] { Integer.TYPE, Integer.TYPE };
// takes two ints, returns a float
compareMethod = c.getMethod("sortCompare", params);
// takes two ints, returns void
swapMethod = c.getMethod("sortSwap", params);
// start the sort
sortObject = o;
sort_mode = OBJECTS;
sort_internal(0, count-1);
} catch (Exception e) {
e.printStackTrace();
}
}
//////////////////////////////////////////////////////////////
// ARRAY UTILITIES
/**
* Calls System.arraycopy(), included here so that we can
* avoid people needing to learn about the System object
* before they can just copy an array.
*/
static public void arraycopy(Object src, int srcPosition,
Object dst, int dstPosition,
int length) {
System.arraycopy(src, srcPosition, dst, dstPosition, length);
}
/**
* Convenience method for arraycopy().
* Identical to
* To use this on numbers, first pass the array to nf() or nfs()
* to get a list of String objects, then use join on that.
*
* The whitespace characters are "\t\n\r\f", which are the defaults
* for java.util.StringTokenizer, plus the unicode non-breaking space
* character, which is found commonly on files created by or used
* in conjunction with Mac OS X (character 160, or 0x00A0 in hex).
*
* This operates differently than the others, where the
* single delimeter is the only breaking point, and consecutive
* delimeters will produce an empty string (""). This way,
* one can split on tab characters, but maintain the column
* alignments (of say an excel file) where there are empty columns.
*/
static public String[] split(String what, char delim) {
// do this so that the exception occurs inside the user's
// program, rather than appearing to be a bug inside split()
if (what == null) return null;
//return split(what, String.valueOf(delim)); // huh
char chars[] = what.toCharArray();
int splitCount = 0; //1;
for (int i = 0; i < chars.length; i++) {
if (chars[i] == delim) splitCount++;
}
// make sure that there is something in the input string
//if (chars.length > 0) {
// if the last char is a delimeter, get rid of it..
//if (chars[chars.length-1] == delim) splitCount--;
// on second thought, i don't agree with this, will disable
//}
if (splitCount == 0) {
String splits[] = new String[1];
splits[0] = new String(what);
return splits;
}
//int pieceCount = splitCount + 1;
String splits[] = new String[splitCount + 1];
int splitIndex = 0;
int startIndex = 0;
for (int i = 0; i < chars.length; i++) {
if (chars[i] == delim) {
splits[splitIndex++] =
new String(chars, startIndex, i-startIndex);
startIndex = i + 1;
}
}
//if (startIndex != chars.length) {
splits[splitIndex] =
new String(chars, startIndex, chars.length-startIndex);
//}
return splits;
}
/**
* FIXME this is only temporary
*/
static public String[] split(String what, String delim) {
return what.split(delim);
}
//////////////////////////////////////////////////////////////
// CASTING FUNCTIONS, INSERTED BY PREPROC
/**
* Convert a char to a boolean. 'T', 't', and '1' will become the
* boolean value true, while 'F', 'f', or '0' will become false.
*/
/*
static final public boolean parseBoolean(char what) {
return ((what == 't') || (what == 'T') || (what == '1'));
}
*/
/**
* Convert an integer to a boolean. Because of how Java handles upgrading
* numbers, this will also cover byte and char (as they will upgrade to
* an int without any sort of explicit cast). The preprocessor will convert boolean(what) to parseBoolean(what).
* The options shown here are not yet finalized and will be
* changing over the next several releases.
*
* The simplest way to turn and applet into an application is to
* add the following code to your program:
*
*
* 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.
*
* public PImage loadImageAlt(String filename) {
* java.awt.Image img = getImage(getCodeBase(), filename);
* return loadImageSync(img);
* }
*
* 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 loadImage(String filename) {
String lower = filename.toLowerCase();
int dot = filename.lastIndexOf('.');
if (dot == -1) {
// no extension found
return loadImage(filename, "unknown");
}
String extension = lower.substring(dot + 1);
// check for, and strip any parameters on the url, i.e.
// filename.jpg?blah=blah&something=that
int question = extension.indexOf('?');
if (question != -1) {
extension = extension.substring(0, question);
}
return loadImage(filename, extension);
}
/**
* Identical to loadImage, but allows you to specify the type of
* image by its extension. Especially useful when downloading from
* CGI scripts.
*
* Use 'unknown' as the extension to pass off to the default
* image loader that handles gif, jpg, and png.
*/
public PImage loadImage(String filename, String extension) {
// just in case. them users will try anything!
extension = extension.toLowerCase();
if (extension.equals("tga")) {
try {
return loadImageTGA(filename);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
//if (lower.endsWith(".tif") || lower.endsWith(".tiff")) {
if (extension.equals("tif") || extension.equals("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) {
if (extension.equals("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")) {
if (extension.equals("jpg") || extension.equals("jpeg") ||
extension.equals("gif") || extension.equals("png") ||
extension.equals("unknown")) {
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"))) {
if (extension.equals("gif") || extension.equals("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();
try {
Class ioClass = Class.forName("javax.imageio.ImageIO");
Method getFormatNamesMethod =
ioClass.getMethod("getReaderFormatNames", (Class[]) null);
loadImageFormats = (String[])
getFormatNamesMethod.invoke((Class[]) null, (Object[]) null);
} catch (Exception e) {
e.printStackTrace();
}
}
if (loadImageFormats != null) {
for (int i = 0; i < loadImageFormats.length; i++) {
//if (filename.endsWith("." + loadImageFormats[i])) {
if (extension.equals(loadImageFormats[i])) {
return loadImageIO(filename);
}
}
}
}
// failed, could not load image after all those attempts
System.err.println("Could not find a method to load " + filename);
return null;
}
/**
* 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) {
//e.printStackTrace(); // non-fatal, right?
}
PImage image = new PImage(awtImage);
image.parent = this;
return image;
}
/**
* Use Java 1.4 ImageIO methods to load an image. All done via reflection
* in order to maintain compatability with previous releases.
*/
protected PImage loadImageIO(String filename) {
InputStream stream = openStream(filename);
if (stream == null) {
System.err.println("The image " + filename + " could not be found.");
return null;
}
try {
Class ioClass = Class.forName("javax.imageio.ImageIO");
Method readMethod =
ioClass.getMethod("read", new Class[] { InputStream.class });
Object bimage = readMethod.invoke(null, new Object[] { stream });
// need to get width and height, then create pixels[] at that size
//int px[] = null;
Class biClass =
Class.forName("java.awt.image.BufferedImage");
Method getHeightMethod =
biClass.getMethod("getHeight", (Class[]) null);
Integer hi = (Integer) getHeightMethod.invoke(bimage, (Object[]) null);
Method getWidthMethod =
biClass.getMethod("getWidth", (Class[]) null);
Integer wi = (Integer) getWidthMethod.invoke(bimage, (Object[]) null);
// was gonna call getType() on the image to see if RGB or ARGB,
// but it's not actually useful, since gif images will come through
// as TYPE_BYTE_INDEXED, which means it'll still have to check for
// the transparency. also, would have to iterate through all the other
// types and guess whether alpha was in there, so.. just gonna stick
// with the old method.
PImage outgoing = new PImage(wi.intValue(), hi.intValue());
outgoing.parent = this;
Method getRgbMethod =
biClass.getMethod("getRGB", new Class[] {
Integer.TYPE, Integer.TYPE, Integer.TYPE, Integer.TYPE,
outgoing.pixels.getClass(), Integer.TYPE, Integer.TYPE
});
getRgbMethod.invoke(bimage, new Object[] {
new Integer(0), new Integer(0),
new Integer(outgoing.width), new Integer(outgoing.height),
outgoing.pixels, new Integer(0), new Integer(outgoing.width)
});
// check the alpha for this image
outgoing.checkAlpha();
// return the image
return outgoing;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* Targa image loader for RLE-compressed TGA files.
*
*
*/
public InputStream openStream(String filename) {
InputStream stream = null;
if (filename == null) return null;
if (filename.length() == 0) {
// an error will be called by the parent function
//System.err.println("The filename passed to openStream() was empty.");
return null;
}
// safe to check for this as a url first. this will prevent online
// access logs from being spammed with GET /sketchfolder/http://blahblah
try {
URL url = new URL(filename);
stream = url.openStream();
return stream;
} catch (MalformedURLException mfue) {
// not a url, that's fine
} catch (FileNotFoundException fnfe) {
// Java 1.5 likes to throw this when URL not available. (fix for 0119)
// http://dev.processing.org/bugs/show_bug.cgi?id=403
} catch (IOException e) {
// changed for 0117, shouldn't be throwing exception
e.printStackTrace();
//System.err.println("Error downloading from URL " + filename);
return null;
//throw new RuntimeException("Error downloading from URL " + filename);
}
// using getClassLoader() prevents java from converting dots
// to slashes or requiring a slash at the beginning.
// (a slash as a prefix means that it'll load from the root of
// the jar, rather than trying to dig into the package location)
ClassLoader cl = getClass().getClassLoader();
// by default, data files are exported to the root path of the jar.
// (not the data folder) so check there first.
stream = cl.getResourceAsStream("data/" + filename);
if (stream != null) {
String cn = stream.getClass().getName();
// this is an irritation of sun's java plug-in, which will return
// a non-null stream for an object that doesn't exist. like all good
// things, this is probably introduced in java 1.5. awesome!
// http://dev.processing.org/bugs/show_bug.cgi?id=359
if (!cn.equals("sun.plugin.cache.EmptyInputStream")) {
return stream;
}
}
// when used with an online script, also need to check without the
// data folder, in case it's not in a subfolder called 'data'
// http://dev.processing.org/bugs/show_bug.cgi?id=389
stream = cl.getResourceAsStream(filename);
if (stream != null) {
String cn = stream.getClass().getName();
if (!cn.equals("sun.plugin.cache.EmptyInputStream")) {
return stream;
}
}
// handle case sensitivity check
if (!online) {
try {
// first see if it's in a data folder
File file = new File(dataPath(filename));
if (!file.exists()) {
// next see if it's just in this folder
file = new File(sketchPath, filename);
}
if (file.exists()) {
try {
String filePath = file.getCanonicalPath();
String filenameActual = new File(filePath).getName();
// make sure there isn't a subfolder prepended to the name
String filenameShort = new File(filename).getName();
// if the actual filename is the same, but capitalized
// differently, warn the user.
//if (filenameActual.equalsIgnoreCase(filenameShort) &&
//!filenameActual.equals(filenameShort)) {
if (!filenameActual.equals(filenameShort)) {
throw new RuntimeException("This file is named " +
filenameActual + " not " +
filename + ". Re-name it " +
"or change your code.");
}
} catch (IOException e) { }
}
// if this file is ok, may as well just load it
stream = new FileInputStream(file);
if (stream != null) return stream;
// have to break these out because a general Exception might
// catch the RuntimeException being thrown above
} catch (IOException ioe) {
} catch (SecurityException se) { }
}
try {
// attempt to load from a local file, used when running as
// an application, or as a signed applet
try { // first try to catch any security exceptions
try {
stream = new FileInputStream(dataPath(filename));
if (stream != null) return stream;
} catch (IOException e2) { }
try {
stream = new FileInputStream(sketchPath(filename));
if (stream != null) return stream;
} catch (Exception e) { } // ignored
try {
stream = new FileInputStream(filename);
if (stream != null) return stream;
} catch (IOException e1) { }
} catch (SecurityException se) { } // online, whups
} catch (Exception e) {
//die(e.getMessage(), e);
e.printStackTrace();
}
return null;
}
static public InputStream openStream(File file) {
try {
return new FileInputStream(file);
} catch (IOException e) {
if (file == null) {
throw new RuntimeException("File passed to openStream() was null");
} else {
e.printStackTrace();
throw new RuntimeException("Couldn't openStream() for " +
file.getAbsolutePath());
}
}
}
public InputStream openStreamGZ(String filename) {
try {
return new GZIPInputStream(openStream(filename));
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("Couldn't openStreamGZ() for " +
filename);
}
}
static public InputStream openStreamGZ(File file) {
try {
return new GZIPInputStream(openStream(file));
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("Couldn't openStreamGZ() for " +
file.getAbsolutePath());
}
}
public byte[] loadBytes(String filename) {
InputStream is = openStream(filename);
if (is != null) return loadBytes(is);
System.err.println("The file \"" + filename + "\" " +
"is missing or inaccessible, make sure " +
"the URL is valid or that the file has been " +
"added to your sketch and is readable.");
return null;
}
static public byte[] loadBytes(InputStream input) {
try {
BufferedInputStream bis = new BufferedInputStream(input);
ByteArrayOutputStream out = new ByteArrayOutputStream();
int c = bis.read();
while (c != -1) {
out.write(c);
c = bis.read();
}
return out.toByteArray();
} catch (IOException e) {
e.printStackTrace();
//throw new RuntimeException("Couldn't load bytes from stream");
}
return null;
}
static public String[] loadStrings(File file) {
InputStream is = openStream(file);
if (is != null) return loadStrings(is);
return null;
}
/**
* Load data from a file and shove it into a String array.
* arraycopy(src, 0, dst, 0, length);
*/
static public void arraycopy(Object src, Object dst, int length) {
System.arraycopy(src, 0, dst, 0, length);
}
/**
* Shortcut to copy the entire contents of
* the source into the destination array.
* Identical to arraycopy(src, 0, dst, 0, src.length);
*/
static public void arraycopy(Object src, Object dst) {
System.arraycopy(src, 0, dst, 0, Array.getLength(src));
}
//
static public boolean[] expand(boolean list[]) {
return expand(list, list.length << 1);
}
static public boolean[] expand(boolean list[], int newSize) {
boolean temp[] = new boolean[newSize];
System.arraycopy(list, 0, temp, 0, Math.min(newSize, list.length));
return temp;
}
static public byte[] expand(byte list[]) {
return expand(list, list.length << 1);
}
static public byte[] expand(byte list[], int newSize) {
byte temp[] = new byte[newSize];
System.arraycopy(list, 0, temp, 0, Math.min(newSize, list.length));
return temp;
}
static public char[] expand(char list[]) {
return expand(list, list.length << 1);
}
static public char[] expand(char list[], int newSize) {
char temp[] = new char[newSize];
System.arraycopy(list, 0, temp, 0, Math.min(newSize, list.length));
return temp;
}
static public int[] expand(int list[]) {
return expand(list, list.length << 1);
}
static public int[] expand(int list[], int newSize) {
int temp[] = new int[newSize];
System.arraycopy(list, 0, temp, 0, Math.min(newSize, list.length));
return temp;
}
static public float[] expand(float list[]) {
return expand(list, list.length << 1);
}
static public float[] expand(float list[], int newSize) {
float temp[] = new float[newSize];
System.arraycopy(list, 0, temp, 0, Math.min(newSize, list.length));
return temp;
}
static public String[] expand(String list[]) {
return expand(list, list.length << 1);
}
static public String[] expand(String list[], int newSize) {
String temp[] = new String[newSize];
// in case the new size is smaller than list.length
System.arraycopy(list, 0, temp, 0, Math.min(newSize, list.length));
return temp;
}
static public Object expand(Object array) {
return expand(array, Array.getLength(array) << 1);
}
static public Object expand(Object list, int newSize) {
Class type = list.getClass().getComponentType();
Object temp = Array.newInstance(type, newSize);
System.arraycopy(list, 0, temp, 0,
Math.min(Array.getLength(list), newSize));
return temp;
}
//
// contract() has been removed in revision 0124, use subset() instead.
// (expand() is also functionally equivalent)
//
static public byte[] append(byte b[], byte value) {
b = expand(b, b.length + 1);
b[b.length-1] = value;
return b;
}
static public char[] append(char b[], char value) {
b = expand(b, b.length + 1);
b[b.length-1] = value;
return b;
}
static public int[] append(int b[], int value) {
b = expand(b, b.length + 1);
b[b.length-1] = value;
return b;
}
static public float[] append(float b[], float value) {
b = expand(b, b.length + 1);
b[b.length-1] = value;
return b;
}
static public String[] append(String b[], String value) {
b = expand(b, b.length + 1);
b[b.length-1] = value;
return b;
}
static public Object append(Object b, Object value) {
int length = Array.getLength(b);
b = expand(b, length + 1);
Array.set(b, length, value);
return b;
}
//
static public boolean[] shorten(boolean list[]) {
return subset(list, 0, list.length-1);
}
static public byte[] shorten(byte list[]) {
return subset(list, 0, list.length-1);
}
static public char[] shorten(char list[]) {
return subset(list, 0, list.length-1);
}
static public int[] shorten(int list[]) {
return subset(list, 0, list.length-1);
}
static public float[] shorten(float list[]) {
return subset(list, 0, list.length-1);
}
static public String[] shorten(String list[]) {
return subset(list, 0, list.length-1);
}
static public Object shorten(Object list) {
int length = Array.getLength(list);
return subset(list, 0, length - 1);
}
//
static final public boolean[] splice(boolean list[],
boolean v, int index) {
boolean outgoing[] = new boolean[list.length + 1];
System.arraycopy(list, 0, outgoing, 0, index);
outgoing[index] = v;
System.arraycopy(list, index, outgoing, index + 1,
list.length - index);
return outgoing;
}
static final public boolean[] splice(boolean list[],
boolean v[], int index) {
boolean outgoing[] = new boolean[list.length + v.length];
System.arraycopy(list, 0, outgoing, 0, index);
System.arraycopy(v, 0, outgoing, index, v.length);
System.arraycopy(list, index, outgoing, index + v.length,
list.length - index);
return outgoing;
}
static final public byte[] splice(byte list[],
byte v, int index) {
byte outgoing[] = new byte[list.length + 1];
System.arraycopy(list, 0, outgoing, 0, index);
outgoing[index] = v;
System.arraycopy(list, index, outgoing, index + 1,
list.length - index);
return outgoing;
}
static final public byte[] splice(byte list[],
byte v[], int index) {
byte outgoing[] = new byte[list.length + v.length];
System.arraycopy(list, 0, outgoing, 0, index);
System.arraycopy(v, 0, outgoing, index, v.length);
System.arraycopy(list, index, outgoing, index + v.length,
list.length - index);
return outgoing;
}
static final public char[] splice(char list[],
char v, int index) {
char outgoing[] = new char[list.length + 1];
System.arraycopy(list, 0, outgoing, 0, index);
outgoing[index] = v;
System.arraycopy(list, index, outgoing, index + 1,
list.length - index);
return outgoing;
}
static final public char[] splice(char list[],
char v[], int index) {
char outgoing[] = new char[list.length + v.length];
System.arraycopy(list, 0, outgoing, 0, index);
System.arraycopy(v, 0, outgoing, index, v.length);
System.arraycopy(list, index, outgoing, index + v.length,
list.length - index);
return outgoing;
}
static final public int[] splice(int list[],
int v, int index) {
int outgoing[] = new int[list.length + 1];
System.arraycopy(list, 0, outgoing, 0, index);
outgoing[index] = v;
System.arraycopy(list, index, outgoing, index + 1,
list.length - index);
return outgoing;
}
static final public int[] splice(int list[],
int v[], int index) {
int outgoing[] = new int[list.length + v.length];
System.arraycopy(list, 0, outgoing, 0, index);
System.arraycopy(v, 0, outgoing, index, v.length);
System.arraycopy(list, index, outgoing, index + v.length,
list.length - index);
return outgoing;
}
static final public float[] splice(float list[],
float v, int index) {
float outgoing[] = new float[list.length + 1];
System.arraycopy(list, 0, outgoing, 0, index);
outgoing[index] = v;
System.arraycopy(list, index, outgoing, index + 1,
list.length - index);
return outgoing;
}
static final public float[] splice(float list[],
float v[], int index) {
float outgoing[] = new float[list.length + v.length];
System.arraycopy(list, 0, outgoing, 0, index);
System.arraycopy(v, 0, outgoing, index, v.length);
System.arraycopy(list, index, outgoing, index + v.length,
list.length - index);
return outgoing;
}
static final public String[] splice(String list[],
String v, int index) {
String outgoing[] = new String[list.length + 1];
System.arraycopy(list, 0, outgoing, 0, index);
outgoing[index] = v;
System.arraycopy(list, index, outgoing, index + 1,
list.length - index);
return outgoing;
}
static final public String[] splice(String list[],
String v[], int index) {
String outgoing[] = new String[list.length + v.length];
System.arraycopy(list, 0, outgoing, 0, index);
System.arraycopy(v, 0, outgoing, index, v.length);
System.arraycopy(list, index, outgoing, index + v.length,
list.length - index);
return outgoing;
}
static final public Object splice(Object list, Object v, int index) {
Object[] outgoing = null;
int length = Array.getLength(list);
// check whether is an array or not, and if so, treat as such
if (list.getClass().getName().charAt(0) == '[') {
int vlength = Array.getLength(v);
outgoing = new Object[length + vlength];
System.arraycopy(list, 0, outgoing, 0, index);
System.arraycopy(v, 0, outgoing, index, vlength);
System.arraycopy(list, index, outgoing, index + vlength, length - index);
} else {
outgoing = new Object[length + 1];
System.arraycopy(list, 0, outgoing, 0, index);
Array.set(outgoing, index, v);
System.arraycopy(list, index, outgoing, index + 1, length - index);
}
return outgoing;
}
//
static public boolean[] subset(boolean list[], int start) {
return subset(list, start, list.length - start);
}
static public boolean[] subset(boolean list[], int start, int count) {
boolean output[] = new boolean[count];
System.arraycopy(list, start, output, 0, count);
return output;
}
static public byte[] subset(byte list[], int start) {
return subset(list, start, list.length - start);
}
static public byte[] subset(byte list[], int start, int count) {
byte output[] = new byte[count];
System.arraycopy(list, start, output, 0, count);
return output;
}
static public char[] subset(char list[], int start) {
return subset(list, start, list.length - start);
}
static public char[] subset(char list[], int start, int count) {
char output[] = new char[count];
System.arraycopy(list, start, output, 0, count);
return output;
}
static public int[] subset(int list[], int start) {
return subset(list, start, list.length - start);
}
static public int[] subset(int list[], int start, int count) {
int output[] = new int[count];
System.arraycopy(list, start, output, 0, count);
return output;
}
static public float[] subset(float list[], int start) {
return subset(list, start, list.length - start);
}
static public float[] subset(float list[], int start, int count) {
float output[] = new float[count];
System.arraycopy(list, start, output, 0, count);
return output;
}
static public String[] subset(String list[], int start) {
return subset(list, start, list.length - start);
}
static public String[] subset(String list[], int start, int count) {
String output[] = new String[count];
System.arraycopy(list, start, output, 0, count);
return output;
}
static public Object subset(Object list, int start) {
int length = Array.getLength(list);
int count = length - start;
Class type = list.getClass().getComponentType();
Object outgoing = Array.newInstance(type, count);
System.arraycopy(list, 0, outgoing, 0, count);
return outgoing;
}
static public Object subset(Object list, int start, int count) {
//int length = Array.getLength(list);
Class type = list.getClass().getComponentType();
Object outgoing = Array.newInstance(type, count);
System.arraycopy(list, start, outgoing, 0, count);
return outgoing;
}
//
static public boolean[] concat(boolean a[], boolean b[]) {
boolean c[] = new boolean[a.length + b.length];
System.arraycopy(a, 0, c, 0, a.length);
System.arraycopy(b, 0, c, a.length, b.length);
return c;
}
static public byte[] concat(byte a[], byte b[]) {
byte c[] = new byte[a.length + b.length];
System.arraycopy(a, 0, c, 0, a.length);
System.arraycopy(b, 0, c, a.length, b.length);
return c;
}
static public char[] concat(char a[], char b[]) {
char c[] = new char[a.length + b.length];
System.arraycopy(a, 0, c, 0, a.length);
System.arraycopy(b, 0, c, a.length, b.length);
return c;
}
static public int[] concat(int a[], int b[]) {
int c[] = new int[a.length + b.length];
System.arraycopy(a, 0, c, 0, a.length);
System.arraycopy(b, 0, c, a.length, b.length);
return c;
}
static public float[] concat(float a[], float b[]) {
float c[] = new float[a.length + b.length];
System.arraycopy(a, 0, c, 0, a.length);
System.arraycopy(b, 0, c, a.length, b.length);
return c;
}
static public String[] concat(String a[], String b[]) {
String c[] = new String[a.length + b.length];
System.arraycopy(a, 0, c, 0, a.length);
System.arraycopy(b, 0, c, a.length, b.length);
return c;
}
static public Object concat(Object a, Object b) {
Class type = a.getClass().getComponentType();
int alength = Array.getLength(a);
int blength = Array.getLength(b);
Object outgoing = Array.newInstance(type, alength + blength);
System.arraycopy(a, 0, outgoing, 0, alength);
System.arraycopy(b, 0, outgoing, alength, blength);
return outgoing;
}
//
static public boolean[] reverse(boolean list[]) {
boolean outgoing[] = new boolean[list.length];
int length1 = list.length - 1;
for (int i = 0; i < list.length; i++) {
outgoing[i] = list[length1 - i];
}
return outgoing;
}
static public byte[] reverse(byte list[]) {
byte outgoing[] = new byte[list.length];
int length1 = list.length - 1;
for (int i = 0; i < list.length; i++) {
outgoing[i] = list[length1 - i];
}
return outgoing;
}
static public char[] reverse(char list[]) {
char outgoing[] = new char[list.length];
int length1 = list.length - 1;
for (int i = 0; i < list.length; i++) {
outgoing[i] = list[length1 - i];
}
return outgoing;
}
static public int[] reverse(int list[]) {
int outgoing[] = new int[list.length];
int length1 = list.length - 1;
for (int i = 0; i < list.length; i++) {
outgoing[i] = list[length1 - i];
}
return outgoing;
}
static public float[] reverse(float list[]) {
float outgoing[] = new float[list.length];
int length1 = list.length - 1;
for (int i = 0; i < list.length; i++) {
outgoing[i] = list[length1 - i];
}
return outgoing;
}
static public String[] reverse(String list[]) {
String outgoing[] = new String[list.length];
int length1 = list.length - 1;
for (int i = 0; i < list.length; i++) {
outgoing[i] = list[length1 - i];
}
return outgoing;
}
static public Object reverse(Object list) {
Class type = list.getClass().getComponentType();
int length = Array.getLength(list);
Object outgoing = Array.newInstance(type, length);
for (int i = 0; i < length; i++) {
Array.set(outgoing, i, Array.get(list, (length - 1) - i));
}
return outgoing;
}
//////////////////////////////////////////////////////////////
// STRINGS
/**
* Remove whitespace characters from the beginning and ending
* of a String. Works like String.trim() but includes the
* unicode nbsp character as well.
*/
static public String trim(String str) {
return str.replace('\u00A0', ' ').trim();
/*
int left = 0;
int right = str.length() - 1;
while ((left <= right) &&
(WHITESPACE.indexOf(str.charAt(left)) != -1)) left++;
if (left == right) return "";
while (WHITESPACE.indexOf(str.charAt(right)) != -1) --right;
return str.substring(left, right-left+1);
*/
}
/**
* Trim the whitespace from a String array. This returns a new
* array and does not affect the passed-in array.
*/
static public String[] trim(String[] array) {
String[] outgoing = new String[array.length];
for (int i = 0; i < array.length; i++) {
outgoing[i] = array[i].replace('\u00A0', ' ').trim();
}
return outgoing;
}
/**
* Join an array of Strings together as a single String,
* separated by the whatever's passed in for the separator.
*/
static public String join(String str[], char separator) {
return join(str, String.valueOf(separator));
}
/**
* Join an array of Strings together as a single String,
* separated by the whatever's passed in for the separator.
*
* e.g. String stuff[] = { "apple", "bear", "cat" };
* String list = join(stuff, ", ");
* // list is now "apple, bear, cat"
*/
static public String join(String str[], String separator) {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < str.length; i++) {
if (i != 0) buffer.append(separator);
buffer.append(str[i]);
}
return buffer.toString();
}
/**
* Split the provided String at wherever whitespace occurs.
* Multiple whitespace (extra spaces or tabs or whatever)
* between items will count as a single break.
*
* i.e. splitTokens("a b") -> { "a", "b" }
* splitTokens("a b") -> { "a", "b" }
* splitTokens("a\tb") -> { "a", "b" }
* splitTokens("a \t b ") -> { "a", "b" }
*/
static public String[] splitTokens(String what) {
return splitTokens(what, WHITESPACE);
}
/**
* Splits a string into pieces, using any of the chars in the
* String 'delim' as separator characters. For instance,
* in addition to white space, you might want to treat commas
* as a separator. The delimeter characters won't appear in
* the returned String array.
*
* i.e. splitTokens("a, b", " ,") -> { "a", "b" }
*
* To include all the whitespace possibilities, use the variable
* WHITESPACE, found in PConstants:
*
* i.e. splitTokens("a | b", WHITESPACE + "|"); -> { "a", "b" }
*/
static public String[] splitTokens(String what, String delim) {
StringTokenizer toker = new StringTokenizer(what, delim);
String pieces[] = new String[toker.countTokens()];
int index = 0;
while (toker.hasMoreTokens()) {
pieces[index++] = toker.nextToken();
}
return pieces;
}
/**
* Split a string into pieces along a specific character.
* Most commonly used to break up a String along tab characters.
* static public void main(String args[]) {
* PApplet.main(new String[] { "YourSketchName" });
* }
* This will properly launch your applet from a double-clickable
* .jar or from the command line.
*
* Parameters useful for launching or also used by the PDE:
*
* --location=x,y upper-lefthand corner of where the applet
* should appear on screen. if not used,
* the default is to center on the main screen.
*
* --present put the applet into full screen presentation
* mode. requires java 1.4 or later.
*
* --hide-stop use to hide the stop button in situations where
* you don't want to allow users to exit. also
* see the FAQ on information for capturing the ESC
* key when running in presentation mode.
*
* --stop-color color of the 'stop' text used to quit an
* sketch when it's in present mode.
*
* --bgcolor=#xxxxxx background color of the window.
*
* --sketch-path location of where to save files from functions
* like saveStrings() or saveFrame(). defaults to
* the folder that the java application was
* launched from, which means if this isn't set by
* the pde, everything goes into the same folder
* as processing.exe.
*
* --display=n set what display should be used by this applet.
* displays are numbered starting from 1.
*
*
* Parameters used by Processing when running via the PDE
*
* --external set when the applet is being used by the PDE
*
* --editor-location=x,y position of the upper-lefthand corner of the
* editor window, for placement of applet window
*
*/
static public void main(String args[]) {
if (args.length < 1) {
System.err.println("Usage: PApplet