~ubuntu-branches/ubuntu/precise/arduino/precise

« back to all changes in this revision

Viewing changes to src/processing/core/PApplet.java

  • Committer: Bazaar Package Importer
  • Author(s): Scott Howard
  • Date: 2010-04-13 22:32:24 UTC
  • Revision ID: james.westby@ubuntu.com-20100413223224-jduxnd0xxnkkda02
Tags: upstream-0018+dfsg
ImportĀ upstreamĀ versionĀ 0018+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
 
2
 
 
3
/*
 
4
  Part of the Processing project - http://processing.org
 
5
 
 
6
  Copyright (c) 2004-09 Ben Fry and Casey Reas
 
7
  Copyright (c) 2001-04 Massachusetts Institute of Technology
 
8
 
 
9
  This library is free software; you can redistribute it and/or
 
10
  modify it under the terms of the GNU Lesser General Public
 
11
  License as published by the Free Software Foundation, version 2.1.
 
12
 
 
13
  This library is distributed in the hope that it will be useful,
 
14
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
  Lesser General Public License for more details.
 
17
 
 
18
  You should have received a copy of the GNU Lesser General
 
19
  Public License along with this library; if not, write to the
 
20
  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 
21
  Boston, MA  02111-1307  USA
 
22
*/
 
23
 
 
24
package processing.core;
 
25
 
 
26
import java.applet.*;
 
27
import java.awt.*;
 
28
import java.awt.event.*;
 
29
import java.awt.image.*;
 
30
import java.io.*;
 
31
import java.lang.reflect.*;
 
32
import java.net.*;
 
33
import java.text.*;
 
34
import java.util.*;
 
35
import java.util.regex.*;
 
36
import java.util.zip.*;
 
37
 
 
38
import javax.imageio.ImageIO;
 
39
import javax.swing.JFileChooser;
 
40
import javax.swing.SwingUtilities;
 
41
 
 
42
 
 
43
/**
 
44
 * Base class for all sketches that use processing.core.
 
45
 * <p/>
 
46
 * Note that you should not use AWT or Swing components inside a Processing
 
47
 * applet. The surface is made to automatically update itself, and will cause
 
48
 * problems with redraw of components drawn above it. If you'd like to
 
49
 * integrate other Java components, see below.
 
50
 * <p/>
 
51
 * As of release 0145, Processing uses active mode rendering in all cases.
 
52
 * All animation tasks happen on the "Processing Animation Thread". The
 
53
 * setup() and draw() methods are handled by that thread, and events (like
 
54
 * mouse movement and key presses, which are fired by the event dispatch
 
55
 * thread or EDT) are queued to be (safely) handled at the end of draw().
 
56
 * For code that needs to run on the EDT, use SwingUtilities.invokeLater().
 
57
 * When doing so, be careful to synchronize between that code (since
 
58
 * invokeLater() will make your code run from the EDT) and the Processing
 
59
 * animation thread. Use of a callback function or the registerXxx() methods
 
60
 * in PApplet can help ensure that your code doesn't do something naughty.
 
61
 * <p/>
 
62
 * As of release 0136 of Processing, we have discontinued support for versions
 
63
 * of Java prior to 1.5. We don't have enough people to support it, and for a
 
64
 * project of our size, we should be focusing on the future, rather than
 
65
 * working around legacy Java code. In addition, Java 1.5 gives us access to
 
66
 * better timing facilities which will improve the steadiness of animation.
 
67
 * <p/>
 
68
 * This class extends Applet instead of JApplet because 1) historically,
 
69
 * we supported Java 1.1, which does not include Swing (without an
 
70
 * additional, sizable, download), and 2) Swing is a bloated piece of crap.
 
71
 * A Processing applet is a heavyweight AWT component, and can be used the
 
72
 * same as any other AWT component, with or without Swing.
 
73
 * <p/>
 
74
 * Similarly, Processing runs in a Frame and not a JFrame. However, there's
 
75
 * nothing to prevent you from embedding a PApplet into a JFrame, it's just
 
76
 * that the base version uses a regular AWT frame because there's simply
 
77
 * no need for swing in that context. If people want to use Swing, they can
 
78
 * embed themselves as they wish.
 
79
 * <p/>
 
80
 * It is possible to use PApplet, along with core.jar in other projects.
 
81
 * In addition to enabling you to use Java 1.5+ features with your sketch,
 
82
 * this also allows you to embed a Processing drawing area into another Java
 
83
 * application. This means you can use standard GUI controls with a Processing
 
84
 * sketch. Because AWT and Swing GUI components cannot be used on top of a
 
85
 * PApplet, you can instead embed the PApplet inside another GUI the way you
 
86
 * would any other Component.
 
87
 * <p/>
 
88
 * It is also possible to resize the Processing window by including
 
89
 * <tt>frame.setResizable(true)</tt> inside your <tt>setup()</tt> method.
 
90
 * Note that the Java method <tt>frame.setSize()</tt> will not work unless
 
91
 * you first set the frame to be resizable.
 
92
 * <p/>
 
93
 * Because the default animation thread will run at 60 frames per second,
 
94
 * an embedded PApplet can make the parent sluggish. You can use frameRate()
 
95
 * to make it update less often, or you can use noLoop() and loop() to disable
 
96
 * and then re-enable looping. If you want to only update the sketch
 
97
 * intermittently, use noLoop() inside setup(), and redraw() whenever
 
98
 * the screen needs to be updated once (or loop() to re-enable the animation
 
99
 * thread). The following example embeds a sketch and also uses the noLoop()
 
100
 * and redraw() methods. You need not use noLoop() and redraw() when embedding
 
101
 * if you want your application to animate continuously.
 
102
 * <PRE>
 
103
 * public class ExampleFrame extends Frame {
 
104
 *
 
105
 *     public ExampleFrame() {
 
106
 *         super("Embedded PApplet");
 
107
 *
 
108
 *         setLayout(new BorderLayout());
 
109
 *         PApplet embed = new Embedded();
 
110
 *         add(embed, BorderLayout.CENTER);
 
111
 *
 
112
 *         // important to call this whenever embedding a PApplet.
 
113
 *         // It ensures that the animation thread is started and
 
114
 *         // that other internal variables are properly set.
 
115
 *         embed.init();
 
116
 *     }
 
117
 * }
 
118
 *
 
119
 * public class Embedded extends PApplet {
 
120
 *
 
121
 *     public void setup() {
 
122
 *         // original setup code here ...
 
123
 *         size(400, 400);
 
124
 *
 
125
 *         // prevent thread from starving everything else
 
126
 *         noLoop();
 
127
 *     }
 
128
 *
 
129
 *     public void draw() {
 
130
 *         // drawing code goes here
 
131
 *     }
 
132
 *
 
133
 *     public void mousePressed() {
 
134
 *         // do something based on mouse movement
 
135
 *
 
136
 *         // update the screen (run draw once)
 
137
 *         redraw();
 
138
 *     }
 
139
 * }
 
140
 * </PRE>
 
141
 *
 
142
 * <H2>Processing on multiple displays</H2>
 
143
 * <P>I was asked about Processing with multiple displays, and for lack of a
 
144
 * better place to document it, things will go here.</P>
 
145
 * <P>You can address both screens by making a window the width of both,
 
146
 * and the height of the maximum of both screens. In this case, do not use
 
147
 * present mode, because that's exclusive to one screen. Basically it'll
 
148
 * give you a PApplet that spans both screens. If using one half to control
 
149
 * and the other half for graphics, you'd just have to put the 'live' stuff
 
150
 * on one half of the canvas, the control stuff on the other. This works
 
151
 * better in windows because on the mac we can't get rid of the menu bar
 
152
 * unless it's running in present mode.</P>
 
153
 * <P>For more control, you need to write straight java code that uses p5.
 
154
 * You can create two windows, that are shown on two separate screens,
 
155
 * that have their own PApplet. this is just one of the tradeoffs of one of
 
156
 * the things that we don't support in p5 from within the environment
 
157
 * itself (we must draw the line somewhere), because of how messy it would
 
158
 * get to start talking about multiple screens. It's also not that tough to
 
159
 * do by hand w/ some Java code.</P>
 
160
 */
 
161
public class PApplet extends Applet
 
162
  implements PConstants, Runnable,
 
163
             MouseListener, MouseMotionListener, KeyListener, FocusListener
 
164
{
 
165
  /**
 
166
   * Full name of the Java version (i.e. 1.5.0_11).
 
167
   * Prior to 0125, this was only the first three digits.
 
168
   */
 
169
  public static final String javaVersionName =
 
170
    System.getProperty("java.version");
 
171
 
 
172
  /**
 
173
   * Version of Java that's in use, whether 1.1 or 1.3 or whatever,
 
174
   * stored as a float.
 
175
   * <P>
 
176
   * Note that because this is stored as a float, the values may
 
177
   * not be <EM>exactly</EM> 1.3 or 1.4. Instead, make sure you're
 
178
   * comparing against 1.3f or 1.4f, which will have the same amount
 
179
   * of error (i.e. 1.40000001). This could just be a double, but
 
180
   * since Processing only uses floats, it's safer for this to be a float
 
181
   * because there's no good way to specify a double with the preproc.
 
182
   */
 
183
  public static final float javaVersion =
 
184
    new Float(javaVersionName.substring(0, 3)).floatValue();
 
185
 
 
186
  /**
 
187
   * Current platform in use.
 
188
   * <P>
 
189
   * Equivalent to System.getProperty("os.name"), just used internally.
 
190
   */
 
191
 
 
192
  /**
 
193
   * Current platform in use, one of the
 
194
   * PConstants WINDOWS, MACOSX, MACOS9, LINUX or OTHER.
 
195
   */
 
196
  static public int platform;
 
197
 
 
198
  /**
 
199
   * Name associated with the current 'platform' (see PConstants.platformNames)
 
200
   */
 
201
  //static public String platformName;
 
202
 
 
203
  static {
 
204
    String osname = System.getProperty("os.name");
 
205
 
 
206
    if (osname.indexOf("Mac") != -1) {
 
207
      platform = MACOSX;
 
208
 
 
209
    } else if (osname.indexOf("Windows") != -1) {
 
210
      platform = WINDOWS;
 
211
 
 
212
    } else if (osname.equals("Linux")) {  // true for the ibm vm
 
213
      platform = LINUX;
 
214
 
 
215
    } else {
 
216
      platform = OTHER;
 
217
    }
 
218
  }
 
219
 
 
220
  /**
 
221
   * Modifier flags for the shortcut key used to trigger menus.
 
222
   * (Cmd on Mac OS X, Ctrl on Linux and Windows)
 
223
   */
 
224
  static public final int MENU_SHORTCUT =
 
225
    Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
 
226
 
 
227
  /** The PGraphics renderer associated with this PApplet */
 
228
  public PGraphics g;
 
229
 
 
230
  //protected Object glock = new Object(); // for sync
 
231
 
 
232
  /** The frame containing this applet (if any) */
 
233
  public Frame frame;
 
234
 
 
235
  /**
 
236
   * The screen size when the applet was started.
 
237
   * <P>
 
238
   * Access this via screen.width and screen.height. To make an applet
 
239
   * run at full screen, use size(screen.width, screen.height).
 
240
   * <P>
 
241
   * If you have multiple displays, this will be the size of the main
 
242
   * display. Running full screen across multiple displays isn't
 
243
   * particularly supported, and requires more monkeying with the values.
 
244
   * This probably can't/won't be fixed until/unless I get a dual head
 
245
   * system.
 
246
   * <P>
 
247
   * Note that this won't update if you change the resolution
 
248
   * of your screen once the the applet is running.
 
249
   * <p>
 
250
   * This variable is not static, because future releases need to be better
 
251
   * at handling multiple displays.
 
252
   */
 
253
  public Dimension screen =
 
254
    Toolkit.getDefaultToolkit().getScreenSize();
 
255
 
 
256
  /**
 
257
   * A leech graphics object that is echoing all events.
 
258
   */
 
259
  public PGraphics recorder;
 
260
 
 
261
  /**
 
262
   * Command line options passed in from main().
 
263
   * <P>
 
264
   * This does not include the arguments passed in to PApplet itself.
 
265
   */
 
266
  public String args[];
 
267
 
 
268
  /** Path to sketch folder */
 
269
  public String sketchPath; //folder;
 
270
 
 
271
  /** When debugging headaches */
 
272
  static final boolean THREAD_DEBUG = false;
 
273
 
 
274
  /** Default width and height for applet when not specified */
 
275
  static public final int DEFAULT_WIDTH = 100;
 
276
  static public final int DEFAULT_HEIGHT = 100;
 
277
 
 
278
  /**
 
279
   * Minimum dimensions for the window holding an applet.
 
280
   * This varies between platforms, Mac OS X 10.3 can do any height
 
281
   * but requires at least 128 pixels width. Windows XP has another
 
282
   * set of limitations. And for all I know, Linux probably lets you
 
283
   * make windows with negative sizes.
 
284
   */
 
285
  static public final int MIN_WINDOW_WIDTH = 128;
 
286
  static public final int MIN_WINDOW_HEIGHT = 128;
 
287
 
 
288
  /**
 
289
   * Exception thrown when size() is called the first time.
 
290
   * <P>
 
291
   * This is used internally so that setup() is forced to run twice
 
292
   * when the renderer is changed. This is the only way for us to handle
 
293
   * invoking the new renderer while also in the midst of rendering.
 
294
   */
 
295
  static public class RendererChangeException extends RuntimeException { }
 
296
 
 
297
  /**
 
298
   * true if no size() command has been executed. This is used to wait until
 
299
   * a size has been set before placing in the window and showing it.
 
300
   */
 
301
  public boolean defaultSize;
 
302
 
 
303
  volatile boolean resizeRequest;
 
304
  volatile int resizeWidth;
 
305
  volatile int resizeHeight;
 
306
 
 
307
  /**
 
308
   * Pixel buffer from this applet's PGraphics.
 
309
   * <P>
 
310
   * When used with OpenGL or Java2D, this value will
 
311
   * be null until loadPixels() has been called.
 
312
   */
 
313
  public int pixels[];
 
314
 
 
315
  /** width of this applet's associated PGraphics */
 
316
  public int width;
 
317
 
 
318
  /** height of this applet's associated PGraphics */
 
319
  public int height;
 
320
 
 
321
  /** current x position of the mouse */
 
322
  public int mouseX;
 
323
 
 
324
  /** current y position of the mouse */
 
325
  public int mouseY;
 
326
 
 
327
  /**
 
328
   * Previous x/y position of the mouse. This will be a different value
 
329
   * when inside a mouse handler (like the mouseMoved() method) versus
 
330
   * when inside draw(). Inside draw(), pmouseX is updated once each
 
331
   * frame, but inside mousePressed() and friends, it's updated each time
 
332
   * an event comes through. Be sure to use only one or the other type of
 
333
   * means for tracking pmouseX and pmouseY within your sketch, otherwise
 
334
   * you're gonna run into trouble.
 
335
   */
 
336
  public int pmouseX, pmouseY;
 
337
 
 
338
  /**
 
339
   * previous mouseX/Y for the draw loop, separated out because this is
 
340
   * separate from the pmouseX/Y when inside the mouse event handlers.
 
341
   */
 
342
  protected int dmouseX, dmouseY;
 
343
 
 
344
  /**
 
345
   * pmouseX/Y for the event handlers (mousePressed(), mouseDragged() etc)
 
346
   * these are different because mouse events are queued to the end of
 
347
   * draw, so the previous position has to be updated on each event,
 
348
   * as opposed to the pmouseX/Y that's used inside draw, which is expected
 
349
   * to be updated once per trip through draw().
 
350
   */
 
351
  protected int emouseX, emouseY;
 
352
 
 
353
  /**
 
354
   * Used to set pmouseX/Y to mouseX/Y the first time mouseX/Y are used,
 
355
   * otherwise pmouseX/Y are always zero, causing a nasty jump.
 
356
   * <P>
 
357
   * Just using (frameCount == 0) won't work since mouseXxxxx()
 
358
   * may not be called until a couple frames into things.
 
359
   */
 
360
  public boolean firstMouse;
 
361
 
 
362
  /**
 
363
   * Last mouse button pressed, one of LEFT, CENTER, or RIGHT.
 
364
   * <P>
 
365
   * If running on Mac OS, a ctrl-click will be interpreted as
 
366
   * the righthand mouse button (unlike Java, which reports it as
 
367
   * the left mouse).
 
368
   */
 
369
  public int mouseButton;
 
370
 
 
371
  public boolean mousePressed;
 
372
  public MouseEvent mouseEvent;
 
373
 
 
374
  /**
 
375
   * Last key pressed.
 
376
   * <P>
 
377
   * If it's a coded key, i.e. UP/DOWN/CTRL/SHIFT/ALT,
 
378
   * this will be set to CODED (0xffff or 65535).
 
379
   */
 
380
  public char key;
 
381
 
 
382
  /**
 
383
   * When "key" is set to CODED, this will contain a Java key code.
 
384
   * <P>
 
385
   * For the arrow keys, keyCode will be one of UP, DOWN, LEFT and RIGHT.
 
386
   * Also available are ALT, CONTROL and SHIFT. A full set of constants
 
387
   * can be obtained from java.awt.event.KeyEvent, from the VK_XXXX variables.
 
388
   */
 
389
  public int keyCode;
 
390
 
 
391
  /**
 
392
   * true if the mouse is currently pressed.
 
393
   */
 
394
  public boolean keyPressed;
 
395
 
 
396
  /**
 
397
   * the last KeyEvent object passed into a mouse function.
 
398
   */
 
399
  public KeyEvent keyEvent;
 
400
 
 
401
  /**
 
402
   * Gets set to true/false as the applet gains/loses focus.
 
403
   */
 
404
  public boolean focused = false;
 
405
 
 
406
  /**
 
407
   * true if the applet is online.
 
408
   * <P>
 
409
   * This can be used to test how the applet should behave
 
410
   * since online situations are different (no file writing, etc).
 
411
   */
 
412
  public boolean online = false;
 
413
 
 
414
  /**
 
415
   * Time in milliseconds when the applet was started.
 
416
   * <P>
 
417
   * Used by the millis() function.
 
418
   */
 
419
  long millisOffset;
 
420
 
 
421
  /**
 
422
   * The current value of frames per second.
 
423
   * <P>
 
424
   * The initial value will be 10 fps, and will be updated with each
 
425
   * frame thereafter. The value is not instantaneous (since that
 
426
   * wouldn't be very useful since it would jump around so much),
 
427
   * but is instead averaged (integrated) over several frames.
 
428
   * As such, this value won't be valid until after 5-10 frames.
 
429
   */
 
430
  public float frameRate = 10;
 
431
  /** Last time in nanoseconds that frameRate was checked */
 
432
  protected long frameRateLastNanos = 0;
 
433
 
 
434
  /** As of release 0116, frameRate(60) is called as a default */
 
435
  protected float frameRateTarget = 60;
 
436
  protected long frameRatePeriod = 1000000000L / 60L;
 
437
 
 
438
  protected boolean looping;
 
439
 
 
440
  /** flag set to true when a redraw is asked for by the user */
 
441
  protected boolean redraw;
 
442
 
 
443
  /**
 
444
   * How many frames have been displayed since the applet started.
 
445
   * <P>
 
446
   * This value is read-only <EM>do not</EM> attempt to set it,
 
447
   * otherwise bad things will happen.
 
448
   * <P>
 
449
   * Inside setup(), frameCount is 0.
 
450
   * For the first iteration of draw(), frameCount will equal 1.
 
451
   */
 
452
  public int frameCount;
 
453
 
 
454
  /**
 
455
   * true if this applet has had it.
 
456
   */
 
457
  public boolean finished;
 
458
 
 
459
  /**
 
460
   * true if exit() has been called so that things shut down
 
461
   * once the main thread kicks off.
 
462
   */
 
463
  protected boolean exitCalled;
 
464
 
 
465
  Thread thread;
 
466
 
 
467
  protected RegisteredMethods sizeMethods;
 
468
  protected RegisteredMethods preMethods, drawMethods, postMethods;
 
469
  protected RegisteredMethods mouseEventMethods, keyEventMethods;
 
470
  protected RegisteredMethods disposeMethods;
 
471
 
 
472
  // messages to send if attached as an external vm
 
473
 
 
474
  /**
 
475
   * Position of the upper-lefthand corner of the editor window
 
476
   * that launched this applet.
 
477
   */
 
478
  static public final String ARGS_EDITOR_LOCATION = "--editor-location";
 
479
 
 
480
  /**
 
481
   * Location for where to position the applet window on screen.
 
482
   * <P>
 
483
   * This is used by the editor to when saving the previous applet
 
484
   * location, or could be used by other classes to launch at a
 
485
   * specific position on-screen.
 
486
   */
 
487
  static public final String ARGS_EXTERNAL = "--external";
 
488
 
 
489
  static public final String ARGS_LOCATION = "--location";
 
490
 
 
491
  static public final String ARGS_DISPLAY = "--display";
 
492
 
 
493
  static public final String ARGS_BGCOLOR = "--bgcolor";
 
494
 
 
495
  static public final String ARGS_PRESENT = "--present";
 
496
 
 
497
  static public final String ARGS_EXCLUSIVE = "--exclusive";
 
498
 
 
499
  static public final String ARGS_STOP_COLOR = "--stop-color";
 
500
 
 
501
  static public final String ARGS_HIDE_STOP = "--hide-stop";
 
502
 
 
503
  /**
 
504
   * Allows the user or PdeEditor to set a specific sketch folder path.
 
505
   * <P>
 
506
   * Used by PdeEditor to pass in the location where saveFrame()
 
507
   * and all that stuff should write things.
 
508
   */
 
509
  static public final String ARGS_SKETCH_FOLDER = "--sketch-path";
 
510
 
 
511
  /**
 
512
   * When run externally to a PdeEditor,
 
513
   * this is sent by the applet when it quits.
 
514
   */
 
515
  //static public final String EXTERNAL_QUIT = "__QUIT__";
 
516
  static public final String EXTERNAL_STOP = "__STOP__";
 
517
 
 
518
  /**
 
519
   * When run externally to a PDE Editor, this is sent by the applet
 
520
   * whenever the window is moved.
 
521
   * <P>
 
522
   * This is used so that the editor can re-open the sketch window
 
523
   * in the same position as the user last left it.
 
524
   */
 
525
  static public final String EXTERNAL_MOVE = "__MOVE__";
 
526
 
 
527
  /** true if this sketch is being run by the PDE */
 
528
  boolean external = false;
 
529
 
 
530
 
 
531
  static final String ERROR_MIN_MAX =
 
532
    "Cannot use min() or max() on an empty array.";
 
533
 
 
534
 
 
535
  // during rev 0100 dev cycle, working on new threading model,
 
536
  // but need to disable and go conservative with changes in order
 
537
  // to get pdf and audio working properly first.
 
538
  // for 0116, the CRUSTY_THREADS are being disabled to fix lots of bugs.
 
539
  //static final boolean CRUSTY_THREADS = false; //true;
 
540
 
 
541
 
 
542
  public void init() {
 
543
//    println("Calling init()");
 
544
 
 
545
    // send tab keys through to the PApplet
 
546
    setFocusTraversalKeysEnabled(false);
 
547
 
 
548
    millisOffset = System.currentTimeMillis();
 
549
 
 
550
    finished = false; // just for clarity
 
551
 
 
552
    // this will be cleared by draw() if it is not overridden
 
553
    looping = true;
 
554
    redraw = true;  // draw this guy once
 
555
    firstMouse = true;
 
556
 
 
557
    // these need to be inited before setup
 
558
    sizeMethods = new RegisteredMethods();
 
559
    preMethods = new RegisteredMethods();
 
560
    drawMethods = new RegisteredMethods();
 
561
    postMethods = new RegisteredMethods();
 
562
    mouseEventMethods = new RegisteredMethods();
 
563
    keyEventMethods = new RegisteredMethods();
 
564
    disposeMethods = new RegisteredMethods();
 
565
 
 
566
    try {
 
567
      getAppletContext();
 
568
      online = true;
 
569
    } catch (NullPointerException e) {
 
570
      online = false;
 
571
    }
 
572
 
 
573
    try {
 
574
      if (sketchPath == null) {
 
575
        sketchPath = System.getProperty("user.dir");
 
576
      }
 
577
    } catch (Exception e) { }  // may be a security problem
 
578
 
 
579
    Dimension size = getSize();
 
580
    if ((size.width != 0) && (size.height != 0)) {
 
581
      // When this PApplet is embedded inside a Java application with other
 
582
      // Component objects, its size() may already be set externally (perhaps
 
583
      // by a LayoutManager). In this case, honor that size as the default.
 
584
      // Size of the component is set, just create a renderer.
 
585
      g = makeGraphics(size.width, size.height, getSketchRenderer(), null, true);
 
586
      // This doesn't call setSize() or setPreferredSize() because the fact
 
587
      // that a size was already set means that someone is already doing it.
 
588
 
 
589
    } else {
 
590
      // Set the default size, until the user specifies otherwise
 
591
      this.defaultSize = true;
 
592
      int w = getSketchWidth();
 
593
      int h = getSketchHeight();
 
594
      g = makeGraphics(w, h, getSketchRenderer(), null, true);
 
595
      // Fire component resize event
 
596
      setSize(w, h);
 
597
      setPreferredSize(new Dimension(w, h));
 
598
    }
 
599
    width = g.width;
 
600
    height = g.height;
 
601
 
 
602
    addListeners();
 
603
 
 
604
    // this is automatically called in applets
 
605
    // though it's here for applications anyway
 
606
    start();
 
607
  }
 
608
 
 
609
 
 
610
  public int getSketchWidth() {
 
611
    return DEFAULT_WIDTH;
 
612
  }
 
613
 
 
614
 
 
615
  public int getSketchHeight() {
 
616
    return DEFAULT_HEIGHT;
 
617
  }
 
618
 
 
619
 
 
620
  public String getSketchRenderer() {
 
621
    return JAVA2D;
 
622
  }
 
623
 
 
624
 
 
625
  /**
 
626
   * Called by the browser or applet viewer to inform this applet that it
 
627
   * should start its execution. It is called after the init method and
 
628
   * each time the applet is revisited in a Web page.
 
629
   * <p/>
 
630
   * Called explicitly via the first call to PApplet.paint(), because
 
631
   * PAppletGL needs to have a usable screen before getting things rolling.
 
632
   */
 
633
  public void start() {
 
634
    // When running inside a browser, start() will be called when someone
 
635
    // returns to a page containing this applet.
 
636
    // http://dev.processing.org/bugs/show_bug.cgi?id=581
 
637
    finished = false;
 
638
 
 
639
    if (thread != null) return;
 
640
    thread = new Thread(this, "Animation Thread");
 
641
    thread.start();
 
642
  }
 
643
 
 
644
 
 
645
  /**
 
646
   * Called by the browser or applet viewer to inform
 
647
   * this applet that it should stop its execution.
 
648
   * <p/>
 
649
   * Unfortunately, there are no guarantees from the Java spec
 
650
   * when or if stop() will be called (i.e. on browser quit,
 
651
   * or when moving between web pages), and it's not always called.
 
652
   */
 
653
  public void stop() {
 
654
    // bringing this back for 0111, hoping it'll help opengl shutdown
 
655
    finished = true;  // why did i comment this out?
 
656
 
 
657
    // don't run stop and disposers twice
 
658
    if (thread == null) return;
 
659
    thread = null;
 
660
 
 
661
    // call to shut down renderer, in case it needs it (pdf does)
 
662
    if (g != null) g.dispose();
 
663
 
 
664
    // maybe this should be done earlier? might help ensure it gets called
 
665
    // before the vm just craps out since 1.5 craps out so aggressively.
 
666
    disposeMethods.handle();
 
667
  }
 
668
 
 
669
 
 
670
  /**
 
671
   * Called by the browser or applet viewer to inform this applet
 
672
   * that it is being reclaimed and that it should destroy
 
673
   * any resources that it has allocated.
 
674
   * <p/>
 
675
   * This also attempts to call PApplet.stop(), in case there
 
676
   * was an inadvertent override of the stop() function by a user.
 
677
   * <p/>
 
678
   * destroy() supposedly gets called as the applet viewer
 
679
   * is shutting down the applet. stop() is called
 
680
   * first, and then destroy() to really get rid of things.
 
681
   * no guarantees on when they're run (on browser quit, or
 
682
   * when moving between pages), though.
 
683
   */
 
684
  public void destroy() {
 
685
    ((PApplet)this).stop();
 
686
  }
 
687
 
 
688
 
 
689
  /**
 
690
   * This returns the last width and height specified by the user
 
691
   * via the size() command.
 
692
   */
 
693
//  public Dimension getPreferredSize() {
 
694
//    return new Dimension(width, height);
 
695
//  }
 
696
 
 
697
 
 
698
//  public void addNotify() {
 
699
//    super.addNotify();
 
700
//    println("addNotify()");
 
701
//  }
 
702
 
 
703
 
 
704
 
 
705
  //////////////////////////////////////////////////////////////
 
706
 
 
707
 
 
708
  public class RegisteredMethods {
 
709
    int count;
 
710
    Object objects[];
 
711
    Method methods[];
 
712
 
 
713
 
 
714
    // convenience version for no args
 
715
    public void handle() {
 
716
      handle(new Object[] { });
 
717
    }
 
718
 
 
719
    public void handle(Object oargs[]) {
 
720
      for (int i = 0; i < count; i++) {
 
721
        try {
 
722
          //System.out.println(objects[i] + " " + args);
 
723
          methods[i].invoke(objects[i], oargs);
 
724
        } catch (Exception e) {
 
725
          e.printStackTrace();
 
726
        }
 
727
      }
 
728
    }
 
729
 
 
730
    public void add(Object object, Method method) {
 
731
      if (objects == null) {
 
732
        objects = new Object[5];
 
733
        methods = new Method[5];
 
734
      }
 
735
      if (count == objects.length) {
 
736
        objects = (Object[]) PApplet.expand(objects);
 
737
        methods = (Method[]) PApplet.expand(methods);
 
738
//        Object otemp[] = new Object[count << 1];
 
739
//        System.arraycopy(objects, 0, otemp, 0, count);
 
740
//        objects = otemp;
 
741
//        Method mtemp[] = new Method[count << 1];
 
742
//        System.arraycopy(methods, 0, mtemp, 0, count);
 
743
//        methods = mtemp;
 
744
      }
 
745
      objects[count] = object;
 
746
      methods[count] = method;
 
747
      count++;
 
748
    }
 
749
 
 
750
 
 
751
    /**
 
752
     * Removes first object/method pair matched (and only the first,
 
753
     * must be called multiple times if object is registered multiple times).
 
754
     * Does not shrink array afterwards, silently returns if method not found.
 
755
     */
 
756
    public void remove(Object object, Method method) {
 
757
      int index = findIndex(object, method);
 
758
      if (index != -1) {
 
759
        // shift remaining methods by one to preserve ordering
 
760
        count--;
 
761
        for (int i = index; i < count; i++) {
 
762
          objects[i] = objects[i+1];
 
763
          methods[i] = methods[i+1];
 
764
        }
 
765
        // clean things out for the gc's sake
 
766
        objects[count] = null;
 
767
        methods[count] = null;
 
768
      }
 
769
    }
 
770
 
 
771
    protected int findIndex(Object object, Method method) {
 
772
      for (int i = 0; i < count; i++) {
 
773
        if (objects[i] == object && methods[i].equals(method)) {
 
774
          //objects[i].equals() might be overridden, so use == for safety
 
775
          // since here we do care about actual object identity
 
776
          //methods[i]==method is never true even for same method, so must use
 
777
          // equals(), this should be safe because of object identity
 
778
          return i;
 
779
        }
 
780
      }
 
781
      return -1;
 
782
    }
 
783
  }
 
784
 
 
785
 
 
786
  public void registerSize(Object o) {
 
787
    Class<?> methodArgs[] = new Class[] { Integer.TYPE, Integer.TYPE };
 
788
    registerWithArgs(sizeMethods, "size", o, methodArgs);
 
789
  }
 
790
 
 
791
  public void registerPre(Object o) {
 
792
    registerNoArgs(preMethods, "pre", o);
 
793
  }
 
794
 
 
795
  public void registerDraw(Object o) {
 
796
    registerNoArgs(drawMethods, "draw", o);
 
797
  }
 
798
 
 
799
  public void registerPost(Object o) {
 
800
    registerNoArgs(postMethods, "post", o);
 
801
  }
 
802
 
 
803
  public void registerMouseEvent(Object o) {
 
804
    Class<?> methodArgs[] = new Class[] { MouseEvent.class };
 
805
    registerWithArgs(mouseEventMethods, "mouseEvent", o, methodArgs);
 
806
  }
 
807
 
 
808
 
 
809
  public void registerKeyEvent(Object o) {
 
810
    Class<?> methodArgs[] = new Class[] { KeyEvent.class };
 
811
    registerWithArgs(keyEventMethods, "keyEvent", o, methodArgs);
 
812
  }
 
813
 
 
814
  public void registerDispose(Object o) {
 
815
    registerNoArgs(disposeMethods, "dispose", o);
 
816
  }
 
817
 
 
818
 
 
819
  protected void registerNoArgs(RegisteredMethods meth,
 
820
                                String name, Object o) {
 
821
    Class<?> c = o.getClass();
 
822
    try {
 
823
      Method method = c.getMethod(name, new Class[] {});
 
824
      meth.add(o, method);
 
825
 
 
826
    } catch (NoSuchMethodException nsme) {
 
827
      die("There is no public " + name + "() method in the class " +
 
828
          o.getClass().getName());
 
829
 
 
830
    } catch (Exception e) {
 
831
      die("Could not register " + name + " + () for " + o, e);
 
832
    }
 
833
  }
 
834
 
 
835
 
 
836
  protected void registerWithArgs(RegisteredMethods meth,
 
837
                                  String name, Object o, Class<?> cargs[]) {
 
838
    Class<?> c = o.getClass();
 
839
    try {
 
840
      Method method = c.getMethod(name, cargs);
 
841
      meth.add(o, method);
 
842
 
 
843
    } catch (NoSuchMethodException nsme) {
 
844
      die("There is no public " + name + "() method in the class " +
 
845
          o.getClass().getName());
 
846
 
 
847
    } catch (Exception e) {
 
848
      die("Could not register " + name + " + () for " + o, e);
 
849
    }
 
850
  }
 
851
 
 
852
 
 
853
  public void unregisterSize(Object o) {
 
854
    Class<?> methodArgs[] = new Class[] { Integer.TYPE, Integer.TYPE };
 
855
    unregisterWithArgs(sizeMethods, "size", o, methodArgs);
 
856
  }
 
857
 
 
858
  public void unregisterPre(Object o) {
 
859
    unregisterNoArgs(preMethods, "pre", o);
 
860
  }
 
861
 
 
862
  public void unregisterDraw(Object o) {
 
863
    unregisterNoArgs(drawMethods, "draw", o);
 
864
  }
 
865
 
 
866
  public void unregisterPost(Object o) {
 
867
    unregisterNoArgs(postMethods, "post", o);
 
868
  }
 
869
 
 
870
  public void unregisterMouseEvent(Object o) {
 
871
    Class<?> methodArgs[] = new Class[] { MouseEvent.class };
 
872
    unregisterWithArgs(mouseEventMethods, "mouseEvent", o, methodArgs);
 
873
  }
 
874
 
 
875
  public void unregisterKeyEvent(Object o) {
 
876
    Class<?> methodArgs[] = new Class[] { KeyEvent.class };
 
877
    unregisterWithArgs(keyEventMethods, "keyEvent", o, methodArgs);
 
878
  }
 
879
 
 
880
  public void unregisterDispose(Object o) {
 
881
    unregisterNoArgs(disposeMethods, "dispose", o);
 
882
  }
 
883
 
 
884
 
 
885
  protected void unregisterNoArgs(RegisteredMethods meth,
 
886
                                  String name, Object o) {
 
887
    Class<?> c = o.getClass();
 
888
    try {
 
889
      Method method = c.getMethod(name, new Class[] {});
 
890
      meth.remove(o, method);
 
891
    } catch (Exception e) {
 
892
      die("Could not unregister " + name + "() for " + o, e);
 
893
    }
 
894
  }
 
895
 
 
896
 
 
897
  protected void unregisterWithArgs(RegisteredMethods meth,
 
898
                                    String name, Object o, Class<?> cargs[]) {
 
899
    Class<?> c = o.getClass();
 
900
    try {
 
901
      Method method = c.getMethod(name, cargs);
 
902
      meth.remove(o, method);
 
903
    } catch (Exception e) {
 
904
      die("Could not unregister " + name + "() for " + o, e);
 
905
    }
 
906
  }
 
907
 
 
908
 
 
909
  //////////////////////////////////////////////////////////////
 
910
 
 
911
 
 
912
  public void setup() {
 
913
  }
 
914
 
 
915
 
 
916
  public void draw() {
 
917
    // if no draw method, then shut things down
 
918
    //System.out.println("no draw method, goodbye");
 
919
    finished = true;
 
920
  }
 
921
 
 
922
 
 
923
  //////////////////////////////////////////////////////////////
 
924
 
 
925
 
 
926
  protected void resizeRenderer(int iwidth, int iheight) {
 
927
//    println("resizeRenderer request for " + iwidth + " " + iheight);
 
928
    if (width != iwidth || height != iheight) {
 
929
//      println("  former size was " + width + " " + height);
 
930
      g.setSize(iwidth, iheight);
 
931
      width = iwidth;
 
932
      height = iheight;
 
933
    }
 
934
  }
 
935
 
 
936
 
 
937
  /**
 
938
   * Starts up and creates a two-dimensional drawing surface,
 
939
   * or resizes the current drawing surface.
 
940
   * <P>
 
941
   * This should be the first thing called inside of setup().
 
942
   * <P>
 
943
   * If using Java 1.3 or later, this will default to using
 
944
   * PGraphics2, the Java2D-based renderer. If using Java 1.1,
 
945
   * or if PGraphics2 is not available, then PGraphics will be used.
 
946
   * To set your own renderer, use the other version of the size()
 
947
   * method that takes a renderer as its last parameter.
 
948
   * <P>
 
949
   * If called once a renderer has already been set, this will
 
950
   * use the previous renderer and simply resize it.
 
951
   */
 
952
  public void size(int iwidth, int iheight) {
 
953
    size(iwidth, iheight, JAVA2D, null);
 
954
  }
 
955
 
 
956
 
 
957
  public void size(int iwidth, int iheight, String irenderer) {
 
958
    size(iwidth, iheight, irenderer, null);
 
959
  }
 
960
 
 
961
 
 
962
  /**
 
963
   * Creates a new PGraphics object and sets it to the specified size.
 
964
   *
 
965
   * Note that you cannot change the renderer once outside of setup().
 
966
   * In most cases, you can call size() to give it a new size,
 
967
   * but you need to always ask for the same renderer, otherwise
 
968
   * you're gonna run into trouble.
 
969
   *
 
970
   * The size() method should *only* be called from inside the setup() or
 
971
   * draw() methods, so that it is properly run on the main animation thread.
 
972
   * To change the size of a PApplet externally, use setSize(), which will
 
973
   * update the component size, and queue a resize of the renderer as well.
 
974
   */
 
975
  public void size(final int iwidth, final int iheight,
 
976
                   String irenderer, String ipath) {
 
977
    // Run this from the EDT, just cuz it's AWT stuff (or maybe later Swing)
 
978
    SwingUtilities.invokeLater(new Runnable() {
 
979
      public void run() {
 
980
        // Set the preferred size so that the layout managers can handle it
 
981
        setPreferredSize(new Dimension(iwidth, iheight));
 
982
        setSize(iwidth, iheight);
 
983
      }
 
984
    });
 
985
 
 
986
    // ensure that this is an absolute path
 
987
    if (ipath != null) ipath = savePath(ipath);
 
988
 
 
989
    String currentRenderer = g.getClass().getName();
 
990
    if (currentRenderer.equals(irenderer)) {
 
991
      // Avoid infinite loop of throwing exception to reset renderer
 
992
      resizeRenderer(iwidth, iheight);
 
993
      //redraw();  // will only be called insize draw()
 
994
 
 
995
    } else {  // renderer is being changed
 
996
      // otherwise ok to fall through and create renderer below
 
997
      // the renderer is changing, so need to create a new object
 
998
      g = makeGraphics(iwidth, iheight, irenderer, ipath, true);
 
999
      width = iwidth;
 
1000
      height = iheight;
 
1001
 
 
1002
      // fire resize event to make sure the applet is the proper size
 
1003
//      setSize(iwidth, iheight);
 
1004
      // this is the function that will run if the user does their own
 
1005
      // size() command inside setup, so set defaultSize to false.
 
1006
      defaultSize = false;
 
1007
 
 
1008
      // throw an exception so that setup() is called again
 
1009
      // but with a properly sized render
 
1010
      // this is for opengl, which needs a valid, properly sized
 
1011
      // display before calling anything inside setup().
 
1012
      throw new RendererChangeException();
 
1013
    }
 
1014
  }
 
1015
 
 
1016
 
 
1017
  /**
 
1018
   * Create an offscreen PGraphics object for drawing. This can be used
 
1019
   * for bitmap or vector images drawing or rendering.
 
1020
   * <UL>
 
1021
   * <LI>Do not use "new PGraphicsXxxx()", use this method. This method
 
1022
   * ensures that internal variables are set up properly that tie the
 
1023
   * new graphics context back to its parent PApplet.
 
1024
   * <LI>The basic way to create bitmap images is to use the <A
 
1025
   * HREF="http://processing.org/reference/saveFrame_.html">saveFrame()</A>
 
1026
   * function.
 
1027
   * <LI>If you want to create a really large scene and write that,
 
1028
   * first make sure that you've allocated a lot of memory in the Preferences.
 
1029
   * <LI>If you want to create images that are larger than the screen,
 
1030
   * you should create your own PGraphics object, draw to that, and use
 
1031
   * <A HREF="http://processing.org/reference/save_.html">save()</A>.
 
1032
   * For now, it's best to use <A HREF="http://dev.processing.org/reference/everything/javadoc/processing/core/PGraphics3D.html">P3D</A> in this scenario.
 
1033
   * P2D is currently disabled, and the JAVA2D default will give mixed
 
1034
   * results. An example of using P3D:
 
1035
   * <PRE>
 
1036
   *
 
1037
   * PGraphics big;
 
1038
   *
 
1039
   * void setup() {
 
1040
   *   big = createGraphics(3000, 3000, P3D);
 
1041
   *
 
1042
   *   big.beginDraw();
 
1043
   *   big.background(128);
 
1044
   *   big.line(20, 1800, 1800, 900);
 
1045
   *   // etc..
 
1046
   *   big.endDraw();
 
1047
   *
 
1048
   *   // make sure the file is written to the sketch folder
 
1049
   *   big.save("big.tif");
 
1050
   * }
 
1051
   *
 
1052
   * </PRE>
 
1053
   * <LI>It's important to always wrap drawing to createGraphics() with
 
1054
   * beginDraw() and endDraw() (beginFrame() and endFrame() prior to
 
1055
   * revision 0115). The reason is that the renderer needs to know when
 
1056
   * drawing has stopped, so that it can update itself internally.
 
1057
   * This also handles calling the defaults() method, for people familiar
 
1058
   * with that.
 
1059
   * <LI>It's not possible to use createGraphics() with the OPENGL renderer,
 
1060
   * because it doesn't allow offscreen use.
 
1061
   * <LI>With Processing 0115 and later, it's possible to write images in
 
1062
   * formats other than the default .tga and .tiff. The exact formats and
 
1063
   * background information can be found in the developer's reference for
 
1064
   * <A HREF="http://dev.processing.org/reference/core/javadoc/processing/core/PImage.html#save(java.lang.String)">PImage.save()</A>.
 
1065
   * </UL>
 
1066
   */
 
1067
  public PGraphics createGraphics(int iwidth, int iheight,
 
1068
                                  String irenderer) {
 
1069
    PGraphics pg = makeGraphics(iwidth, iheight, irenderer, null, false);
 
1070
    //pg.parent = this;  // make save() work
 
1071
    return pg;
 
1072
  }
 
1073
 
 
1074
 
 
1075
  /**
 
1076
   * Create an offscreen graphics surface for drawing, in this case
 
1077
   * for a renderer that writes to a file (such as PDF or DXF).
 
1078
   * @param ipath can be an absolute or relative path
 
1079
   */
 
1080
  public PGraphics createGraphics(int iwidth, int iheight,
 
1081
                                  String irenderer, String ipath) {
 
1082
    if (ipath != null) {
 
1083
      ipath = savePath(ipath);
 
1084
    }
 
1085
    PGraphics pg = makeGraphics(iwidth, iheight, irenderer, ipath, false);
 
1086
    pg.parent = this;  // make save() work
 
1087
    return pg;
 
1088
  }
 
1089
 
 
1090
 
 
1091
  /**
 
1092
   * Version of createGraphics() used internally.
 
1093
   *
 
1094
   * @param ipath must be an absolute path, usually set via savePath()
 
1095
   * @oaram applet the parent applet object, this should only be non-null
 
1096
   *               in cases where this is the main drawing surface object.
 
1097
   */
 
1098
  protected PGraphics makeGraphics(int iwidth, int iheight,
 
1099
                                   String irenderer, String ipath,
 
1100
                                   boolean iprimary) {
 
1101
    if (irenderer.equals(OPENGL)) {
 
1102
      if (PApplet.platform == WINDOWS) {
 
1103
        String s = System.getProperty("java.version");
 
1104
        if (s != null) {
 
1105
          if (s.equals("1.5.0_10")) {
 
1106
            System.err.println("OpenGL support is broken with Java 1.5.0_10");
 
1107
            System.err.println("See http://dev.processing.org" +
 
1108
                               "/bugs/show_bug.cgi?id=513 for more info.");
 
1109
            throw new RuntimeException("Please update your Java " +
 
1110
                                       "installation (see bug #513)");
 
1111
          }
 
1112
        }
 
1113
      }
 
1114
    }
 
1115
 
 
1116
//    if (irenderer.equals(P2D)) {
 
1117
//      throw new RuntimeException("The P2D renderer is currently disabled, " +
 
1118
//                                 "please use P3D or JAVA2D.");
 
1119
//    }
 
1120
 
 
1121
    String openglError =
 
1122
      "Before using OpenGL, first select " +
 
1123
      "Import Library > opengl from the Sketch menu.";
 
1124
 
 
1125
    try {
 
1126
      /*
 
1127
      Class<?> rendererClass = Class.forName(irenderer);
 
1128
 
 
1129
      Class<?> constructorParams[] = null;
 
1130
      Object constructorValues[] = null;
 
1131
 
 
1132
      if (ipath == null) {
 
1133
        constructorParams = new Class[] {
 
1134
          Integer.TYPE, Integer.TYPE, PApplet.class
 
1135
        };
 
1136
        constructorValues = new Object[] {
 
1137
          new Integer(iwidth), new Integer(iheight), this
 
1138
        };
 
1139
      } else {
 
1140
        constructorParams = new Class[] {
 
1141
          Integer.TYPE, Integer.TYPE, PApplet.class, String.class
 
1142
        };
 
1143
        constructorValues = new Object[] {
 
1144
          new Integer(iwidth), new Integer(iheight), this, ipath
 
1145
        };
 
1146
      }
 
1147
 
 
1148
      Constructor<?> constructor =
 
1149
        rendererClass.getConstructor(constructorParams);
 
1150
      PGraphics pg = (PGraphics) constructor.newInstance(constructorValues);
 
1151
      */
 
1152
 
 
1153
      Class<?> rendererClass =
 
1154
        Thread.currentThread().getContextClassLoader().loadClass(irenderer);
 
1155
 
 
1156
      //Class<?> params[] = null;
 
1157
      //PApplet.println(rendererClass.getConstructors());
 
1158
      Constructor<?> constructor = rendererClass.getConstructor(new Class[] { });
 
1159
      PGraphics pg = (PGraphics) constructor.newInstance();
 
1160
 
 
1161
      pg.setParent(this);
 
1162
      pg.setPrimary(iprimary);
 
1163
      if (ipath != null) pg.setPath(ipath);
 
1164
      pg.setSize(iwidth, iheight);
 
1165
 
 
1166
      // everything worked, return it
 
1167
      return pg;
 
1168
 
 
1169
    } catch (InvocationTargetException ite) {
 
1170
      String msg = ite.getTargetException().getMessage();
 
1171
      if ((msg != null) &&
 
1172
          (msg.indexOf("no jogl in java.library.path") != -1)) {
 
1173
        throw new RuntimeException(openglError +
 
1174
                                   " (The native library is missing.)");
 
1175
 
 
1176
      } else {
 
1177
        ite.getTargetException().printStackTrace();
 
1178
        Throwable target = ite.getTargetException();
 
1179
        if (platform == MACOSX) target.printStackTrace(System.out);  // bug
 
1180
        // neither of these help, or work
 
1181
        //target.printStackTrace(System.err);
 
1182
        //System.err.flush();
 
1183
        //System.out.println(System.err);  // and the object isn't null
 
1184
        throw new RuntimeException(target.getMessage());
 
1185
      }
 
1186
 
 
1187
    } catch (ClassNotFoundException cnfe) {
 
1188
      if (cnfe.getMessage().indexOf("processing.opengl.PGraphicsGL") != -1) {
 
1189
        throw new RuntimeException(openglError +
 
1190
                                   " (The library .jar file is missing.)");
 
1191
      } else {
 
1192
        throw new RuntimeException("You need to use \"Import Library\" " +
 
1193
                                   "to add " + irenderer + " to your sketch.");
 
1194
      }
 
1195
 
 
1196
    } catch (Exception e) {
 
1197
      //System.out.println("ex3");
 
1198
      if ((e instanceof IllegalArgumentException) ||
 
1199
          (e instanceof NoSuchMethodException) ||
 
1200
          (e instanceof IllegalAccessException)) {
 
1201
        e.printStackTrace();
 
1202
        /*
 
1203
        String msg = "public " +
 
1204
          irenderer.substring(irenderer.lastIndexOf('.') + 1) +
 
1205
          "(int width, int height, PApplet parent" +
 
1206
          ((ipath == null) ? "" : ", String filename") +
 
1207
          ") does not exist.";
 
1208
          */
 
1209
        String msg = irenderer + " needs to be updated " +
 
1210
          "for the current release of Processing.";
 
1211
        throw new RuntimeException(msg);
 
1212
 
 
1213
      } else {
 
1214
        if (platform == MACOSX) e.printStackTrace(System.out);
 
1215
        throw new RuntimeException(e.getMessage());
 
1216
      }
 
1217
    }
 
1218
  }
 
1219
 
 
1220
 
 
1221
  /**
 
1222
   * Preferred method of creating new PImage objects, ensures that a
 
1223
   * reference to the parent PApplet is included, which makes save() work
 
1224
   * without needing an absolute path.
 
1225
   */
 
1226
  public PImage createImage(int wide, int high, int format) {
 
1227
    PImage image = new PImage(wide, high, format);
 
1228
    image.parent = this;  // make save() work
 
1229
    return image;
 
1230
  }
 
1231
 
 
1232
 
 
1233
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
 
1234
 
 
1235
 
 
1236
  public void update(Graphics screen) {
 
1237
    paint(screen);
 
1238
  }
 
1239
 
 
1240
 
 
1241
  //synchronized public void paint(Graphics screen) {  // shutting off for 0146
 
1242
  public void paint(Graphics screen) {
 
1243
    // ignore the very first call to paint, since it's coming
 
1244
    // from the o.s., and the applet will soon update itself anyway.
 
1245
    if (frameCount == 0) {
 
1246
//      println("Skipping frame");
 
1247
      // paint() may be called more than once before things
 
1248
      // are finally painted to the screen and the thread gets going
 
1249
      return;
 
1250
    }
 
1251
 
 
1252
    // without ignoring the first call, the first several frames
 
1253
    // are confused because paint() gets called in the midst of
 
1254
    // the initial nextFrame() call, so there are multiple
 
1255
    // updates fighting with one another.
 
1256
 
 
1257
    // g.image is synchronized so that draw/loop and paint don't
 
1258
    // try to fight over it. this was causing a randomized slowdown
 
1259
    // that would cut the frameRate into a third on macosx,
 
1260
    // and is probably related to the windows sluggishness bug too
 
1261
 
 
1262
    // make sure the screen is visible and usable
 
1263
    // (also prevents over-drawing when using PGraphicsOpenGL)
 
1264
    if ((g != null) && (g.image != null)) {
 
1265
//      println("inside paint(), screen.drawImage()");
 
1266
      screen.drawImage(g.image, 0, 0, null);
 
1267
    }
 
1268
  }
 
1269
 
 
1270
 
 
1271
  // active paint method
 
1272
  protected void paint() {
 
1273
    try {
 
1274
      Graphics screen = this.getGraphics();
 
1275
      if (screen != null) {
 
1276
        if ((g != null) && (g.image != null)) {
 
1277
          screen.drawImage(g.image, 0, 0, null);
 
1278
        }
 
1279
        Toolkit.getDefaultToolkit().sync();
 
1280
      }
 
1281
    } catch (Exception e) {
 
1282
      // Seen on applet destroy, maybe can ignore?
 
1283
      e.printStackTrace();
 
1284
 
 
1285
//    } finally {
 
1286
//      if (g != null) {
 
1287
//        g.dispose();
 
1288
//      }
 
1289
    }
 
1290
  }
 
1291
 
 
1292
 
 
1293
  //////////////////////////////////////////////////////////////
 
1294
 
 
1295
 
 
1296
  /**
 
1297
   * Main method for the primary animation thread.
 
1298
   *
 
1299
   * <A HREF="http://java.sun.com/products/jfc/tsc/articles/painting/">Painting in AWT and Swing</A>
 
1300
   */
 
1301
  public void run() {  // not good to make this synchronized, locks things up
 
1302
    long beforeTime = System.nanoTime();
 
1303
    long overSleepTime = 0L;
 
1304
 
 
1305
    int noDelays = 0;
 
1306
    // Number of frames with a delay of 0 ms before the
 
1307
    // animation thread yields to other running threads.
 
1308
    final int NO_DELAYS_PER_YIELD = 15;
 
1309
 
 
1310
    /*
 
1311
      // this has to be called after the exception is thrown,
 
1312
      // otherwise the supporting libs won't have a valid context to draw to
 
1313
      Object methodArgs[] =
 
1314
        new Object[] { new Integer(width), new Integer(height) };
 
1315
      sizeMethods.handle(methodArgs);
 
1316
     */
 
1317
 
 
1318
    while ((Thread.currentThread() == thread) && !finished) {
 
1319
      // Don't resize the renderer from the EDT (i.e. from a ComponentEvent),
 
1320
      // otherwise it may attempt a resize mid-render.
 
1321
      if (resizeRequest) {
 
1322
        resizeRenderer(resizeWidth, resizeHeight);
 
1323
        resizeRequest = false;
 
1324
      }
 
1325
 
 
1326
      // render a single frame
 
1327
      handleDraw();
 
1328
 
 
1329
      if (frameCount == 1) {
 
1330
        // Call the request focus event once the image is sure to be on
 
1331
        // screen and the component is valid. The OpenGL renderer will
 
1332
        // request focus for its canvas inside beginDraw().
 
1333
        // http://java.sun.com/j2se/1.4.2/docs/api/java/awt/doc-files/FocusSpec.html
 
1334
        //println("requesting focus");
 
1335
        requestFocus();
 
1336
      }
 
1337
 
 
1338
      // wait for update & paint to happen before drawing next frame
 
1339
      // this is necessary since the drawing is sometimes in a
 
1340
      // separate thread, meaning that the next frame will start
 
1341
      // before the update/paint is completed
 
1342
 
 
1343
      long afterTime = System.nanoTime();
 
1344
      long timeDiff = afterTime - beforeTime;
 
1345
      //System.out.println("time diff is " + timeDiff);
 
1346
      long sleepTime = (frameRatePeriod - timeDiff) - overSleepTime;
 
1347
 
 
1348
      if (sleepTime > 0) {  // some time left in this cycle
 
1349
        try {
 
1350
//          Thread.sleep(sleepTime / 1000000L);  // nanoseconds -> milliseconds
 
1351
          Thread.sleep(sleepTime / 1000000L, (int) (sleepTime % 1000000L));
 
1352
          noDelays = 0;  // Got some sleep, not delaying anymore
 
1353
        } catch (InterruptedException ex) { }
 
1354
 
 
1355
        overSleepTime = (System.nanoTime() - afterTime) - sleepTime;
 
1356
        //System.out.println("  oversleep is " + overSleepTime);
 
1357
 
 
1358
      } else {    // sleepTime <= 0; the frame took longer than the period
 
1359
//        excess -= sleepTime;  // store excess time value
 
1360
        overSleepTime = 0L;
 
1361
 
 
1362
        if (noDelays > NO_DELAYS_PER_YIELD) {
 
1363
          Thread.yield();   // give another thread a chance to run
 
1364
          noDelays = 0;
 
1365
        }
 
1366
      }
 
1367
 
 
1368
      beforeTime = System.nanoTime();
 
1369
    }
 
1370
 
 
1371
    stop();  // call to shutdown libs?
 
1372
 
 
1373
    // If the user called the exit() function, the window should close,
 
1374
    // rather than the sketch just halting.
 
1375
    if (exitCalled) {
 
1376
      exit2();
 
1377
    }
 
1378
  }
 
1379
 
 
1380
 
 
1381
  //synchronized public void handleDisplay() {
 
1382
  public void handleDraw() {
 
1383
    if (g != null && (looping || redraw)) {
 
1384
      if (!g.canDraw()) {
 
1385
        // Don't draw if the renderer is not yet ready.
 
1386
        // (e.g. OpenGL has to wait for a peer to be on screen)
 
1387
        return;
 
1388
      }
 
1389
 
 
1390
      //System.out.println("handleDraw() " + frameCount);
 
1391
 
 
1392
      g.beginDraw();
 
1393
      if (recorder != null) {
 
1394
        recorder.beginDraw();
 
1395
      }
 
1396
 
 
1397
      long now = System.nanoTime();
 
1398
 
 
1399
      if (frameCount == 0) {
 
1400
        try {
 
1401
          //println("Calling setup()");
 
1402
          setup();
 
1403
          //println("Done with setup()");
 
1404
 
 
1405
        } catch (RendererChangeException e) {
 
1406
          // Give up, instead set the new renderer and re-attempt setup()
 
1407
          return;
 
1408
        }
 
1409
        this.defaultSize = false;
 
1410
 
 
1411
      } else {  // frameCount > 0, meaning an actual draw()
 
1412
        // update the current frameRate
 
1413
        double rate = 1000000.0 / ((now - frameRateLastNanos) / 1000000.0);
 
1414
        float instantaneousRate = (float) rate / 1000.0f;
 
1415
        frameRate = (frameRate * 0.9f) + (instantaneousRate * 0.1f);
 
1416
 
 
1417
        preMethods.handle();
 
1418
 
 
1419
        // use dmouseX/Y as previous mouse pos, since this is the
 
1420
        // last position the mouse was in during the previous draw.
 
1421
        pmouseX = dmouseX;
 
1422
        pmouseY = dmouseY;
 
1423
 
 
1424
        //println("Calling draw()");
 
1425
        draw();
 
1426
        //println("Done calling draw()");
 
1427
 
 
1428
        // dmouseX/Y is updated only once per frame (unlike emouseX/Y)
 
1429
        dmouseX = mouseX;
 
1430
        dmouseY = mouseY;
 
1431
 
 
1432
        // these are called *after* loop so that valid
 
1433
        // drawing commands can be run inside them. it can't
 
1434
        // be before, since a call to background() would wipe
 
1435
        // out anything that had been drawn so far.
 
1436
        dequeueMouseEvents();
 
1437
        dequeueKeyEvents();
 
1438
 
 
1439
        drawMethods.handle();
 
1440
 
 
1441
        redraw = false;  // unset 'redraw' flag in case it was set
 
1442
        // (only do this once draw() has run, not just setup())
 
1443
 
 
1444
      }
 
1445
 
 
1446
      g.endDraw();
 
1447
      if (recorder != null) {
 
1448
        recorder.endDraw();
 
1449
      }
 
1450
 
 
1451
      frameRateLastNanos = now;
 
1452
      frameCount++;
 
1453
 
 
1454
      // Actively render the screen
 
1455
      paint();
 
1456
 
 
1457
//    repaint();
 
1458
//    getToolkit().sync();  // force repaint now (proper method)
 
1459
 
 
1460
      postMethods.handle();
 
1461
    }
 
1462
  }
 
1463
 
 
1464
 
 
1465
  //////////////////////////////////////////////////////////////
 
1466
 
 
1467
 
 
1468
 
 
1469
  synchronized public void redraw() {
 
1470
    if (!looping) {
 
1471
      redraw = true;
 
1472
//      if (thread != null) {
 
1473
//        // wake from sleep (necessary otherwise it'll be
 
1474
//        // up to 10 seconds before update)
 
1475
//        if (CRUSTY_THREADS) {
 
1476
//          thread.interrupt();
 
1477
//        } else {
 
1478
//          synchronized (blocker) {
 
1479
//            blocker.notifyAll();
 
1480
//          }
 
1481
//        }
 
1482
//      }
 
1483
    }
 
1484
  }
 
1485
 
 
1486
 
 
1487
  synchronized public void loop() {
 
1488
    if (!looping) {
 
1489
      looping = true;
 
1490
    }
 
1491
  }
 
1492
 
 
1493
 
 
1494
  synchronized public void noLoop() {
 
1495
    if (looping) {
 
1496
      looping = false;
 
1497
    }
 
1498
  }
 
1499
 
 
1500
 
 
1501
  //////////////////////////////////////////////////////////////
 
1502
 
 
1503
 
 
1504
  public void addListeners() {
 
1505
    addMouseListener(this);
 
1506
    addMouseMotionListener(this);
 
1507
    addKeyListener(this);
 
1508
    addFocusListener(this);
 
1509
 
 
1510
    addComponentListener(new ComponentAdapter() {
 
1511
      public void componentResized(ComponentEvent e) {
 
1512
        Component c = e.getComponent();
 
1513
        //System.out.println("componentResized() " + c);
 
1514
        Rectangle bounds = c.getBounds();
 
1515
        resizeRequest = true;
 
1516
        resizeWidth = bounds.width;
 
1517
        resizeHeight = bounds.height;
 
1518
      }
 
1519
    });
 
1520
  }
 
1521
 
 
1522
 
 
1523
  //////////////////////////////////////////////////////////////
 
1524
 
 
1525
 
 
1526
  MouseEvent mouseEventQueue[] = new MouseEvent[10];
 
1527
  int mouseEventCount;
 
1528
 
 
1529
  protected void enqueueMouseEvent(MouseEvent e) {
 
1530
    synchronized (mouseEventQueue) {
 
1531
      if (mouseEventCount == mouseEventQueue.length) {
 
1532
        MouseEvent temp[] = new MouseEvent[mouseEventCount << 1];
 
1533
        System.arraycopy(mouseEventQueue, 0, temp, 0, mouseEventCount);
 
1534
        mouseEventQueue = temp;
 
1535
      }
 
1536
      mouseEventQueue[mouseEventCount++] = e;
 
1537
    }
 
1538
  }
 
1539
 
 
1540
  protected void dequeueMouseEvents() {
 
1541
    synchronized (mouseEventQueue) {
 
1542
      for (int i = 0; i < mouseEventCount; i++) {
 
1543
        mouseEvent = mouseEventQueue[i];
 
1544
        handleMouseEvent(mouseEvent);
 
1545
      }
 
1546
      mouseEventCount = 0;
 
1547
    }
 
1548
  }
 
1549
 
 
1550
 
 
1551
  /**
 
1552
   * Actually take action based on a mouse event.
 
1553
   * Internally updates mouseX, mouseY, mousePressed, and mouseEvent.
 
1554
   * Then it calls the event type with no params,
 
1555
   * i.e. mousePressed() or mouseReleased() that the user may have
 
1556
   * overloaded to do something more useful.
 
1557
   */
 
1558
  protected void handleMouseEvent(MouseEvent event) {
 
1559
    int id = event.getID();
 
1560
 
 
1561
    // http://dev.processing.org/bugs/show_bug.cgi?id=170
 
1562
    // also prevents mouseExited() on the mac from hosing the mouse
 
1563
    // position, because x/y are bizarre values on the exit event.
 
1564
    // see also the id check below.. both of these go together
 
1565
    if ((id == MouseEvent.MOUSE_DRAGGED) ||
 
1566
        (id == MouseEvent.MOUSE_MOVED)) {
 
1567
      pmouseX = emouseX;
 
1568
      pmouseY = emouseY;
 
1569
      mouseX = event.getX();
 
1570
      mouseY = event.getY();
 
1571
    }
 
1572
 
 
1573
    mouseEvent = event;
 
1574
 
 
1575
    int modifiers = event.getModifiers();
 
1576
    if ((modifiers & InputEvent.BUTTON1_MASK) != 0) {
 
1577
      mouseButton = LEFT;
 
1578
    } else if ((modifiers & InputEvent.BUTTON2_MASK) != 0) {
 
1579
      mouseButton = CENTER;
 
1580
    } else if ((modifiers & InputEvent.BUTTON3_MASK) != 0) {
 
1581
      mouseButton = RIGHT;
 
1582
    }
 
1583
    // if running on macos, allow ctrl-click as right mouse
 
1584
    if (platform == MACOSX) {
 
1585
      if (mouseEvent.isPopupTrigger()) {
 
1586
        mouseButton = RIGHT;
 
1587
      }
 
1588
    }
 
1589
 
 
1590
    mouseEventMethods.handle(new Object[] { event });
 
1591
 
 
1592
    // this used to only be called on mouseMoved and mouseDragged
 
1593
    // change it back if people run into trouble
 
1594
    if (firstMouse) {
 
1595
      pmouseX = mouseX;
 
1596
      pmouseY = mouseY;
 
1597
      dmouseX = mouseX;
 
1598
      dmouseY = mouseY;
 
1599
      firstMouse = false;
 
1600
    }
 
1601
 
 
1602
    //println(event);
 
1603
 
 
1604
    switch (id) {
 
1605
    case MouseEvent.MOUSE_PRESSED:
 
1606
      mousePressed = true;
 
1607
      mousePressed();
 
1608
      break;
 
1609
    case MouseEvent.MOUSE_RELEASED:
 
1610
      mousePressed = false;
 
1611
      mouseReleased();
 
1612
      break;
 
1613
    case MouseEvent.MOUSE_CLICKED:
 
1614
      mouseClicked();
 
1615
      break;
 
1616
    case MouseEvent.MOUSE_DRAGGED:
 
1617
      mouseDragged();
 
1618
      break;
 
1619
    case MouseEvent.MOUSE_MOVED:
 
1620
      mouseMoved();
 
1621
      break;
 
1622
    }
 
1623
 
 
1624
    if ((id == MouseEvent.MOUSE_DRAGGED) ||
 
1625
        (id == MouseEvent.MOUSE_MOVED)) {
 
1626
      emouseX = mouseX;
 
1627
      emouseY = mouseY;
 
1628
    }
 
1629
  }
 
1630
 
 
1631
 
 
1632
  /**
 
1633
   * Figure out how to process a mouse event. When loop() has been
 
1634
   * called, the events will be queued up until drawing is complete.
 
1635
   * If noLoop() has been called, then events will happen immediately.
 
1636
   */
 
1637
  protected void checkMouseEvent(MouseEvent event) {
 
1638
    if (looping) {
 
1639
      enqueueMouseEvent(event);
 
1640
    } else {
 
1641
      handleMouseEvent(event);
 
1642
    }
 
1643
  }
 
1644
 
 
1645
 
 
1646
  /**
 
1647
   * If you override this or any function that takes a "MouseEvent e"
 
1648
   * without calling its super.mouseXxxx() then mouseX, mouseY,
 
1649
   * mousePressed, and mouseEvent will no longer be set.
 
1650
   */
 
1651
  public void mousePressed(MouseEvent e) {
 
1652
    checkMouseEvent(e);
 
1653
  }
 
1654
 
 
1655
  public void mouseReleased(MouseEvent e) {
 
1656
    checkMouseEvent(e);
 
1657
  }
 
1658
 
 
1659
  public void mouseClicked(MouseEvent e) {
 
1660
    checkMouseEvent(e);
 
1661
  }
 
1662
 
 
1663
  public void mouseEntered(MouseEvent e) {
 
1664
    checkMouseEvent(e);
 
1665
  }
 
1666
 
 
1667
  public void mouseExited(MouseEvent e) {
 
1668
    checkMouseEvent(e);
 
1669
  }
 
1670
 
 
1671
  public void mouseDragged(MouseEvent e) {
 
1672
    checkMouseEvent(e);
 
1673
  }
 
1674
 
 
1675
  public void mouseMoved(MouseEvent e) {
 
1676
    checkMouseEvent(e);
 
1677
  }
 
1678
 
 
1679
 
 
1680
  /**
 
1681
   * Mouse has been pressed, and should be considered "down"
 
1682
   * until mouseReleased() is called. If you must, use
 
1683
   * int button = mouseEvent.getButton();
 
1684
   * to figure out which button was clicked. It will be one of:
 
1685
   * MouseEvent.BUTTON1, MouseEvent.BUTTON2, MouseEvent.BUTTON3
 
1686
   * Note, however, that this is completely inconsistent across
 
1687
   * platforms.
 
1688
   */
 
1689
  public void mousePressed() { }
 
1690
 
 
1691
  /**
 
1692
   * Mouse button has been released.
 
1693
   */
 
1694
  public void mouseReleased() { }
 
1695
 
 
1696
  /**
 
1697
   * When the mouse is clicked, mousePressed() will be called,
 
1698
   * then mouseReleased(), then mouseClicked(). Note that
 
1699
   * mousePressed is already false inside of mouseClicked().
 
1700
   */
 
1701
  public void mouseClicked() { }
 
1702
 
 
1703
  /**
 
1704
   * Mouse button is pressed and the mouse has been dragged.
 
1705
   */
 
1706
  public void mouseDragged() { }
 
1707
 
 
1708
  /**
 
1709
   * Mouse button is not pressed but the mouse has changed locations.
 
1710
   */
 
1711
  public void mouseMoved() { }
 
1712
 
 
1713
 
 
1714
  //////////////////////////////////////////////////////////////
 
1715
 
 
1716
 
 
1717
  KeyEvent keyEventQueue[] = new KeyEvent[10];
 
1718
  int keyEventCount;
 
1719
 
 
1720
  protected void enqueueKeyEvent(KeyEvent e) {
 
1721
    synchronized (keyEventQueue) {
 
1722
      if (keyEventCount == keyEventQueue.length) {
 
1723
        KeyEvent temp[] = new KeyEvent[keyEventCount << 1];
 
1724
        System.arraycopy(keyEventQueue, 0, temp, 0, keyEventCount);
 
1725
        keyEventQueue = temp;
 
1726
      }
 
1727
      keyEventQueue[keyEventCount++] = e;
 
1728
    }
 
1729
  }
 
1730
 
 
1731
  protected void dequeueKeyEvents() {
 
1732
    synchronized (keyEventQueue) {
 
1733
      for (int i = 0; i < keyEventCount; i++) {
 
1734
        keyEvent = keyEventQueue[i];
 
1735
        handleKeyEvent(keyEvent);
 
1736
      }
 
1737
      keyEventCount = 0;
 
1738
    }
 
1739
  }
 
1740
 
 
1741
 
 
1742
  protected void handleKeyEvent(KeyEvent event) {
 
1743
    keyEvent = event;
 
1744
    key = event.getKeyChar();
 
1745
    keyCode = event.getKeyCode();
 
1746
 
 
1747
    keyEventMethods.handle(new Object[] { event });
 
1748
 
 
1749
    switch (event.getID()) {
 
1750
    case KeyEvent.KEY_PRESSED:
 
1751
      keyPressed = true;
 
1752
      keyPressed();
 
1753
      break;
 
1754
    case KeyEvent.KEY_RELEASED:
 
1755
      keyPressed = false;
 
1756
      keyReleased();
 
1757
      break;
 
1758
    case KeyEvent.KEY_TYPED:
 
1759
      keyTyped();
 
1760
      break;
 
1761
    }
 
1762
 
 
1763
    // if someone else wants to intercept the key, they should
 
1764
    // set key to zero (or something besides the ESC).
 
1765
    if (event.getID() == KeyEvent.KEY_PRESSED) {
 
1766
      if (key == KeyEvent.VK_ESCAPE) {
 
1767
        exit();
 
1768
      }
 
1769
      // When running tethered to the Processing application, respond to
 
1770
      // Ctrl-W (or Cmd-W) events by closing the sketch. Disable this behavior
 
1771
      // when running independently, because this sketch may be one component
 
1772
      // embedded inside an application that has its own close behavior.
 
1773
      if (external &&
 
1774
          event.getModifiers() == MENU_SHORTCUT &&
 
1775
          event.getKeyCode() == 'W') {
 
1776
        exit();
 
1777
      }
 
1778
    }
 
1779
  }
 
1780
 
 
1781
 
 
1782
  protected void checkKeyEvent(KeyEvent event) {
 
1783
    if (looping) {
 
1784
      enqueueKeyEvent(event);
 
1785
    } else {
 
1786
      handleKeyEvent(event);
 
1787
    }
 
1788
  }
 
1789
 
 
1790
 
 
1791
  /**
 
1792
   * Overriding keyXxxxx(KeyEvent e) functions will cause the 'key',
 
1793
   * 'keyCode', and 'keyEvent' variables to no longer work;
 
1794
   * key events will no longer be queued until the end of draw();
 
1795
   * and the keyPressed(), keyReleased() and keyTyped() methods
 
1796
   * will no longer be called.
 
1797
   */
 
1798
  public void keyPressed(KeyEvent e) { checkKeyEvent(e); }
 
1799
  public void keyReleased(KeyEvent e) { checkKeyEvent(e); }
 
1800
  public void keyTyped(KeyEvent e) { checkKeyEvent(e); }
 
1801
 
 
1802
 
 
1803
  /**
 
1804
   * Called each time a single key on the keyboard is pressed.
 
1805
   * Because of how operating systems handle key repeats, holding
 
1806
   * down a key will cause multiple calls to keyPressed(), because
 
1807
   * the OS repeat takes over.
 
1808
   * <P>
 
1809
   * Examples for key handling:
 
1810
   * (Tested on Windows XP, please notify if different on other
 
1811
   * platforms, I have a feeling Mac OS and Linux may do otherwise)
 
1812
   * <PRE>
 
1813
   * 1. Pressing 'a' on the keyboard:
 
1814
   *    keyPressed  with key == 'a' and keyCode == 'A'
 
1815
   *    keyTyped    with key == 'a' and keyCode ==  0
 
1816
   *    keyReleased with key == 'a' and keyCode == 'A'
 
1817
   *
 
1818
   * 2. Pressing 'A' on the keyboard:
 
1819
   *    keyPressed  with key == 'A' and keyCode == 'A'
 
1820
   *    keyTyped    with key == 'A' and keyCode ==  0
 
1821
   *    keyReleased with key == 'A' and keyCode == 'A'
 
1822
   *
 
1823
   * 3. Pressing 'shift', then 'a' on the keyboard (caps lock is off):
 
1824
   *    keyPressed  with key == CODED and keyCode == SHIFT
 
1825
   *    keyPressed  with key == 'A'   and keyCode == 'A'
 
1826
   *    keyTyped    with key == 'A'   and keyCode == 0
 
1827
   *    keyReleased with key == 'A'   and keyCode == 'A'
 
1828
   *    keyReleased with key == CODED and keyCode == SHIFT
 
1829
   *
 
1830
   * 4. Holding down the 'a' key.
 
1831
   *    The following will happen several times,
 
1832
   *    depending on your machine's "key repeat rate" settings:
 
1833
   *    keyPressed  with key == 'a' and keyCode == 'A'
 
1834
   *    keyTyped    with key == 'a' and keyCode ==  0
 
1835
   *    When you finally let go, you'll get:
 
1836
   *    keyReleased with key == 'a' and keyCode == 'A'
 
1837
   *
 
1838
   * 5. Pressing and releasing the 'shift' key
 
1839
   *    keyPressed  with key == CODED and keyCode == SHIFT
 
1840
   *    keyReleased with key == CODED and keyCode == SHIFT
 
1841
   *    (note there is no keyTyped)
 
1842
   *
 
1843
   * 6. Pressing the tab key in an applet with Java 1.4 will
 
1844
   *    normally do nothing, but PApplet dynamically shuts
 
1845
   *    this behavior off if Java 1.4 is in use (tested 1.4.2_05 Windows).
 
1846
   *    Java 1.1 (Microsoft VM) passes the TAB key through normally.
 
1847
   *    Not tested on other platforms or for 1.3.
 
1848
   * </PRE>
 
1849
   */
 
1850
  public void keyPressed() { }
 
1851
 
 
1852
 
 
1853
  /**
 
1854
   * See keyPressed().
 
1855
   */
 
1856
  public void keyReleased() { }
 
1857
 
 
1858
 
 
1859
  /**
 
1860
   * Only called for "regular" keys like letters,
 
1861
   * see keyPressed() for full documentation.
 
1862
   */
 
1863
  public void keyTyped() { }
 
1864
 
 
1865
 
 
1866
  //////////////////////////////////////////////////////////////
 
1867
 
 
1868
  // i am focused man, and i'm not afraid of death.
 
1869
  // and i'm going all out. i circle the vultures in a van
 
1870
  // and i run the block.
 
1871
 
 
1872
 
 
1873
  public void focusGained() { }
 
1874
 
 
1875
  public void focusGained(FocusEvent e) {
 
1876
    focused = true;
 
1877
    focusGained();
 
1878
  }
 
1879
 
 
1880
 
 
1881
  public void focusLost() { }
 
1882
 
 
1883
  public void focusLost(FocusEvent e) {
 
1884
    focused = false;
 
1885
    focusLost();
 
1886
  }
 
1887
 
 
1888
 
 
1889
  //////////////////////////////////////////////////////////////
 
1890
 
 
1891
  // getting the time
 
1892
 
 
1893
 
 
1894
  /**
 
1895
   * Get the number of milliseconds since the applet started.
 
1896
   * <P>
 
1897
   * This is a function, rather than a variable, because it may
 
1898
   * change multiple times per frame.
 
1899
   */
 
1900
  public int millis() {
 
1901
    return (int) (System.currentTimeMillis() - millisOffset);
 
1902
  }
 
1903
 
 
1904
  /** Seconds position of the current time. */
 
1905
  static public int second() {
 
1906
    return Calendar.getInstance().get(Calendar.SECOND);
 
1907
  }
 
1908
 
 
1909
  /** Minutes position of the current time. */
 
1910
  static public int minute() {
 
1911
    return Calendar.getInstance().get(Calendar.MINUTE);
 
1912
  }
 
1913
 
 
1914
  /**
 
1915
   * Hour position of the current time in international format (0-23).
 
1916
   * <P>
 
1917
   * To convert this value to American time: <BR>
 
1918
   * <PRE>int yankeeHour = (hour() % 12);
 
1919
   * if (yankeeHour == 0) yankeeHour = 12;</PRE>
 
1920
   */
 
1921
  static public int hour() {
 
1922
    return Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
 
1923
  }
 
1924
 
 
1925
  /**
 
1926
   * Get the current day of the month (1 through 31).
 
1927
   * <P>
 
1928
   * If you're looking for the day of the week (M-F or whatever)
 
1929
   * or day of the year (1..365) then use java's Calendar.get()
 
1930
   */
 
1931
  static public int day() {
 
1932
    return Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
 
1933
  }
 
1934
 
 
1935
  /**
 
1936
   * Get the current month in range 1 through 12.
 
1937
   */
 
1938
  static public int month() {
 
1939
    // months are number 0..11 so change to colloquial 1..12
 
1940
    return Calendar.getInstance().get(Calendar.MONTH) + 1;
 
1941
  }
 
1942
 
 
1943
  /**
 
1944
   * Get the current year.
 
1945
   */
 
1946
  static public int year() {
 
1947
    return Calendar.getInstance().get(Calendar.YEAR);
 
1948
  }
 
1949
 
 
1950
 
 
1951
  //////////////////////////////////////////////////////////////
 
1952
 
 
1953
  // controlling time (playing god)
 
1954
 
 
1955
 
 
1956
  /**
 
1957
   * The delay() function causes the program to halt for a specified time.
 
1958
   * Delay times are specified in thousandths of a second. For example,
 
1959
   * running delay(3000) will stop the program for three seconds and
 
1960
   * delay(500) will stop the program for a half-second. Remember: the
 
1961
   * display window is updated only at the end of draw(), so putting more
 
1962
   * than one delay() inside draw() will simply add them together and the new
 
1963
   * frame will be drawn when the total delay is over.
 
1964
   * <br/> <br/>
 
1965
   * I'm not sure if this is even helpful anymore, as the screen isn't
 
1966
   * updated before or after the delay, meaning which means it just
 
1967
   * makes the app lock up temporarily.
 
1968
   */
 
1969
  public void delay(int napTime) {
 
1970
    if (frameCount != 0) {
 
1971
      if (napTime > 0) {
 
1972
        try {
 
1973
          Thread.sleep(napTime);
 
1974
        } catch (InterruptedException e) { }
 
1975
      }
 
1976
    }
 
1977
  }
 
1978
 
 
1979
 
 
1980
  /**
 
1981
   * Set a target frameRate. This will cause delay() to be called
 
1982
   * after each frame so that the sketch synchronizes to a particular speed.
 
1983
   * Note that this only sets the maximum frame rate, it cannot be used to
 
1984
   * make a slow sketch go faster. Sketches have no default frame rate
 
1985
   * setting, and will attempt to use maximum processor power to achieve
 
1986
   * maximum speed.
 
1987
   */
 
1988
  public void frameRate(float newRateTarget) {
 
1989
    frameRateTarget = newRateTarget;
 
1990
    frameRatePeriod = (long) (1000000000.0 / frameRateTarget);
 
1991
  }
 
1992
 
 
1993
 
 
1994
  //////////////////////////////////////////////////////////////
 
1995
 
 
1996
 
 
1997
  /**
 
1998
   * Get a param from the web page, or (eventually)
 
1999
   * from a properties file.
 
2000
   */
 
2001
  public String param(String what) {
 
2002
    if (online) {
 
2003
      return getParameter(what);
 
2004
 
 
2005
    } else {
 
2006
      System.err.println("param() only works inside a web browser");
 
2007
    }
 
2008
    return null;
 
2009
  }
 
2010
 
 
2011
 
 
2012
  /**
 
2013
   * Show status in the status bar of a web browser, or in the
 
2014
   * System.out console. Eventually this might show status in the
 
2015
   * p5 environment itself, rather than relying on the console.
 
2016
   */
 
2017
  public void status(String what) {
 
2018
    if (online) {
 
2019
      showStatus(what);
 
2020
 
 
2021
    } else {
 
2022
      System.out.println(what);  // something more interesting?
 
2023
    }
 
2024
  }
 
2025
 
 
2026
 
 
2027
  public void link(String here) {
 
2028
    link(here, null);
 
2029
  }
 
2030
 
 
2031
 
 
2032
  /**
 
2033
   * Link to an external page without all the muss.
 
2034
   * <P>
 
2035
   * When run with an applet, uses the browser to open the url,
 
2036
   * for applications, attempts to launch a browser with the url.
 
2037
   * <P>
 
2038
   * Works on Mac OS X and Windows. For Linux, use:
 
2039
   * <PRE>open(new String[] { "firefox", url });</PRE>
 
2040
   * or whatever you want as your browser, since Linux doesn't
 
2041
   * yet have a standard method for launching URLs.
 
2042
   */
 
2043
  public void link(String url, String frameTitle) {
 
2044
    if (online) {
 
2045
      try {
 
2046
        if (frameTitle == null) {
 
2047
          getAppletContext().showDocument(new URL(url));
 
2048
        } else {
 
2049
          getAppletContext().showDocument(new URL(url), frameTitle);
 
2050
        }
 
2051
      } catch (Exception e) {
 
2052
        e.printStackTrace();
 
2053
        throw new RuntimeException("Could not open " + url);
 
2054
      }
 
2055
    } else {
 
2056
      try {
 
2057
        if (platform == WINDOWS) {
 
2058
          // the following uses a shell execute to launch the .html file
 
2059
          // note that under cygwin, the .html files have to be chmodded +x
 
2060
          // after they're unpacked from the zip file. i don't know why,
 
2061
          // and don't understand what this does in terms of windows
 
2062
          // permissions. without the chmod, the command prompt says
 
2063
          // "Access is denied" in both cygwin and the "dos" prompt.
 
2064
          //Runtime.getRuntime().exec("cmd /c " + currentDir + "\\reference\\" +
 
2065
          //                    referenceFile + ".html");
 
2066
 
 
2067
          // replace ampersands with control sequence for DOS.
 
2068
          // solution contributed by toxi on the bugs board.
 
2069
          url = url.replaceAll("&","^&");
 
2070
 
 
2071
          // open dos prompt, give it 'start' command, which will
 
2072
          // open the url properly. start by itself won't work since
 
2073
          // it appears to need cmd
 
2074
          Runtime.getRuntime().exec("cmd /c start " + url);
 
2075
 
 
2076
        } else if (platform == MACOSX) {
 
2077
          //com.apple.mrj.MRJFileUtils.openURL(url);
 
2078
          try {
 
2079
            Class<?> mrjFileUtils = Class.forName("com.apple.mrj.MRJFileUtils");
 
2080
            Method openMethod =
 
2081
              mrjFileUtils.getMethod("openURL", new Class[] { String.class });
 
2082
            openMethod.invoke(null, new Object[] { url });
 
2083
          } catch (Exception e) {
 
2084
            e.printStackTrace();
 
2085
          }
 
2086
        } else {
 
2087
          //throw new RuntimeException("Can't open URLs for this platform");
 
2088
          // Just pass it off to open() and hope for the best
 
2089
          open(url);
 
2090
        }
 
2091
      } catch (IOException e) {
 
2092
        e.printStackTrace();
 
2093
        throw new RuntimeException("Could not open " + url);
 
2094
      }
 
2095
    }
 
2096
  }
 
2097
 
 
2098
 
 
2099
  /**
 
2100
   * Attempt to open a file using the platform's shell.
 
2101
   */
 
2102
  static public void open(String filename) {
 
2103
    open(new String[] { filename });
 
2104
  }
 
2105
 
 
2106
 
 
2107
  static String openLauncher;
 
2108
 
 
2109
  /**
 
2110
   * Launch a process using a platforms shell. This version uses an array
 
2111
   * to make it easier to deal with spaces in the individual elements.
 
2112
   * (This avoids the situation of trying to put single or double quotes
 
2113
   * around different bits).
 
2114
   */
 
2115
  static public Process open(String argv[]) {
 
2116
    String[] params = null;
 
2117
 
 
2118
    if (platform == WINDOWS) {
 
2119
      // just launching the .html file via the shell works
 
2120
      // but make sure to chmod +x the .html files first
 
2121
      // also place quotes around it in case there's a space
 
2122
      // in the user.dir part of the url
 
2123
      params = new String[] { "cmd", "/c" };
 
2124
 
 
2125
    } else if (platform == MACOSX) {
 
2126
      params = new String[] { "open" };
 
2127
 
 
2128
    } else if (platform == LINUX) {
 
2129
      if (openLauncher == null) {
 
2130
        // Attempt to use gnome-open
 
2131
        try {
 
2132
          Process p = Runtime.getRuntime().exec(new String[] { "gnome-open" });
 
2133
          /*int result =*/ p.waitFor();
 
2134
          // Not installed will throw an IOException (JDK 1.4.2, Ubuntu 7.04)
 
2135
          openLauncher = "gnome-open";
 
2136
        } catch (Exception e) { }
 
2137
      }
 
2138
      if (openLauncher == null) {
 
2139
        // Attempt with kde-open
 
2140
        try {
 
2141
          Process p = Runtime.getRuntime().exec(new String[] { "kde-open" });
 
2142
          /*int result =*/ p.waitFor();
 
2143
          openLauncher = "kde-open";
 
2144
        } catch (Exception e) { }
 
2145
      }
 
2146
      if (openLauncher == null) {
 
2147
        System.err.println("Could not find gnome-open or kde-open, " +
 
2148
                           "the open() command may not work.");
 
2149
      }
 
2150
      if (openLauncher != null) {
 
2151
        params = new String[] { openLauncher };
 
2152
      }
 
2153
    //} else {  // give up and just pass it to Runtime.exec()
 
2154
      //open(new String[] { filename });
 
2155
      //params = new String[] { filename };
 
2156
    }
 
2157
    if (params != null) {
 
2158
      // If the 'open', 'gnome-open' or 'cmd' are already included
 
2159
      if (params[0].equals(argv[0])) {
 
2160
        // then don't prepend those params again
 
2161
        return exec(argv);
 
2162
      } else {
 
2163
        params = concat(params, argv);
 
2164
        return exec(params);
 
2165
      }
 
2166
    } else {
 
2167
      return exec(argv);
 
2168
    }
 
2169
  }
 
2170
 
 
2171
 
 
2172
  static public Process exec(String[] argv) {
 
2173
    try {
 
2174
      return Runtime.getRuntime().exec(argv);
 
2175
    } catch (Exception e) {
 
2176
      e.printStackTrace();
 
2177
      throw new RuntimeException("Could not open " + join(argv, ' '));
 
2178
    }
 
2179
  }
 
2180
 
 
2181
 
 
2182
  //////////////////////////////////////////////////////////////
 
2183
 
 
2184
 
 
2185
  /**
 
2186
   * Function for an applet/application to kill itself and
 
2187
   * display an error. Mostly this is here to be improved later.
 
2188
   */
 
2189
  public void die(String what) {
 
2190
    stop();
 
2191
    throw new RuntimeException(what);
 
2192
  }
 
2193
 
 
2194
 
 
2195
  /**
 
2196
   * Same as above but with an exception. Also needs work.
 
2197
   */
 
2198
  public void die(String what, Exception e) {
 
2199
    if (e != null) e.printStackTrace();
 
2200
    die(what);
 
2201
  }
 
2202
 
 
2203
 
 
2204
  /**
 
2205
   * Call to safely exit the sketch when finished. For instance,
 
2206
   * to render a single frame, save it, and quit.
 
2207
   */
 
2208
  public void exit() {
 
2209
    if (thread == null) {
 
2210
      // exit immediately, stop() has already been called,
 
2211
      // meaning that the main thread has long since exited
 
2212
      exit2();
 
2213
 
 
2214
    } else if (looping) {
 
2215
      // stop() will be called as the thread exits
 
2216
      finished = true;
 
2217
      // tell the code to call exit2() to do a System.exit()
 
2218
      // once the next draw() has completed
 
2219
      exitCalled = true;
 
2220
 
 
2221
    } else if (!looping) {
 
2222
      // if not looping, need to call stop explicitly,
 
2223
      // because the main thread will be sleeping
 
2224
      stop();
 
2225
 
 
2226
      // now get out
 
2227
      exit2();
 
2228
    }
 
2229
  }
 
2230
 
 
2231
 
 
2232
  void exit2() {
 
2233
    try {
 
2234
      System.exit(0);
 
2235
    } catch (SecurityException e) {
 
2236
      // don't care about applet security exceptions
 
2237
    }
 
2238
  }
 
2239
 
 
2240
 
 
2241
 
 
2242
  //////////////////////////////////////////////////////////////
 
2243
 
 
2244
 
 
2245
  public void method(String name) {
 
2246
//    final Object o = this;
 
2247
//    final Class<?> c = getClass();
 
2248
    try {
 
2249
      Method method = getClass().getMethod(name, new Class[] {});
 
2250
      method.invoke(this, new Object[] { });
 
2251
 
 
2252
    } catch (IllegalArgumentException e) {
 
2253
      e.printStackTrace();
 
2254
    } catch (IllegalAccessException e) {
 
2255
      e.printStackTrace();
 
2256
    } catch (InvocationTargetException e) {
 
2257
      e.getTargetException().printStackTrace();
 
2258
    } catch (NoSuchMethodException nsme) {
 
2259
      System.err.println("There is no public " + name + "() method " +
 
2260
                         "in the class " + getClass().getName());
 
2261
    } catch (Exception e) {
 
2262
      e.printStackTrace();
 
2263
    }
 
2264
  }
 
2265
 
 
2266
 
 
2267
  public void thread(final String name) {
 
2268
    Thread later = new Thread() {
 
2269
      public void run() {
 
2270
        method(name);
 
2271
      }
 
2272
    };
 
2273
    later.start();
 
2274
  }
 
2275
 
 
2276
 
 
2277
  /*
 
2278
  public void thread(String name) {
 
2279
    final Object o = this;
 
2280
    final Class<?> c = getClass();
 
2281
    try {
 
2282
      final Method method = c.getMethod(name, new Class[] {});
 
2283
      Thread later = new Thread() {
 
2284
        public void run() {
 
2285
          try {
 
2286
            method.invoke(o, new Object[] { });
 
2287
 
 
2288
          } catch (IllegalArgumentException e) {
 
2289
            e.printStackTrace();
 
2290
          } catch (IllegalAccessException e) {
 
2291
            e.printStackTrace();
 
2292
          } catch (InvocationTargetException e) {
 
2293
            e.getTargetException().printStackTrace();
 
2294
          }
 
2295
        }
 
2296
      };
 
2297
      later.start();
 
2298
 
 
2299
    } catch (NoSuchMethodException nsme) {
 
2300
      System.err.println("There is no " + name + "() method " +
 
2301
                         "in the class " + getClass().getName());
 
2302
 
 
2303
    } catch (Exception e) {
 
2304
      e.printStackTrace();
 
2305
    }
 
2306
  }
 
2307
  */
 
2308
 
 
2309
 
 
2310
 
 
2311
  //////////////////////////////////////////////////////////////
 
2312
 
 
2313
  // SCREEN GRABASS
 
2314
 
 
2315
 
 
2316
  /**
 
2317
   * Intercepts any relative paths to make them absolute (relative
 
2318
   * to the sketch folder) before passing to save() in PImage.
 
2319
   * (Changed in 0100)
 
2320
   */
 
2321
  public void save(String filename) {
 
2322
    g.save(savePath(filename));
 
2323
  }
 
2324
 
 
2325
 
 
2326
  /**
 
2327
   * Grab an image of what's currently in the drawing area and save it
 
2328
   * as a .tif or .tga file.
 
2329
   * <P>
 
2330
   * Best used just before endDraw() at the end of your draw().
 
2331
   * This can only create .tif or .tga images, so if neither extension
 
2332
   * is specified it defaults to writing a tiff and adds a .tif suffix.
 
2333
   */
 
2334
  public void saveFrame() {
 
2335
    try {
 
2336
      g.save(savePath("screen-" + nf(frameCount, 4) + ".tif"));
 
2337
    } catch (SecurityException se) {
 
2338
      System.err.println("Can't use saveFrame() when running in a browser, " +
 
2339
                         "unless using a signed applet.");
 
2340
    }
 
2341
  }
 
2342
 
 
2343
 
 
2344
  /**
 
2345
   * Save the current frame as a .tif or .tga image.
 
2346
   * <P>
 
2347
   * The String passed in can contain a series of # signs
 
2348
   * that will be replaced with the screengrab number.
 
2349
   * <PRE>
 
2350
   * i.e. saveFrame("blah-####.tif");
 
2351
   *      // saves a numbered tiff image, replacing the
 
2352
   *      // #### signs with zeros and the frame number </PRE>
 
2353
   */
 
2354
  public void saveFrame(String what) {
 
2355
    try {
 
2356
      g.save(savePath(insertFrame(what)));
 
2357
    } catch (SecurityException se) {
 
2358
      System.err.println("Can't use saveFrame() when running in a browser, " +
 
2359
                         "unless using a signed applet.");
 
2360
    }
 
2361
  }
 
2362
 
 
2363
 
 
2364
  /**
 
2365
   * Check a string for #### signs to see if the frame number should be
 
2366
   * inserted. Used for functions like saveFrame() and beginRecord() to
 
2367
   * replace the # marks with the frame number. If only one # is used,
 
2368
   * it will be ignored, under the assumption that it's probably not
 
2369
   * intended to be the frame number.
 
2370
   */
 
2371
  protected String insertFrame(String what) {
 
2372
    int first = what.indexOf('#');
 
2373
    int last = what.lastIndexOf('#');
 
2374
 
 
2375
    if ((first != -1) && (last - first > 0)) {
 
2376
      String prefix = what.substring(0, first);
 
2377
      int count = last - first + 1;
 
2378
      String suffix = what.substring(last + 1);
 
2379
      return prefix + nf(frameCount, count) + suffix;
 
2380
    }
 
2381
    return what;  // no change
 
2382
  }
 
2383
 
 
2384
 
 
2385
 
 
2386
  //////////////////////////////////////////////////////////////
 
2387
 
 
2388
  // CURSOR
 
2389
 
 
2390
  //
 
2391
 
 
2392
 
 
2393
  int cursorType = ARROW; // cursor type
 
2394
  boolean cursorVisible = true; // cursor visibility flag
 
2395
  PImage invisibleCursor;
 
2396
 
 
2397
 
 
2398
  /**
 
2399
   * Set the cursor type
 
2400
   */
 
2401
  public void cursor(int cursorType) {
 
2402
    setCursor(Cursor.getPredefinedCursor(cursorType));
 
2403
    cursorVisible = true;
 
2404
    this.cursorType = cursorType;
 
2405
  }
 
2406
 
 
2407
 
 
2408
  /**
 
2409
   * Replace the cursor with the specified PImage. The x- and y-
 
2410
   * coordinate of the center will be the center of the image.
 
2411
   */
 
2412
  public void cursor(PImage image) {
 
2413
    cursor(image, image.width/2, image.height/2);
 
2414
  }
 
2415
 
 
2416
 
 
2417
  /**
 
2418
   * Set a custom cursor to an image with a specific hotspot.
 
2419
   * Only works with JDK 1.2 and later.
 
2420
   * Currently seems to be broken on Java 1.4 for Mac OS X
 
2421
   * <P>
 
2422
   * Based on code contributed by Amit Pitaru, plus additional
 
2423
   * code to handle Java versions via reflection by Jonathan Feinberg.
 
2424
   * Reflection removed for release 0128 and later.
 
2425
   */
 
2426
  public void cursor(PImage image, int hotspotX, int hotspotY) {
 
2427
    // don't set this as cursor type, instead use cursor_type
 
2428
    // to save the last cursor used in case cursor() is called
 
2429
    //cursor_type = Cursor.CUSTOM_CURSOR;
 
2430
    Image jimage =
 
2431
      createImage(new MemoryImageSource(image.width, image.height,
 
2432
                                        image.pixels, 0, image.width));
 
2433
    Point hotspot = new Point(hotspotX, hotspotY);
 
2434
    Toolkit tk = Toolkit.getDefaultToolkit();
 
2435
    Cursor cursor = tk.createCustomCursor(jimage, hotspot, "Custom Cursor");
 
2436
    setCursor(cursor);
 
2437
    cursorVisible = true;
 
2438
  }
 
2439
 
 
2440
 
 
2441
  /**
 
2442
   * Show the cursor after noCursor() was called.
 
2443
   * Notice that the program remembers the last set cursor type
 
2444
   */
 
2445
  public void cursor() {
 
2446
    // maybe should always set here? seems dangerous, since
 
2447
    // it's likely that java will set the cursor to something
 
2448
    // else on its own, and the applet will be stuck b/c bagel
 
2449
    // thinks that the cursor is set to one particular thing
 
2450
    if (!cursorVisible) {
 
2451
      cursorVisible = true;
 
2452
      setCursor(Cursor.getPredefinedCursor(cursorType));
 
2453
    }
 
2454
  }
 
2455
 
 
2456
 
 
2457
  /**
 
2458
   * Hide the cursor by creating a transparent image
 
2459
   * and using it as a custom cursor.
 
2460
   */
 
2461
  public void noCursor() {
 
2462
    if (!cursorVisible) return;  // don't hide if already hidden.
 
2463
 
 
2464
    if (invisibleCursor == null) {
 
2465
      invisibleCursor = new PImage(16, 16, ARGB);
 
2466
    }
 
2467
    // was formerly 16x16, but the 0x0 was added by jdf as a fix
 
2468
    // for macosx, which wasn't honoring the invisible cursor
 
2469
    cursor(invisibleCursor, 8, 8);
 
2470
    cursorVisible = false;
 
2471
  }
 
2472
 
 
2473
 
 
2474
  //////////////////////////////////////////////////////////////
 
2475
 
 
2476
 
 
2477
  static public void print(byte what) {
 
2478
    System.out.print(what);
 
2479
    System.out.flush();
 
2480
  }
 
2481
 
 
2482
  static public void print(boolean what) {
 
2483
    System.out.print(what);
 
2484
    System.out.flush();
 
2485
  }
 
2486
 
 
2487
  static public void print(char what) {
 
2488
    System.out.print(what);
 
2489
    System.out.flush();
 
2490
  }
 
2491
 
 
2492
  static public void print(int what) {
 
2493
    System.out.print(what);
 
2494
    System.out.flush();
 
2495
  }
 
2496
 
 
2497
  static public void print(float what) {
 
2498
    System.out.print(what);
 
2499
    System.out.flush();
 
2500
  }
 
2501
 
 
2502
  static public void print(String what) {
 
2503
    System.out.print(what);
 
2504
    System.out.flush();
 
2505
  }
 
2506
 
 
2507
  static public void print(Object what) {
 
2508
    if (what == null) {
 
2509
      // special case since this does fuggly things on > 1.1
 
2510
      System.out.print("null");
 
2511
    } else {
 
2512
      System.out.println(what.toString());
 
2513
    }
 
2514
  }
 
2515
 
 
2516
  //
 
2517
 
 
2518
  static public void println() {
 
2519
    System.out.println();
 
2520
  }
 
2521
 
 
2522
  //
 
2523
 
 
2524
  static public void println(byte what) {
 
2525
    print(what); System.out.println();
 
2526
  }
 
2527
 
 
2528
  static public void println(boolean what) {
 
2529
    print(what); System.out.println();
 
2530
  }
 
2531
 
 
2532
  static public void println(char what) {
 
2533
    print(what); System.out.println();
 
2534
  }
 
2535
 
 
2536
  static public void println(int what) {
 
2537
    print(what); System.out.println();
 
2538
  }
 
2539
 
 
2540
  static public void println(float what) {
 
2541
    print(what); System.out.println();
 
2542
  }
 
2543
 
 
2544
  static public void println(String what) {
 
2545
    print(what); System.out.println();
 
2546
  }
 
2547
 
 
2548
  static public void println(Object what) {
 
2549
    if (what == null) {
 
2550
      // special case since this does fuggly things on > 1.1
 
2551
      System.out.println("null");
 
2552
 
 
2553
    } else {
 
2554
      String name = what.getClass().getName();
 
2555
      if (name.charAt(0) == '[') {
 
2556
        switch (name.charAt(1)) {
 
2557
        case '[':
 
2558
          // don't even mess with multi-dimensional arrays (case '[')
 
2559
          // or anything else that's not int, float, boolean, char
 
2560
          System.out.println(what);
 
2561
          break;
 
2562
 
 
2563
        case 'L':
 
2564
          // print a 1D array of objects as individual elements
 
2565
          Object poo[] = (Object[]) what;
 
2566
          for (int i = 0; i < poo.length; i++) {
 
2567
            if (poo[i] instanceof String) {
 
2568
              System.out.println("[" + i + "] \"" + poo[i] + "\"");
 
2569
            } else {
 
2570
              System.out.println("[" + i + "] " + poo[i]);
 
2571
            }
 
2572
          }
 
2573
          break;
 
2574
 
 
2575
        case 'Z':  // boolean
 
2576
          boolean zz[] = (boolean[]) what;
 
2577
          for (int i = 0; i < zz.length; i++) {
 
2578
            System.out.println("[" + i + "] " + zz[i]);
 
2579
          }
 
2580
          break;
 
2581
 
 
2582
        case 'B':  // byte
 
2583
          byte bb[] = (byte[]) what;
 
2584
          for (int i = 0; i < bb.length; i++) {
 
2585
            System.out.println("[" + i + "] " + bb[i]);
 
2586
          }
 
2587
          break;
 
2588
 
 
2589
        case 'C':  // char
 
2590
          char cc[] = (char[]) what;
 
2591
          for (int i = 0; i < cc.length; i++) {
 
2592
            System.out.println("[" + i + "] '" + cc[i] + "'");
 
2593
          }
 
2594
          break;
 
2595
 
 
2596
        case 'I':  // int
 
2597
          int ii[] = (int[]) what;
 
2598
          for (int i = 0; i < ii.length; i++) {
 
2599
            System.out.println("[" + i + "] " + ii[i]);
 
2600
          }
 
2601
          break;
 
2602
 
 
2603
        case 'F':  // float
 
2604
          float ff[] = (float[]) what;
 
2605
          for (int i = 0; i < ff.length; i++) {
 
2606
            System.out.println("[" + i + "] " + ff[i]);
 
2607
          }
 
2608
          break;
 
2609
 
 
2610
          /*
 
2611
        case 'D':  // double
 
2612
          double dd[] = (double[]) what;
 
2613
          for (int i = 0; i < dd.length; i++) {
 
2614
            System.out.println("[" + i + "] " + dd[i]);
 
2615
          }
 
2616
          break;
 
2617
          */
 
2618
 
 
2619
        default:
 
2620
          System.out.println(what);
 
2621
        }
 
2622
      } else {  // not an array
 
2623
        System.out.println(what);
 
2624
      }
 
2625
    }
 
2626
  }
 
2627
 
 
2628
  //
 
2629
 
 
2630
  /*
 
2631
  // not very useful, because it only works for public (and protected?)
 
2632
  // fields of a class, not local variables to methods
 
2633
  public void printvar(String name) {
 
2634
    try {
 
2635
      Field field = getClass().getDeclaredField(name);
 
2636
      println(name + " = " + field.get(this));
 
2637
    } catch (Exception e) {
 
2638
      e.printStackTrace();
 
2639
    }
 
2640
  }
 
2641
  */
 
2642
 
 
2643
 
 
2644
  //////////////////////////////////////////////////////////////
 
2645
 
 
2646
  // MATH
 
2647
 
 
2648
  // lots of convenience methods for math with floats.
 
2649
  // doubles are overkill for processing applets, and casting
 
2650
  // things all the time is annoying, thus the functions below.
 
2651
 
 
2652
 
 
2653
  static public final float abs(float n) {
 
2654
    return (n < 0) ? -n : n;
 
2655
  }
 
2656
 
 
2657
  static public final int abs(int n) {
 
2658
    return (n < 0) ? -n : n;
 
2659
  }
 
2660
 
 
2661
  static public final float sq(float a) {
 
2662
    return a*a;
 
2663
  }
 
2664
 
 
2665
  static public final float sqrt(float a) {
 
2666
    return (float)Math.sqrt(a);
 
2667
  }
 
2668
 
 
2669
  static public final float log(float a) {
 
2670
    return (float)Math.log(a);
 
2671
  }
 
2672
 
 
2673
  static public final float exp(float a) {
 
2674
    return (float)Math.exp(a);
 
2675
  }
 
2676
 
 
2677
  static public final float pow(float a, float b) {
 
2678
    return (float)Math.pow(a, b);
 
2679
  }
 
2680
 
 
2681
 
 
2682
  static public final int max(int a, int b) {
 
2683
    return (a > b) ? a : b;
 
2684
  }
 
2685
 
 
2686
  static public final float max(float a, float b) {
 
2687
    return (a > b) ? a : b;
 
2688
  }
 
2689
 
 
2690
  /*
 
2691
  static public final double max(double a, double b) {
 
2692
    return (a > b) ? a : b;
 
2693
  }
 
2694
  */
 
2695
 
 
2696
 
 
2697
  static public final int max(int a, int b, int c) {
 
2698
    return (a > b) ? ((a > c) ? a : c) : ((b > c) ? b : c);
 
2699
  }
 
2700
 
 
2701
  static public final float max(float a, float b, float c) {
 
2702
    return (a > b) ? ((a > c) ? a : c) : ((b > c) ? b : c);
 
2703
  }
 
2704
 
 
2705
 
 
2706
  /**
 
2707
   * Find the maximum value in an array.
 
2708
   * Throws an ArrayIndexOutOfBoundsException if the array is length 0.
 
2709
   * @param list the source array
 
2710
   * @return The maximum value
 
2711
   */
 
2712
  static public final int max(int[] list) {
 
2713
    if (list.length == 0) {
 
2714
      throw new ArrayIndexOutOfBoundsException(ERROR_MIN_MAX);
 
2715
    }
 
2716
    int max = list[0];
 
2717
    for (int i = 1; i < list.length; i++) {
 
2718
      if (list[i] > max) max = list[i];
 
2719
    }
 
2720
    return max;
 
2721
  }
 
2722
 
 
2723
  /**
 
2724
   * Find the maximum value in an array.
 
2725
   * Throws an ArrayIndexOutOfBoundsException if the array is length 0.
 
2726
   * @param list the source array
 
2727
   * @return The maximum value
 
2728
   */
 
2729
  static public final float max(float[] list) {
 
2730
    if (list.length == 0) {
 
2731
      throw new ArrayIndexOutOfBoundsException(ERROR_MIN_MAX);
 
2732
    }
 
2733
    float max = list[0];
 
2734
    for (int i = 1; i < list.length; i++) {
 
2735
      if (list[i] > max) max = list[i];
 
2736
    }
 
2737
    return max;
 
2738
  }
 
2739
 
 
2740
 
 
2741
  /**
 
2742
   * Find the maximum value in an array.
 
2743
   * Throws an ArrayIndexOutOfBoundsException if the array is length 0.
 
2744
   * @param list the source array
 
2745
   * @return The maximum value
 
2746
   */
 
2747
  /*
 
2748
  static public final double max(double[] list) {
 
2749
    if (list.length == 0) {
 
2750
      throw new ArrayIndexOutOfBoundsException(ERROR_MIN_MAX);
 
2751
    }
 
2752
    double max = list[0];
 
2753
    for (int i = 1; i < list.length; i++) {
 
2754
      if (list[i] > max) max = list[i];
 
2755
    }
 
2756
    return max;
 
2757
  }
 
2758
  */
 
2759
 
 
2760
 
 
2761
  static public final int min(int a, int b) {
 
2762
    return (a < b) ? a : b;
 
2763
  }
 
2764
 
 
2765
  static public final float min(float a, float b) {
 
2766
    return (a < b) ? a : b;
 
2767
  }
 
2768
 
 
2769
  /*
 
2770
  static public final double min(double a, double b) {
 
2771
    return (a < b) ? a : b;
 
2772
  }
 
2773
  */
 
2774
 
 
2775
 
 
2776
  static public final int min(int a, int b, int c) {
 
2777
    return (a < b) ? ((a < c) ? a : c) : ((b < c) ? b : c);
 
2778
  }
 
2779
 
 
2780
  static public final float min(float a, float b, float c) {
 
2781
    return (a < b) ? ((a < c) ? a : c) : ((b < c) ? b : c);
 
2782
  }
 
2783
 
 
2784
  /*
 
2785
  static public final double min(double a, double b, double c) {
 
2786
    return (a < b) ? ((a < c) ? a : c) : ((b < c) ? b : c);
 
2787
  }
 
2788
  */
 
2789
 
 
2790
 
 
2791
  /**
 
2792
   * Find the minimum value in an array.
 
2793
   * Throws an ArrayIndexOutOfBoundsException if the array is length 0.
 
2794
   * @param list the source array
 
2795
   * @return The minimum value
 
2796
   */
 
2797
  static public final int min(int[] list) {
 
2798
    if (list.length == 0) {
 
2799
      throw new ArrayIndexOutOfBoundsException(ERROR_MIN_MAX);
 
2800
    }
 
2801
    int min = list[0];
 
2802
    for (int i = 1; i < list.length; i++) {
 
2803
      if (list[i] < min) min = list[i];
 
2804
    }
 
2805
    return min;
 
2806
  }
 
2807
 
 
2808
 
 
2809
  /**
 
2810
   * Find the minimum value in an array.
 
2811
   * Throws an ArrayIndexOutOfBoundsException if the array is length 0.
 
2812
   * @param list the source array
 
2813
   * @return The minimum value
 
2814
   */
 
2815
  static public final float min(float[] list) {
 
2816
    if (list.length == 0) {
 
2817
      throw new ArrayIndexOutOfBoundsException(ERROR_MIN_MAX);
 
2818
    }
 
2819
    float min = list[0];
 
2820
    for (int i = 1; i < list.length; i++) {
 
2821
      if (list[i] < min) min = list[i];
 
2822
    }
 
2823
    return min;
 
2824
  }
 
2825
 
 
2826
 
 
2827
  /**
 
2828
   * Find the minimum value in an array.
 
2829
   * Throws an ArrayIndexOutOfBoundsException if the array is length 0.
 
2830
   * @param list the source array
 
2831
   * @return The minimum value
 
2832
   */
 
2833
  /*
 
2834
  static public final double min(double[] list) {
 
2835
    if (list.length == 0) {
 
2836
      throw new ArrayIndexOutOfBoundsException(ERROR_MIN_MAX);
 
2837
    }
 
2838
    double min = list[0];
 
2839
    for (int i = 1; i < list.length; i++) {
 
2840
      if (list[i] < min) min = list[i];
 
2841
    }
 
2842
    return min;
 
2843
  }
 
2844
  */
 
2845
 
 
2846
  static public final int constrain(int amt, int low, int high) {
 
2847
    return (amt < low) ? low : ((amt > high) ? high : amt);
 
2848
  }
 
2849
 
 
2850
  static public final float constrain(float amt, float low, float high) {
 
2851
    return (amt < low) ? low : ((amt > high) ? high : amt);
 
2852
  }
 
2853
 
 
2854
 
 
2855
  static public final float sin(float angle) {
 
2856
    return (float)Math.sin(angle);
 
2857
  }
 
2858
 
 
2859
  static public final float cos(float angle) {
 
2860
    return (float)Math.cos(angle);
 
2861
  }
 
2862
 
 
2863
  static public final float tan(float angle) {
 
2864
    return (float)Math.tan(angle);
 
2865
  }
 
2866
 
 
2867
 
 
2868
  static public final float asin(float value) {
 
2869
    return (float)Math.asin(value);
 
2870
  }
 
2871
 
 
2872
  static public final float acos(float value) {
 
2873
    return (float)Math.acos(value);
 
2874
  }
 
2875
 
 
2876
  static public final float atan(float value) {
 
2877
    return (float)Math.atan(value);
 
2878
  }
 
2879
 
 
2880
  static public final float atan2(float a, float b) {
 
2881
    return (float)Math.atan2(a, b);
 
2882
  }
 
2883
 
 
2884
 
 
2885
  static public final float degrees(float radians) {
 
2886
    return radians * RAD_TO_DEG;
 
2887
  }
 
2888
 
 
2889
  static public final float radians(float degrees) {
 
2890
    return degrees * DEG_TO_RAD;
 
2891
  }
 
2892
 
 
2893
 
 
2894
  static public final int ceil(float what) {
 
2895
    return (int) Math.ceil(what);
 
2896
  }
 
2897
 
 
2898
  static public final int floor(float what) {
 
2899
    return (int) Math.floor(what);
 
2900
  }
 
2901
 
 
2902
  static public final int round(float what) {
 
2903
    return (int) Math.round(what);
 
2904
  }
 
2905
 
 
2906
 
 
2907
  static public final float mag(float a, float b) {
 
2908
    return (float)Math.sqrt(a*a + b*b);
 
2909
  }
 
2910
 
 
2911
  static public final float mag(float a, float b, float c) {
 
2912
    return (float)Math.sqrt(a*a + b*b + c*c);
 
2913
  }
 
2914
 
 
2915
 
 
2916
  static public final float dist(float x1, float y1, float x2, float y2) {
 
2917
    return sqrt(sq(x2-x1) + sq(y2-y1));
 
2918
  }
 
2919
 
 
2920
  static public final float dist(float x1, float y1, float z1,
 
2921
                                 float x2, float y2, float z2) {
 
2922
    return sqrt(sq(x2-x1) + sq(y2-y1) + sq(z2-z1));
 
2923
  }
 
2924
 
 
2925
 
 
2926
  static public final float lerp(float start, float stop, float amt) {
 
2927
    return start + (stop-start) * amt;
 
2928
  }
 
2929
 
 
2930
  /**
 
2931
   * Normalize a value to exist between 0 and 1 (inclusive).
 
2932
   * Mathematically the opposite of lerp(), figures out what proportion
 
2933
   * a particular value is relative to start and stop coordinates.
 
2934
   */
 
2935
  static public final float norm(float value, float start, float stop) {
 
2936
    return (value - start) / (stop - start);
 
2937
  }
 
2938
 
 
2939
  /**
 
2940
   * Convenience function to map a variable from one coordinate space
 
2941
   * to another. Equivalent to unlerp() followed by lerp().
 
2942
   */
 
2943
  static public final float map(float value,
 
2944
                                float istart, float istop,
 
2945
                                float ostart, float ostop) {
 
2946
    return ostart + (ostop - ostart) * ((value - istart) / (istop - istart));
 
2947
  }
 
2948
 
 
2949
 
 
2950
  /*
 
2951
  static public final double map(double value,
 
2952
                                 double istart, double istop,
 
2953
                                 double ostart, double ostop) {
 
2954
    return ostart + (ostop - ostart) * ((value - istart) / (istop - istart));
 
2955
  }
 
2956
  */
 
2957
 
 
2958
 
 
2959
 
 
2960
  //////////////////////////////////////////////////////////////
 
2961
 
 
2962
  // RANDOM NUMBERS
 
2963
 
 
2964
 
 
2965
  Random internalRandom;
 
2966
 
 
2967
  /**
 
2968
   * Return a random number in the range [0, howbig).
 
2969
   * <P>
 
2970
   * The number returned will range from zero up to
 
2971
   * (but not including) 'howbig'.
 
2972
   */
 
2973
  public final float random(float howbig) {
 
2974
    // for some reason (rounding error?) Math.random() * 3
 
2975
    // can sometimes return '3' (once in ~30 million tries)
 
2976
    // so a check was added to avoid the inclusion of 'howbig'
 
2977
 
 
2978
    // avoid an infinite loop
 
2979
    if (howbig == 0) return 0;
 
2980
 
 
2981
    // internal random number object
 
2982
    if (internalRandom == null) internalRandom = new Random();
 
2983
 
 
2984
    float value = 0;
 
2985
    do {
 
2986
      //value = (float)Math.random() * howbig;
 
2987
      value = internalRandom.nextFloat() * howbig;
 
2988
    } while (value == howbig);
 
2989
    return value;
 
2990
  }
 
2991
 
 
2992
 
 
2993
  /**
 
2994
   * Return a random number in the range [howsmall, howbig).
 
2995
   * <P>
 
2996
   * The number returned will range from 'howsmall' up to
 
2997
   * (but not including 'howbig'.
 
2998
   * <P>
 
2999
   * If howsmall is >= howbig, howsmall will be returned,
 
3000
   * meaning that random(5, 5) will return 5 (useful)
 
3001
   * and random(7, 4) will return 7 (not useful.. better idea?)
 
3002
   */
 
3003
  public final float random(float howsmall, float howbig) {
 
3004
    if (howsmall >= howbig) return howsmall;
 
3005
    float diff = howbig - howsmall;
 
3006
    return random(diff) + howsmall;
 
3007
  }
 
3008
 
 
3009
 
 
3010
  public final void randomSeed(long what) {
 
3011
    // internal random number object
 
3012
    if (internalRandom == null) internalRandom = new Random();
 
3013
    internalRandom.setSeed(what);
 
3014
  }
 
3015
 
 
3016
 
 
3017
 
 
3018
  //////////////////////////////////////////////////////////////
 
3019
 
 
3020
  // PERLIN NOISE
 
3021
 
 
3022
  // [toxi 040903]
 
3023
  // octaves and amplitude amount per octave are now user controlled
 
3024
  // via the noiseDetail() function.
 
3025
 
 
3026
  // [toxi 030902]
 
3027
  // cleaned up code and now using bagel's cosine table to speed up
 
3028
 
 
3029
  // [toxi 030901]
 
3030
  // implementation by the german demo group farbrausch
 
3031
  // as used in their demo "art": http://www.farb-rausch.de/fr010src.zip
 
3032
 
 
3033
  static final int PERLIN_YWRAPB = 4;
 
3034
  static final int PERLIN_YWRAP = 1<<PERLIN_YWRAPB;
 
3035
  static final int PERLIN_ZWRAPB = 8;
 
3036
  static final int PERLIN_ZWRAP = 1<<PERLIN_ZWRAPB;
 
3037
  static final int PERLIN_SIZE = 4095;
 
3038
 
 
3039
  int perlin_octaves = 4; // default to medium smooth
 
3040
  float perlin_amp_falloff = 0.5f; // 50% reduction/octave
 
3041
 
 
3042
  // [toxi 031112]
 
3043
  // new vars needed due to recent change of cos table in PGraphics
 
3044
  int perlin_TWOPI, perlin_PI;
 
3045
  float[] perlin_cosTable;
 
3046
  float[] perlin;
 
3047
 
 
3048
  Random perlinRandom;
 
3049
 
 
3050
 
 
3051
  /**
 
3052
   * Computes the Perlin noise function value at point x.
 
3053
   */
 
3054
  public float noise(float x) {
 
3055
    // is this legit? it's a dumb way to do it (but repair it later)
 
3056
    return noise(x, 0f, 0f);
 
3057
  }
 
3058
 
 
3059
  /**
 
3060
   * Computes the Perlin noise function value at the point x, y.
 
3061
   */
 
3062
  public float noise(float x, float y) {
 
3063
    return noise(x, y, 0f);
 
3064
  }
 
3065
 
 
3066
  /**
 
3067
   * Computes the Perlin noise function value at x, y, z.
 
3068
   */
 
3069
  public float noise(float x, float y, float z) {
 
3070
    if (perlin == null) {
 
3071
      if (perlinRandom == null) {
 
3072
        perlinRandom = new Random();
 
3073
      }
 
3074
      perlin = new float[PERLIN_SIZE + 1];
 
3075
      for (int i = 0; i < PERLIN_SIZE + 1; i++) {
 
3076
        perlin[i] = perlinRandom.nextFloat(); //(float)Math.random();
 
3077
      }
 
3078
      // [toxi 031112]
 
3079
      // noise broke due to recent change of cos table in PGraphics
 
3080
      // this will take care of it
 
3081
      perlin_cosTable = PGraphics.cosLUT;
 
3082
      perlin_TWOPI = perlin_PI = PGraphics.SINCOS_LENGTH;
 
3083
      perlin_PI >>= 1;
 
3084
    }
 
3085
 
 
3086
    if (x<0) x=-x;
 
3087
    if (y<0) y=-y;
 
3088
    if (z<0) z=-z;
 
3089
 
 
3090
    int xi=(int)x, yi=(int)y, zi=(int)z;
 
3091
    float xf = (float)(x-xi);
 
3092
    float yf = (float)(y-yi);
 
3093
    float zf = (float)(z-zi);
 
3094
    float rxf, ryf;
 
3095
 
 
3096
    float r=0;
 
3097
    float ampl=0.5f;
 
3098
 
 
3099
    float n1,n2,n3;
 
3100
 
 
3101
    for (int i=0; i<perlin_octaves; i++) {
 
3102
      int of=xi+(yi<<PERLIN_YWRAPB)+(zi<<PERLIN_ZWRAPB);
 
3103
 
 
3104
      rxf=noise_fsc(xf);
 
3105
      ryf=noise_fsc(yf);
 
3106
 
 
3107
      n1  = perlin[of&PERLIN_SIZE];
 
3108
      n1 += rxf*(perlin[(of+1)&PERLIN_SIZE]-n1);
 
3109
      n2  = perlin[(of+PERLIN_YWRAP)&PERLIN_SIZE];
 
3110
      n2 += rxf*(perlin[(of+PERLIN_YWRAP+1)&PERLIN_SIZE]-n2);
 
3111
      n1 += ryf*(n2-n1);
 
3112
 
 
3113
      of += PERLIN_ZWRAP;
 
3114
      n2  = perlin[of&PERLIN_SIZE];
 
3115
      n2 += rxf*(perlin[(of+1)&PERLIN_SIZE]-n2);
 
3116
      n3  = perlin[(of+PERLIN_YWRAP)&PERLIN_SIZE];
 
3117
      n3 += rxf*(perlin[(of+PERLIN_YWRAP+1)&PERLIN_SIZE]-n3);
 
3118
      n2 += ryf*(n3-n2);
 
3119
 
 
3120
      n1 += noise_fsc(zf)*(n2-n1);
 
3121
 
 
3122
      r += n1*ampl;
 
3123
      ampl *= perlin_amp_falloff;
 
3124
      xi<<=1; xf*=2;
 
3125
      yi<<=1; yf*=2;
 
3126
      zi<<=1; zf*=2;
 
3127
 
 
3128
      if (xf>=1.0f) { xi++; xf--; }
 
3129
      if (yf>=1.0f) { yi++; yf--; }
 
3130
      if (zf>=1.0f) { zi++; zf--; }
 
3131
    }
 
3132
    return r;
 
3133
  }
 
3134
 
 
3135
  // [toxi 031112]
 
3136
  // now adjusts to the size of the cosLUT used via
 
3137
  // the new variables, defined above
 
3138
  private float noise_fsc(float i) {
 
3139
    // using bagel's cosine table instead
 
3140
    return 0.5f*(1.0f-perlin_cosTable[(int)(i*perlin_PI)%perlin_TWOPI]);
 
3141
  }
 
3142
 
 
3143
  // [toxi 040903]
 
3144
  // make perlin noise quality user controlled to allow
 
3145
  // for different levels of detail. lower values will produce
 
3146
  // smoother results as higher octaves are surpressed
 
3147
 
 
3148
  public void noiseDetail(int lod) {
 
3149
    if (lod>0) perlin_octaves=lod;
 
3150
  }
 
3151
 
 
3152
  public void noiseDetail(int lod, float falloff) {
 
3153
    if (lod>0) perlin_octaves=lod;
 
3154
    if (falloff>0) perlin_amp_falloff=falloff;
 
3155
  }
 
3156
 
 
3157
  public void noiseSeed(long what) {
 
3158
    if (perlinRandom == null) perlinRandom = new Random();
 
3159
    perlinRandom.setSeed(what);
 
3160
    // force table reset after changing the random number seed [0122]
 
3161
    perlin = null;
 
3162
  }
 
3163
 
 
3164
 
 
3165
 
 
3166
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
 
3167
 
 
3168
 
 
3169
  protected String[] loadImageFormats;
 
3170
 
 
3171
 
 
3172
  /**
 
3173
   * Load an image from the data folder or a local directory.
 
3174
   * Supports .gif (including transparency), .tga, and .jpg images.
 
3175
   * In Java 1.3 or later, .png images are
 
3176
   * <A HREF="http://java.sun.com/j2se/1.3/docs/guide/2d/new_features.html">
 
3177
   * also supported</A>.
 
3178
   * <P>
 
3179
   * Generally, loadImage() should only be used during setup, because
 
3180
   * re-loading images inside draw() is likely to cause a significant
 
3181
   * delay while memory is allocated and the thread blocks while waiting
 
3182
   * for the image to load because loading is not asynchronous.
 
3183
   * <P>
 
3184
   * To load several images asynchronously, see more information in the
 
3185
   * FAQ about writing your own threaded image loading method.
 
3186
   * <P>
 
3187
   * As of 0096, returns null if no image of that name is found,
 
3188
   * rather than an error.
 
3189
   * <P>
 
3190
   * Release 0115 also provides support for reading TIFF and RLE-encoded
 
3191
   * Targa (.tga) files written by Processing via save() and saveFrame().
 
3192
   * Other TIFF and Targa files will probably not load, use a different
 
3193
   * format (gif, jpg and png are safest bets) when creating images with
 
3194
   * another application to use with Processing.
 
3195
   * <P>
 
3196
   * Also in release 0115, more image formats (BMP and others) can
 
3197
   * be read when using Java 1.4 and later. Because many people still
 
3198
   * use Java 1.1 and 1.3, these formats are not recommended for
 
3199
   * work that will be posted on the web. To get a list of possible
 
3200
   * image formats for use with Java 1.4 and later, use the following:
 
3201
   * <TT>println(javax.imageio.ImageIO.getReaderFormatNames())</TT>
 
3202
   * <P>
 
3203
   * Images are loaded via a byte array that is passed to
 
3204
   * Toolkit.createImage(). Unfortunately, we cannot use Applet.getImage()
 
3205
   * because it takes a URL argument, which would be a pain in the a--
 
3206
   * to make work consistently for online and local sketches.
 
3207
   * Sometimes this causes problems, resulting in issues like
 
3208
   * <A HREF="http://dev.processing.org/bugs/show_bug.cgi?id=279">Bug 279</A>
 
3209
   * and
 
3210
   * <A HREF="http://dev.processing.org/bugs/show_bug.cgi?id=305">Bug 305</A>.
 
3211
   * In release 0115, everything was instead run through javax.imageio,
 
3212
   * but that turned out to be very slow, see
 
3213
   * <A HREF="http://dev.processing.org/bugs/show_bug.cgi?id=392">Bug 392</A>.
 
3214
   * As a result, starting with 0116, the following happens:
 
3215
   * <UL>
 
3216
   * <LI>TGA and TIFF images are loaded using the internal load methods.
 
3217
   * <LI>JPG, GIF, and PNG images are loaded via loadBytes().
 
3218
   * <LI>If the image still isn't loaded, it's passed to javax.imageio.
 
3219
   * </UL>
 
3220
   * For releases 0116 and later, if you have problems such as those seen
 
3221
   * in Bugs 279 and 305, use Applet.getImage() instead. You'll be stuck
 
3222
   * with the limitations of getImage() (the headache of dealing with
 
3223
   * online/offline use). Set up your own MediaTracker, and pass the resulting
 
3224
   * java.awt.Image to the PImage constructor that takes an AWT image.
 
3225
   */
 
3226
  public PImage loadImage(String filename) {
 
3227
    return loadImage(filename, null);
 
3228
  }
 
3229
 
 
3230
 
 
3231
  /**
 
3232
   * Identical to loadImage, but allows you to specify the type of
 
3233
   * image by its extension. Especially useful when downloading from
 
3234
   * CGI scripts.
 
3235
   * <br/> <br/>
 
3236
   * Use 'unknown' as the extension to pass off to the default
 
3237
   * image loader that handles gif, jpg, and png.
 
3238
   */
 
3239
  public PImage loadImage(String filename, String extension) {
 
3240
    if (extension == null) {
 
3241
      String lower = filename.toLowerCase();
 
3242
      int dot = filename.lastIndexOf('.');
 
3243
      if (dot == -1) {
 
3244
        extension = "unknown";  // no extension found
 
3245
      }
 
3246
      extension = lower.substring(dot + 1);
 
3247
 
 
3248
      // check for, and strip any parameters on the url, i.e.
 
3249
      // filename.jpg?blah=blah&something=that
 
3250
      int question = extension.indexOf('?');
 
3251
      if (question != -1) {
 
3252
        extension = extension.substring(0, question);
 
3253
      }
 
3254
    }
 
3255
 
 
3256
    // just in case. them users will try anything!
 
3257
    extension = extension.toLowerCase();
 
3258
 
 
3259
    if (extension.equals("tga")) {
 
3260
      try {
 
3261
        return loadImageTGA(filename);
 
3262
      } catch (IOException e) {
 
3263
        e.printStackTrace();
 
3264
        return null;
 
3265
      }
 
3266
    }
 
3267
 
 
3268
    if (extension.equals("tif") || extension.equals("tiff")) {
 
3269
      byte bytes[] = loadBytes(filename);
 
3270
      return (bytes == null) ? null : PImage.loadTIFF(bytes);
 
3271
    }
 
3272
 
 
3273
    // For jpeg, gif, and png, load them using createImage(),
 
3274
    // because the javax.imageio code was found to be much slower, see
 
3275
    // <A HREF="http://dev.processing.org/bugs/show_bug.cgi?id=392">Bug 392</A>.
 
3276
    try {
 
3277
      if (extension.equals("jpg") || extension.equals("jpeg") ||
 
3278
          extension.equals("gif") || extension.equals("png") ||
 
3279
          extension.equals("unknown")) {
 
3280
        byte bytes[] = loadBytes(filename);
 
3281
        if (bytes == null) {
 
3282
          return null;
 
3283
        } else {
 
3284
          Image awtImage = Toolkit.getDefaultToolkit().createImage(bytes);
 
3285
          PImage image = loadImageMT(awtImage);
 
3286
          if (image.width == -1) {
 
3287
            System.err.println("The file " + filename +
 
3288
                               " contains bad image data, or may not be an image.");
 
3289
          }
 
3290
          // if it's a .gif image, test to see if it has transparency
 
3291
          if (extension.equals("gif") || extension.equals("png")) {
 
3292
            image.checkAlpha();
 
3293
          }
 
3294
          return image;
 
3295
        }
 
3296
      }
 
3297
    } catch (Exception e) {
 
3298
      // show error, but move on to the stuff below, see if it'll work
 
3299
      e.printStackTrace();
 
3300
    }
 
3301
 
 
3302
    if (loadImageFormats == null) {
 
3303
      loadImageFormats = ImageIO.getReaderFormatNames();
 
3304
    }
 
3305
    if (loadImageFormats != null) {
 
3306
      for (int i = 0; i < loadImageFormats.length; i++) {
 
3307
        if (extension.equals(loadImageFormats[i])) {
 
3308
          return loadImageIO(filename);
 
3309
        }
 
3310
      }
 
3311
    }
 
3312
 
 
3313
    // failed, could not load image after all those attempts
 
3314
    System.err.println("Could not find a method to load " + filename);
 
3315
    return null;
 
3316
  }
 
3317
 
 
3318
 
 
3319
  public PImage requestImage(String filename) {
 
3320
    return requestImage(filename, null);
 
3321
  }
 
3322
 
 
3323
 
 
3324
  public PImage requestImage(String filename, String extension) {
 
3325
    PImage vessel = createImage(0, 0, ARGB);
 
3326
    AsyncImageLoader ail =
 
3327
      new AsyncImageLoader(filename, extension, vessel);
 
3328
    ail.start();
 
3329
    return vessel;
 
3330
  }
 
3331
 
 
3332
 
 
3333
  /**
 
3334
   * By trial and error, four image loading threads seem to work best when
 
3335
   * loading images from online. This is consistent with the number of open
 
3336
   * connections that web browsers will maintain. The variable is made public
 
3337
   * (however no accessor has been added since it's esoteric) if you really
 
3338
   * want to have control over the value used. For instance, when loading local
 
3339
   * files, it might be better to only have a single thread (or two) loading
 
3340
   * images so that you're disk isn't simply jumping around.
 
3341
   */
 
3342
  public int requestImageMax = 4;
 
3343
  volatile int requestImageCount;
 
3344
 
 
3345
  class AsyncImageLoader extends Thread {
 
3346
    String filename;
 
3347
    String extension;
 
3348
    PImage vessel;
 
3349
 
 
3350
    public AsyncImageLoader(String filename, String extension, PImage vessel) {
 
3351
      this.filename = filename;
 
3352
      this.extension = extension;
 
3353
      this.vessel = vessel;
 
3354
    }
 
3355
 
 
3356
    public void run() {
 
3357
      while (requestImageCount == requestImageMax) {
 
3358
        try {
 
3359
          Thread.sleep(10);
 
3360
        } catch (InterruptedException e) { }
 
3361
      }
 
3362
      requestImageCount++;
 
3363
 
 
3364
      PImage actual = loadImage(filename, extension);
 
3365
 
 
3366
      // An error message should have already printed
 
3367
      if (actual == null) {
 
3368
        vessel.width = -1;
 
3369
        vessel.height = -1;
 
3370
 
 
3371
      } else {
 
3372
        vessel.width = actual.width;
 
3373
        vessel.height = actual.height;
 
3374
        vessel.format = actual.format;
 
3375
        vessel.pixels = actual.pixels;
 
3376
      }
 
3377
      requestImageCount--;
 
3378
    }
 
3379
  }
 
3380
 
 
3381
 
 
3382
  /**
 
3383
   * Load an AWT image synchronously by setting up a MediaTracker for
 
3384
   * a single image, and blocking until it has loaded.
 
3385
   */
 
3386
  protected PImage loadImageMT(Image awtImage) {
 
3387
    MediaTracker tracker = new MediaTracker(this);
 
3388
    tracker.addImage(awtImage, 0);
 
3389
    try {
 
3390
      tracker.waitForAll();
 
3391
    } catch (InterruptedException e) {
 
3392
      //e.printStackTrace();  // non-fatal, right?
 
3393
    }
 
3394
 
 
3395
    PImage image = new PImage(awtImage);
 
3396
    image.parent = this;
 
3397
    return image;
 
3398
  }
 
3399
 
 
3400
 
 
3401
  /**
 
3402
   * Use Java 1.4 ImageIO methods to load an image.
 
3403
   */
 
3404
  protected PImage loadImageIO(String filename) {
 
3405
    InputStream stream = createInput(filename);
 
3406
    if (stream == null) {
 
3407
      System.err.println("The image " + filename + " could not be found.");
 
3408
      return null;
 
3409
    }
 
3410
 
 
3411
    try {
 
3412
      BufferedImage bi = ImageIO.read(stream);
 
3413
      PImage outgoing = new PImage(bi.getWidth(), bi.getHeight());
 
3414
      outgoing.parent = this;
 
3415
 
 
3416
      bi.getRGB(0, 0, outgoing.width, outgoing.height,
 
3417
                outgoing.pixels, 0, outgoing.width);
 
3418
 
 
3419
      // check the alpha for this image
 
3420
      // was gonna call getType() on the image to see if RGB or ARGB,
 
3421
      // but it's not actually useful, since gif images will come through
 
3422
      // as TYPE_BYTE_INDEXED, which means it'll still have to check for
 
3423
      // the transparency. also, would have to iterate through all the other
 
3424
      // types and guess whether alpha was in there, so.. just gonna stick
 
3425
      // with the old method.
 
3426
      outgoing.checkAlpha();
 
3427
 
 
3428
      // return the image
 
3429
      return outgoing;
 
3430
 
 
3431
    } catch (Exception e) {
 
3432
      e.printStackTrace();
 
3433
      return null;
 
3434
    }
 
3435
  }
 
3436
 
 
3437
 
 
3438
  /**
 
3439
   * Targa image loader for RLE-compressed TGA files.
 
3440
   * <P>
 
3441
   * Rewritten for 0115 to read/write RLE-encoded targa images.
 
3442
   * For 0125, non-RLE encoded images are now supported, along with
 
3443
   * images whose y-order is reversed (which is standard for TGA files).
 
3444
   */
 
3445
  protected PImage loadImageTGA(String filename) throws IOException {
 
3446
    InputStream is = createInput(filename);
 
3447
    if (is == null) return null;
 
3448
 
 
3449
    byte header[] = new byte[18];
 
3450
    int offset = 0;
 
3451
    do {
 
3452
      int count = is.read(header, offset, header.length - offset);
 
3453
      if (count == -1) return null;
 
3454
      offset += count;
 
3455
    } while (offset < 18);
 
3456
 
 
3457
    /*
 
3458
      header[2] image type code
 
3459
      2  (0x02) - Uncompressed, RGB images.
 
3460
      3  (0x03) - Uncompressed, black and white images.
 
3461
      10 (0x0A) - Runlength encoded RGB images.
 
3462
      11 (0x0B) - Compressed, black and white images. (grayscale?)
 
3463
 
 
3464
      header[16] is the bit depth (8, 24, 32)
 
3465
 
 
3466
      header[17] image descriptor (packed bits)
 
3467
      0x20 is 32 = origin upper-left
 
3468
      0x28 is 32 + 8 = origin upper-left + 32 bits
 
3469
 
 
3470
        7  6  5  4  3  2  1  0
 
3471
      128 64 32 16  8  4  2  1
 
3472
    */
 
3473
 
 
3474
    int format = 0;
 
3475
 
 
3476
    if (((header[2] == 3) || (header[2] == 11)) &&  // B&W, plus RLE or not
 
3477
        (header[16] == 8) &&  // 8 bits
 
3478
        ((header[17] == 0x8) || (header[17] == 0x28))) {  // origin, 32 bit
 
3479
      format = ALPHA;
 
3480
 
 
3481
    } else if (((header[2] == 2) || (header[2] == 10)) &&  // RGB, RLE or not
 
3482
               (header[16] == 24) &&  // 24 bits
 
3483
               ((header[17] == 0x20) || (header[17] == 0))) {  // origin
 
3484
      format = RGB;
 
3485
 
 
3486
    } else if (((header[2] == 2) || (header[2] == 10)) &&
 
3487
               (header[16] == 32) &&
 
3488
               ((header[17] == 0x8) || (header[17] == 0x28))) {  // origin, 32
 
3489
      format = ARGB;
 
3490
    }
 
3491
 
 
3492
    if (format == 0) {
 
3493
      System.err.println("Unknown .tga file format for " + filename);
 
3494
                         //" (" + header[2] + " " +
 
3495
                         //(header[16] & 0xff) + " " +
 
3496
                         //hex(header[17], 2) + ")");
 
3497
      return null;
 
3498
    }
 
3499
 
 
3500
    int w = ((header[13] & 0xff) << 8) + (header[12] & 0xff);
 
3501
    int h = ((header[15] & 0xff) << 8) + (header[14] & 0xff);
 
3502
    PImage outgoing = createImage(w, h, format);
 
3503
 
 
3504
    // where "reversed" means upper-left corner (normal for most of
 
3505
    // the modernized world, but "reversed" for the tga spec)
 
3506
    boolean reversed = (header[17] & 0x20) != 0;
 
3507
 
 
3508
    if ((header[2] == 2) || (header[2] == 3)) {  // not RLE encoded
 
3509
      if (reversed) {
 
3510
        int index = (h-1) * w;
 
3511
        switch (format) {
 
3512
        case ALPHA:
 
3513
          for (int y = h-1; y >= 0; y--) {
 
3514
            for (int x = 0; x < w; x++) {
 
3515
              outgoing.pixels[index + x] = is.read();
 
3516
            }
 
3517
            index -= w;
 
3518
          }
 
3519
          break;
 
3520
        case RGB:
 
3521
          for (int y = h-1; y >= 0; y--) {
 
3522
            for (int x = 0; x < w; x++) {
 
3523
              outgoing.pixels[index + x] =
 
3524
                is.read() | (is.read() << 8) | (is.read() << 16) |
 
3525
                0xff000000;
 
3526
            }
 
3527
            index -= w;
 
3528
          }
 
3529
          break;
 
3530
        case ARGB:
 
3531
          for (int y = h-1; y >= 0; y--) {
 
3532
            for (int x = 0; x < w; x++) {
 
3533
              outgoing.pixels[index + x] =
 
3534
                is.read() | (is.read() << 8) | (is.read() << 16) |
 
3535
                (is.read() << 24);
 
3536
            }
 
3537
            index -= w;
 
3538
          }
 
3539
        }
 
3540
      } else {  // not reversed
 
3541
        int count = w * h;
 
3542
        switch (format) {
 
3543
        case ALPHA:
 
3544
          for (int i = 0; i < count; i++) {
 
3545
            outgoing.pixels[i] = is.read();
 
3546
          }
 
3547
          break;
 
3548
        case RGB:
 
3549
          for (int i = 0; i < count; i++) {
 
3550
            outgoing.pixels[i] =
 
3551
              is.read() | (is.read() << 8) | (is.read() << 16) |
 
3552
              0xff000000;
 
3553
          }
 
3554
          break;
 
3555
        case ARGB:
 
3556
          for (int i = 0; i < count; i++) {
 
3557
            outgoing.pixels[i] =
 
3558
              is.read() | (is.read() << 8) | (is.read() << 16) |
 
3559
              (is.read() << 24);
 
3560
          }
 
3561
          break;
 
3562
        }
 
3563
      }
 
3564
 
 
3565
    } else {  // header[2] is 10 or 11
 
3566
      int index = 0;
 
3567
      int px[] = outgoing.pixels;
 
3568
 
 
3569
      while (index < px.length) {
 
3570
        int num = is.read();
 
3571
        boolean isRLE = (num & 0x80) != 0;
 
3572
        if (isRLE) {
 
3573
          num -= 127;  // (num & 0x7F) + 1
 
3574
          int pixel = 0;
 
3575
          switch (format) {
 
3576
          case ALPHA:
 
3577
            pixel = is.read();
 
3578
            break;
 
3579
          case RGB:
 
3580
            pixel = 0xFF000000 |
 
3581
              is.read() | (is.read() << 8) | (is.read() << 16);
 
3582
            //(is.read() << 16) | (is.read() << 8) | is.read();
 
3583
            break;
 
3584
          case ARGB:
 
3585
            pixel = is.read() |
 
3586
              (is.read() << 8) | (is.read() << 16) | (is.read() << 24);
 
3587
            break;
 
3588
          }
 
3589
          for (int i = 0; i < num; i++) {
 
3590
            px[index++] = pixel;
 
3591
            if (index == px.length) break;
 
3592
          }
 
3593
        } else {  // write up to 127 bytes as uncompressed
 
3594
          num += 1;
 
3595
          switch (format) {
 
3596
          case ALPHA:
 
3597
            for (int i = 0; i < num; i++) {
 
3598
              px[index++] = is.read();
 
3599
            }
 
3600
            break;
 
3601
          case RGB:
 
3602
            for (int i = 0; i < num; i++) {
 
3603
              px[index++] = 0xFF000000 |
 
3604
                is.read() | (is.read() << 8) | (is.read() << 16);
 
3605
              //(is.read() << 16) | (is.read() << 8) | is.read();
 
3606
            }
 
3607
            break;
 
3608
          case ARGB:
 
3609
            for (int i = 0; i < num; i++) {
 
3610
              px[index++] = is.read() | //(is.read() << 24) |
 
3611
                (is.read() << 8) | (is.read() << 16) | (is.read() << 24);
 
3612
              //(is.read() << 16) | (is.read() << 8) | is.read();
 
3613
            }
 
3614
            break;
 
3615
          }
 
3616
        }
 
3617
      }
 
3618
 
 
3619
      if (!reversed) {
 
3620
        int[] temp = new int[w];
 
3621
        for (int y = 0; y < h/2; y++) {
 
3622
          int z = (h-1) - y;
 
3623
          System.arraycopy(px, y*w, temp, 0, w);
 
3624
          System.arraycopy(px, z*w, px, y*w, w);
 
3625
          System.arraycopy(temp, 0, px, z*w, w);
 
3626
        }
 
3627
      }
 
3628
    }
 
3629
 
 
3630
    return outgoing;
 
3631
  }
 
3632
 
 
3633
 
 
3634
 
 
3635
  //////////////////////////////////////////////////////////////
 
3636
 
 
3637
  // SHAPE I/O
 
3638
 
 
3639
 
 
3640
  /**
 
3641
   * Load a geometry from a file as a PShape. Currently only supports SVG data.
 
3642
   */
 
3643
  public PShape loadShape(String filename) {
 
3644
    if (filename.toLowerCase().endsWith(".svg")) {
 
3645
      return new PShapeSVG(this, filename);
 
3646
    }
 
3647
    return null;
 
3648
  }
 
3649
 
 
3650
 
 
3651
 
 
3652
  //////////////////////////////////////////////////////////////
 
3653
 
 
3654
  // FONT I/O
 
3655
 
 
3656
 
 
3657
  public PFont loadFont(String filename) {
 
3658
    try {
 
3659
      InputStream input = createInput(filename);
 
3660
      return new PFont(input);
 
3661
 
 
3662
    } catch (Exception e) {
 
3663
      die("Could not load font " + filename + ". " +
 
3664
          "Make sure that the font has been copied " +
 
3665
          "to the data folder of your sketch.", e);
 
3666
    }
 
3667
    return null;
 
3668
  }
 
3669
 
 
3670
 
 
3671
  public PFont createFont(String name, float size) {
 
3672
    return createFont(name, size, true, PFont.DEFAULT_CHARSET);
 
3673
  }
 
3674
 
 
3675
 
 
3676
  public PFont createFont(String name, float size, boolean smooth) {
 
3677
    return createFont(name, size, smooth, PFont.DEFAULT_CHARSET);
 
3678
  }
 
3679
 
 
3680
 
 
3681
  /**
 
3682
   * Create a .vlw font on the fly from either a font name that's
 
3683
   * installed on the system, or from a .ttf or .otf that's inside
 
3684
   * the data folder of this sketch.
 
3685
   * <P/>
 
3686
   * Only works with Java 1.3 or later. Many .otf fonts don't seem
 
3687
   * to be supported by Java, perhaps because they're CFF based?
 
3688
   * <P/>
 
3689
   * Font names are inconsistent across platforms and Java versions.
 
3690
   * On Mac OS X, Java 1.3 uses the font menu name of the font,
 
3691
   * whereas Java 1.4 uses the PostScript name of the font. Java 1.4
 
3692
   * on OS X will also accept the font menu name as well. On Windows,
 
3693
   * it appears that only the menu names are used, no matter what
 
3694
   * Java version is in use. Naming system unknown/untested for 1.5.
 
3695
   * <P/>
 
3696
   * Use 'null' for the charset if you want to use any of the 65,536
 
3697
   * unicode characters that exist in the font. Note that this can
 
3698
   * produce an enormous file or may cause an OutOfMemoryError.
 
3699
   */
 
3700
  public PFont createFont(String name, float size,
 
3701
                          boolean smooth, char charset[]) {
 
3702
    String lowerName = name.toLowerCase();
 
3703
    Font baseFont = null;
 
3704
 
 
3705
    try {
 
3706
      if (lowerName.endsWith(".otf") || lowerName.endsWith(".ttf")) {
 
3707
        InputStream stream = createInput(name);
 
3708
        if (stream == null) {
 
3709
          System.err.println("The font \"" + name + "\" " +
 
3710
                             "is missing or inaccessible, make sure " +
 
3711
                             "the URL is valid or that the file has been " +
 
3712
                             "added to your sketch and is readable.");
 
3713
          return null;
 
3714
        }
 
3715
        baseFont = Font.createFont(Font.TRUETYPE_FONT, createInput(name));
 
3716
 
 
3717
      } else {
 
3718
        //baseFont = new Font(name, Font.PLAIN, 1);
 
3719
        baseFont = PFont.findFont(name);
 
3720
      }
 
3721
    } catch (Exception e) {
 
3722
      System.err.println("Problem using createFont() with " + name);
 
3723
      e.printStackTrace();
 
3724
    }
 
3725
    return new PFont(baseFont.deriveFont(size), smooth, charset);
 
3726
  }
 
3727
 
 
3728
 
 
3729
 
 
3730
  //////////////////////////////////////////////////////////////
 
3731
 
 
3732
  // FILE/FOLDER SELECTION
 
3733
 
 
3734
 
 
3735
  public File selectedFile;
 
3736
  protected Frame parentFrame;
 
3737
 
 
3738
 
 
3739
  protected void checkParentFrame() {
 
3740
    if (parentFrame == null) {
 
3741
      Component comp = getParent();
 
3742
      while (comp != null) {
 
3743
        if (comp instanceof Frame) {
 
3744
          parentFrame = (Frame) comp;
 
3745
          break;
 
3746
        }
 
3747
        comp = comp.getParent();
 
3748
      }
 
3749
      // Who you callin' a hack?
 
3750
      if (parentFrame == null) {
 
3751
        parentFrame = new Frame();
 
3752
      }
 
3753
    }
 
3754
  }
 
3755
 
 
3756
 
 
3757
  /**
 
3758
   * Open a platform-specific file chooser dialog to select a file for input.
 
3759
   * @return full path to the selected file, or null if no selection.
 
3760
   */
 
3761
  public String selectInput() {
 
3762
    return selectInput("Select a file...");
 
3763
  }
 
3764
 
 
3765
 
 
3766
  /**
 
3767
   * Open a platform-specific file chooser dialog to select a file for input.
 
3768
   * @param prompt Mesage to show the user when prompting for a file.
 
3769
   * @return full path to the selected file, or null if canceled.
 
3770
   */
 
3771
  public String selectInput(String prompt) {
 
3772
    return selectFileImpl(prompt, FileDialog.LOAD);
 
3773
  }
 
3774
 
 
3775
 
 
3776
  /**
 
3777
   * Open a platform-specific file save dialog to select a file for output.
 
3778
   * @return full path to the file entered, or null if canceled.
 
3779
   */
 
3780
  public String selectOutput() {
 
3781
    return selectOutput("Save as...");
 
3782
  }
 
3783
 
 
3784
 
 
3785
  /**
 
3786
   * Open a platform-specific file save dialog to select a file for output.
 
3787
   * @param prompt Mesage to show the user when prompting for a file.
 
3788
   * @return full path to the file entered, or null if canceled.
 
3789
   */
 
3790
  public String selectOutput(String prompt) {
 
3791
    return selectFileImpl(prompt, FileDialog.SAVE);
 
3792
  }
 
3793
 
 
3794
 
 
3795
  protected String selectFileImpl(final String prompt, final int mode) {
 
3796
    checkParentFrame();
 
3797
 
 
3798
    try {
 
3799
      SwingUtilities.invokeAndWait(new Runnable() {
 
3800
        public void run() {
 
3801
          FileDialog fileDialog =
 
3802
            new FileDialog(parentFrame, prompt, mode);
 
3803
          fileDialog.setVisible(true);
 
3804
          String directory = fileDialog.getDirectory();
 
3805
          String filename = fileDialog.getFile();
 
3806
          selectedFile =
 
3807
            (filename == null) ? null : new File(directory, filename);
 
3808
        }
 
3809
      });
 
3810
      return (selectedFile == null) ? null : selectedFile.getAbsolutePath();
 
3811
 
 
3812
    } catch (Exception e) {
 
3813
      e.printStackTrace();
 
3814
      return null;
 
3815
    }
 
3816
  }
 
3817
 
 
3818
 
 
3819
  /**
 
3820
   * Open a platform-specific folder chooser dialog.
 
3821
   * @return full path to the selected folder, or null if no selection.
 
3822
   */
 
3823
  public String selectFolder() {
 
3824
    return selectFolder("Select a folder...");
 
3825
  }
 
3826
 
 
3827
 
 
3828
  /**
 
3829
   * Open a platform-specific folder chooser dialog.
 
3830
   * @param prompt Mesage to show the user when prompting for a file.
 
3831
   * @return full path to the selected folder, or null if no selection.
 
3832
   */
 
3833
  public String selectFolder(final String prompt) {
 
3834
    checkParentFrame();
 
3835
 
 
3836
    try {
 
3837
      SwingUtilities.invokeAndWait(new Runnable() {
 
3838
        public void run() {
 
3839
          if (platform == MACOSX) {
 
3840
            FileDialog fileDialog =
 
3841
              new FileDialog(parentFrame, prompt, FileDialog.LOAD);
 
3842
            System.setProperty("apple.awt.fileDialogForDirectories", "true");
 
3843
            fileDialog.setVisible(true);
 
3844
            System.setProperty("apple.awt.fileDialogForDirectories", "false");
 
3845
            String filename = fileDialog.getFile();
 
3846
            selectedFile = (filename == null) ? null :
 
3847
              new File(fileDialog.getDirectory(), fileDialog.getFile());
 
3848
          } else {
 
3849
            JFileChooser fileChooser = new JFileChooser();
 
3850
            fileChooser.setDialogTitle(prompt);
 
3851
            fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
 
3852
 
 
3853
            int returned = fileChooser.showOpenDialog(parentFrame);
 
3854
            System.out.println(returned);
 
3855
            if (returned == JFileChooser.CANCEL_OPTION) {
 
3856
              selectedFile = null;
 
3857
            } else {
 
3858
              selectedFile = fileChooser.getSelectedFile();
 
3859
            }
 
3860
          }
 
3861
        }
 
3862
      });
 
3863
      return (selectedFile == null) ? null : selectedFile.getAbsolutePath();
 
3864
 
 
3865
    } catch (Exception e) {
 
3866
      e.printStackTrace();
 
3867
      return null;
 
3868
    }
 
3869
  }
 
3870
 
 
3871
 
 
3872
 
 
3873
  //////////////////////////////////////////////////////////////
 
3874
 
 
3875
  // READERS AND WRITERS
 
3876
 
 
3877
 
 
3878
  /**
 
3879
   * I want to read lines from a file. I have RSI from typing these
 
3880
   * eight lines of code so many times.
 
3881
   */
 
3882
  public BufferedReader createReader(String filename) {
 
3883
    try {
 
3884
      InputStream is = createInput(filename);
 
3885
      if (is == null) {
 
3886
        System.err.println(filename + " does not exist or could not be read");
 
3887
        return null;
 
3888
      }
 
3889
      return createReader(is);
 
3890
 
 
3891
    } catch (Exception e) {
 
3892
      if (filename == null) {
 
3893
        System.err.println("Filename passed to reader() was null");
 
3894
      } else {
 
3895
        System.err.println("Couldn't create a reader for " + filename);
 
3896
      }
 
3897
    }
 
3898
    return null;
 
3899
  }
 
3900
 
 
3901
 
 
3902
  /**
 
3903
   * I want to read lines from a file. And I'm still annoyed.
 
3904
   */
 
3905
  static public BufferedReader createReader(File file) {
 
3906
    try {
 
3907
      InputStream is = new FileInputStream(file);
 
3908
      if (file.getName().toLowerCase().endsWith(".gz")) {
 
3909
        is = new GZIPInputStream(is);
 
3910
      }
 
3911
      return createReader(is);
 
3912
 
 
3913
    } catch (Exception e) {
 
3914
      if (file == null) {
 
3915
        throw new RuntimeException("File passed to createReader() was null");
 
3916
      } else {
 
3917
        e.printStackTrace();
 
3918
        throw new RuntimeException("Couldn't create a reader for " +
 
3919
                                   file.getAbsolutePath());
 
3920
      }
 
3921
    }
 
3922
    //return null;
 
3923
  }
 
3924
 
 
3925
 
 
3926
  /**
 
3927
   * I want to read lines from a stream. If I have to type the
 
3928
   * following lines any more I'm gonna send Sun my medical bills.
 
3929
   */
 
3930
  static public BufferedReader createReader(InputStream input) {
 
3931
    InputStreamReader isr = null;
 
3932
    try {
 
3933
      isr = new InputStreamReader(input, "UTF-8");
 
3934
    } catch (UnsupportedEncodingException e) { }  // not gonna happen
 
3935
    return new BufferedReader(isr);
 
3936
  }
 
3937
 
 
3938
 
 
3939
  /**
 
3940
   * I want to print lines to a file. Why can't I?
 
3941
   */
 
3942
  public PrintWriter createWriter(String filename) {
 
3943
    return createWriter(saveFile(filename));
 
3944
  }
 
3945
 
 
3946
 
 
3947
  /**
 
3948
   * I want to print lines to a file. I have RSI from typing these
 
3949
   * eight lines of code so many times.
 
3950
   */
 
3951
  static public PrintWriter createWriter(File file) {
 
3952
    try {
 
3953
      createPath(file);  // make sure in-between folders exist
 
3954
      OutputStream output = new FileOutputStream(file);
 
3955
      if (file.getName().toLowerCase().endsWith(".gz")) {
 
3956
        output = new GZIPOutputStream(output);
 
3957
      }
 
3958
      return createWriter(output);
 
3959
 
 
3960
    } catch (Exception e) {
 
3961
      if (file == null) {
 
3962
        throw new RuntimeException("File passed to createWriter() was null");
 
3963
      } else {
 
3964
        e.printStackTrace();
 
3965
        throw new RuntimeException("Couldn't create a writer for " +
 
3966
                                   file.getAbsolutePath());
 
3967
      }
 
3968
    }
 
3969
    //return null;
 
3970
  }
 
3971
 
 
3972
 
 
3973
  /**
 
3974
   * I want to print lines to a file. Why am I always explaining myself?
 
3975
   * It's the JavaSoft API engineers who need to explain themselves.
 
3976
   */
 
3977
  static public PrintWriter createWriter(OutputStream output) {
 
3978
    try {
 
3979
      OutputStreamWriter osw = new OutputStreamWriter(output, "UTF-8");
 
3980
      return new PrintWriter(osw);
 
3981
    } catch (UnsupportedEncodingException e) { }  // not gonna happen
 
3982
    return null;
 
3983
  }
 
3984
 
 
3985
 
 
3986
  //////////////////////////////////////////////////////////////
 
3987
 
 
3988
  // FILE INPUT
 
3989
 
 
3990
 
 
3991
  /**
 
3992
   * @deprecated As of release 0136, use createInput() instead.
 
3993
   */
 
3994
  public InputStream openStream(String filename) {
 
3995
    return createInput(filename);
 
3996
  }
 
3997
 
 
3998
 
 
3999
  /**
 
4000
   * Simplified method to open a Java InputStream.
 
4001
   * <P>
 
4002
   * This method is useful if you want to use the facilities provided
 
4003
   * by PApplet to easily open things from the data folder or from a URL,
 
4004
   * but want an InputStream object so that you can use other Java
 
4005
   * methods to take more control of how the stream is read.
 
4006
   * <P>
 
4007
   * If the requested item doesn't exist, null is returned.
 
4008
   * (Prior to 0096, die() would be called, killing the applet)
 
4009
   * <P>
 
4010
   * For 0096+, the "data" folder is exported intact with subfolders,
 
4011
   * and openStream() properly handles subdirectories from the data folder
 
4012
   * <P>
 
4013
   * If not online, this will also check to see if the user is asking
 
4014
   * for a file whose name isn't properly capitalized. This helps prevent
 
4015
   * issues when a sketch is exported to the web, where case sensitivity
 
4016
   * matters, as opposed to Windows and the Mac OS default where
 
4017
   * case sensitivity is preserved but ignored.
 
4018
   * <P>
 
4019
   * It is strongly recommended that libraries use this method to open
 
4020
   * data files, so that the loading sequence is handled in the same way
 
4021
   * as functions like loadBytes(), loadImage(), etc.
 
4022
   * <P>
 
4023
   * The filename passed in can be:
 
4024
   * <UL>
 
4025
   * <LI>A URL, for instance openStream("http://processing.org/");
 
4026
   * <LI>A file in the sketch's data folder
 
4027
   * <LI>Another file to be opened locally (when running as an application)
 
4028
   * </UL>
 
4029
   */
 
4030
  public InputStream createInput(String filename) {
 
4031
    InputStream input = createInputRaw(filename);
 
4032
    if ((input != null) && filename.toLowerCase().endsWith(".gz")) {
 
4033
      try {
 
4034
        return new GZIPInputStream(input);
 
4035
      } catch (IOException e) {
 
4036
        e.printStackTrace();
 
4037
        return null;
 
4038
      }
 
4039
    }
 
4040
    return input;
 
4041
  }
 
4042
 
 
4043
 
 
4044
  /**
 
4045
   * Call openStream() without automatic gzip decompression.
 
4046
   */
 
4047
  public InputStream createInputRaw(String filename) {
 
4048
    InputStream stream = null;
 
4049
 
 
4050
    if (filename == null) return null;
 
4051
 
 
4052
    if (filename.length() == 0) {
 
4053
      // an error will be called by the parent function
 
4054
      //System.err.println("The filename passed to openStream() was empty.");
 
4055
      return null;
 
4056
    }
 
4057
 
 
4058
    // safe to check for this as a url first. this will prevent online
 
4059
    // access logs from being spammed with GET /sketchfolder/http://blahblah
 
4060
    try {
 
4061
      URL url = new URL(filename);
 
4062
      stream = url.openStream();
 
4063
      return stream;
 
4064
 
 
4065
    } catch (MalformedURLException mfue) {
 
4066
      // not a url, that's fine
 
4067
 
 
4068
    } catch (FileNotFoundException fnfe) {
 
4069
      // Java 1.5 likes to throw this when URL not available. (fix for 0119)
 
4070
      // http://dev.processing.org/bugs/show_bug.cgi?id=403
 
4071
 
 
4072
    } catch (IOException e) {
 
4073
      // changed for 0117, shouldn't be throwing exception
 
4074
      e.printStackTrace();
 
4075
      //System.err.println("Error downloading from URL " + filename);
 
4076
      return null;
 
4077
      //throw new RuntimeException("Error downloading from URL " + filename);
 
4078
    }
 
4079
 
 
4080
    // Moved this earlier than the getResourceAsStream() checks, because
 
4081
    // calling getResourceAsStream() on a directory lists its contents.
 
4082
    // http://dev.processing.org/bugs/show_bug.cgi?id=716
 
4083
    try {
 
4084
      // First see if it's in a data folder. This may fail by throwing
 
4085
      // a SecurityException. If so, this whole block will be skipped.
 
4086
      File file = new File(dataPath(filename));
 
4087
      if (!file.exists()) {
 
4088
        // next see if it's just in the sketch folder
 
4089
        file = new File(sketchPath, filename);
 
4090
      }
 
4091
      if (file.isDirectory()) {
 
4092
        return null;
 
4093
      }
 
4094
      if (file.exists()) {
 
4095
        try {
 
4096
          // handle case sensitivity check
 
4097
          String filePath = file.getCanonicalPath();
 
4098
          String filenameActual = new File(filePath).getName();
 
4099
          // make sure there isn't a subfolder prepended to the name
 
4100
          String filenameShort = new File(filename).getName();
 
4101
          // if the actual filename is the same, but capitalized
 
4102
          // differently, warn the user.
 
4103
          //if (filenameActual.equalsIgnoreCase(filenameShort) &&
 
4104
          //!filenameActual.equals(filenameShort)) {
 
4105
          if (!filenameActual.equals(filenameShort)) {
 
4106
            throw new RuntimeException("This file is named " +
 
4107
                                       filenameActual + " not " +
 
4108
                                       filename + ". Rename the file " +
 
4109
            "or change your code.");
 
4110
          }
 
4111
        } catch (IOException e) { }
 
4112
      }
 
4113
 
 
4114
      // if this file is ok, may as well just load it
 
4115
      stream = new FileInputStream(file);
 
4116
      if (stream != null) return stream;
 
4117
 
 
4118
      // have to break these out because a general Exception might
 
4119
      // catch the RuntimeException being thrown above
 
4120
    } catch (IOException ioe) {
 
4121
    } catch (SecurityException se) { }
 
4122
 
 
4123
    // Using getClassLoader() prevents java from converting dots
 
4124
    // to slashes or requiring a slash at the beginning.
 
4125
    // (a slash as a prefix means that it'll load from the root of
 
4126
    // the jar, rather than trying to dig into the package location)
 
4127
    ClassLoader cl = getClass().getClassLoader();
 
4128
 
 
4129
    // by default, data files are exported to the root path of the jar.
 
4130
    // (not the data folder) so check there first.
 
4131
    stream = cl.getResourceAsStream("data/" + filename);
 
4132
    if (stream != null) {
 
4133
      String cn = stream.getClass().getName();
 
4134
      // this is an irritation of sun's java plug-in, which will return
 
4135
      // a non-null stream for an object that doesn't exist. like all good
 
4136
      // things, this is probably introduced in java 1.5. awesome!
 
4137
      // http://dev.processing.org/bugs/show_bug.cgi?id=359
 
4138
      if (!cn.equals("sun.plugin.cache.EmptyInputStream")) {
 
4139
        return stream;
 
4140
      }
 
4141
    }
 
4142
 
 
4143
    // When used with an online script, also need to check without the
 
4144
    // data folder, in case it's not in a subfolder called 'data'.
 
4145
    // http://dev.processing.org/bugs/show_bug.cgi?id=389
 
4146
    stream = cl.getResourceAsStream(filename);
 
4147
    if (stream != null) {
 
4148
      String cn = stream.getClass().getName();
 
4149
      if (!cn.equals("sun.plugin.cache.EmptyInputStream")) {
 
4150
        return stream;
 
4151
      }
 
4152
    }
 
4153
 
 
4154
    try {
 
4155
      // attempt to load from a local file, used when running as
 
4156
      // an application, or as a signed applet
 
4157
      try {  // first try to catch any security exceptions
 
4158
        try {
 
4159
          stream = new FileInputStream(dataPath(filename));
 
4160
          if (stream != null) return stream;
 
4161
        } catch (IOException e2) { }
 
4162
 
 
4163
        try {
 
4164
          stream = new FileInputStream(sketchPath(filename));
 
4165
          if (stream != null) return stream;
 
4166
        } catch (Exception e) { }  // ignored
 
4167
 
 
4168
        try {
 
4169
          stream = new FileInputStream(filename);
 
4170
          if (stream != null) return stream;
 
4171
        } catch (IOException e1) { }
 
4172
 
 
4173
      } catch (SecurityException se) { }  // online, whups
 
4174
 
 
4175
    } catch (Exception e) {
 
4176
      //die(e.getMessage(), e);
 
4177
      e.printStackTrace();
 
4178
    }
 
4179
    return null;
 
4180
  }
 
4181
 
 
4182
 
 
4183
  static public InputStream createInput(File file) {
 
4184
    try {
 
4185
      InputStream input = new FileInputStream(file);
 
4186
      if (file.getName().toLowerCase().endsWith(".gz")) {
 
4187
        return new GZIPInputStream(input);
 
4188
      }
 
4189
      return input;
 
4190
 
 
4191
    } catch (IOException e) {
 
4192
      if (file == null) {
 
4193
        throw new RuntimeException("File passed to openStream() was null");
 
4194
 
 
4195
      } else {
 
4196
        e.printStackTrace();
 
4197
        throw new RuntimeException("Couldn't openStream() for " +
 
4198
                                   file.getAbsolutePath());
 
4199
      }
 
4200
    }
 
4201
  }
 
4202
 
 
4203
 
 
4204
  public byte[] loadBytes(String filename) {
 
4205
    InputStream is = createInput(filename);
 
4206
    if (is != null) return loadBytes(is);
 
4207
 
 
4208
    System.err.println("The file \"" + filename + "\" " +
 
4209
                       "is missing or inaccessible, make sure " +
 
4210
                       "the URL is valid or that the file has been " +
 
4211
                       "added to your sketch and is readable.");
 
4212
    return null;
 
4213
  }
 
4214
 
 
4215
 
 
4216
  static public byte[] loadBytes(InputStream input) {
 
4217
    try {
 
4218
      BufferedInputStream bis = new BufferedInputStream(input);
 
4219
      ByteArrayOutputStream out = new ByteArrayOutputStream();
 
4220
 
 
4221
      int c = bis.read();
 
4222
      while (c != -1) {
 
4223
        out.write(c);
 
4224
        c = bis.read();
 
4225
      }
 
4226
      return out.toByteArray();
 
4227
 
 
4228
    } catch (IOException e) {
 
4229
      e.printStackTrace();
 
4230
      //throw new RuntimeException("Couldn't load bytes from stream");
 
4231
    }
 
4232
    return null;
 
4233
  }
 
4234
 
 
4235
 
 
4236
  static public byte[] loadBytes(File file) {
 
4237
    InputStream is = createInput(file);
 
4238
    return loadBytes(is);
 
4239
  }
 
4240
 
 
4241
 
 
4242
  static public String[] loadStrings(File file) {
 
4243
    InputStream is = createInput(file);
 
4244
    if (is != null) return loadStrings(is);
 
4245
    return null;
 
4246
  }
 
4247
 
 
4248
 
 
4249
  /**
 
4250
   * Load data from a file and shove it into a String array.
 
4251
   * <P>
 
4252
   * Exceptions are handled internally, when an error, occurs, an
 
4253
   * exception is printed to the console and 'null' is returned,
 
4254
   * but the program continues running. This is a tradeoff between
 
4255
   * 1) showing the user that there was a problem but 2) not requiring
 
4256
   * that all i/o code is contained in try/catch blocks, for the sake
 
4257
   * of new users (or people who are just trying to get things done
 
4258
   * in a "scripting" fashion. If you want to handle exceptions,
 
4259
   * use Java methods for I/O.
 
4260
   */
 
4261
  public String[] loadStrings(String filename) {
 
4262
    InputStream is = createInput(filename);
 
4263
    if (is != null) return loadStrings(is);
 
4264
 
 
4265
    System.err.println("The file \"" + filename + "\" " +
 
4266
                       "is missing or inaccessible, make sure " +
 
4267
                       "the URL is valid or that the file has been " +
 
4268
                       "added to your sketch and is readable.");
 
4269
    return null;
 
4270
  }
 
4271
 
 
4272
 
 
4273
  static public String[] loadStrings(InputStream input) {
 
4274
    try {
 
4275
      BufferedReader reader =
 
4276
        new BufferedReader(new InputStreamReader(input, "UTF-8"));
 
4277
 
 
4278
      String lines[] = new String[100];
 
4279
      int lineCount = 0;
 
4280
      String line = null;
 
4281
      while ((line = reader.readLine()) != null) {
 
4282
        if (lineCount == lines.length) {
 
4283
          String temp[] = new String[lineCount << 1];
 
4284
          System.arraycopy(lines, 0, temp, 0, lineCount);
 
4285
          lines = temp;
 
4286
        }
 
4287
        lines[lineCount++] = line;
 
4288
      }
 
4289
      reader.close();
 
4290
 
 
4291
      if (lineCount == lines.length) {
 
4292
        return lines;
 
4293
      }
 
4294
 
 
4295
      // resize array to appropriate amount for these lines
 
4296
      String output[] = new String[lineCount];
 
4297
      System.arraycopy(lines, 0, output, 0, lineCount);
 
4298
      return output;
 
4299
 
 
4300
    } catch (IOException e) {
 
4301
      e.printStackTrace();
 
4302
      //throw new RuntimeException("Error inside loadStrings()");
 
4303
    }
 
4304
    return null;
 
4305
  }
 
4306
 
 
4307
 
 
4308
 
 
4309
  //////////////////////////////////////////////////////////////
 
4310
 
 
4311
  // FILE OUTPUT
 
4312
 
 
4313
 
 
4314
  /**
 
4315
   * Similar to createInput() (formerly openStream), this creates a Java
 
4316
   * OutputStream for a given filename or path. The file will be created in
 
4317
   * the sketch folder, or in the same folder as an exported application.
 
4318
   * <p/>
 
4319
   * If the path does not exist, intermediate folders will be created. If an
 
4320
   * exception occurs, it will be printed to the console, and null will be
 
4321
   * returned.
 
4322
   * <p/>
 
4323
   * Future releases may also add support for handling HTTP POST via this
 
4324
   * method (for better symmetry with createInput), however that's maybe a
 
4325
   * little too clever (and then we'd have to add the same features to the
 
4326
   * other file functions like createWriter). Who you callin' bloated?
 
4327
   */
 
4328
  public OutputStream createOutput(String filename) {
 
4329
    return createOutput(saveFile(filename));
 
4330
  }
 
4331
 
 
4332
 
 
4333
  static public OutputStream createOutput(File file) {
 
4334
    try {
 
4335
      createPath(file);  // make sure the path exists
 
4336
      FileOutputStream fos = new FileOutputStream(file);
 
4337
      if (file.getName().toLowerCase().endsWith(".gz")) {
 
4338
        return new GZIPOutputStream(fos);
 
4339
      }
 
4340
      return fos;
 
4341
 
 
4342
    } catch (IOException e) {
 
4343
      e.printStackTrace();
 
4344
    }
 
4345
    return null;
 
4346
  }
 
4347
 
 
4348
 
 
4349
  /**
 
4350
   * Save the contents of a stream to a file in the sketch folder.
 
4351
   * This is basically saveBytes(blah, loadBytes()), but done
 
4352
   * more efficiently (and with less confusing syntax).
 
4353
   */
 
4354
  public void saveStream(String targetFilename, String sourceLocation) {
 
4355
    saveStream(saveFile(targetFilename), sourceLocation);
 
4356
  }
 
4357
 
 
4358
 
 
4359
  /**
 
4360
   * Identical to the other saveStream(), but writes to a File
 
4361
   * object, for greater control over the file location.
 
4362
   * Note that unlike other api methods, this will not automatically
 
4363
   * compress or uncompress gzip files.
 
4364
   */
 
4365
  public void saveStream(File targetFile, String sourceLocation) {
 
4366
    saveStream(targetFile, createInputRaw(sourceLocation));
 
4367
  }
 
4368
 
 
4369
 
 
4370
  static public void saveStream(File targetFile, InputStream sourceStream) {
 
4371
    File tempFile = null;
 
4372
    try {
 
4373
      File parentDir = targetFile.getParentFile();
 
4374
      tempFile = File.createTempFile(targetFile.getName(), null, parentDir);
 
4375
 
 
4376
      BufferedInputStream bis = new BufferedInputStream(sourceStream, 16384);
 
4377
      FileOutputStream fos = new FileOutputStream(tempFile);
 
4378
      BufferedOutputStream bos = new BufferedOutputStream(fos);
 
4379
 
 
4380
      byte[] buffer = new byte[8192];
 
4381
      int bytesRead;
 
4382
      while ((bytesRead = bis.read(buffer)) != -1) {
 
4383
        bos.write(buffer, 0, bytesRead);
 
4384
      }
 
4385
 
 
4386
      bos.flush();
 
4387
      bos.close();
 
4388
      bos = null;
 
4389
 
 
4390
      if (!tempFile.renameTo(targetFile)) {
 
4391
        System.err.println("Could not rename temporary file " +
 
4392
                           tempFile.getAbsolutePath());
 
4393
      }
 
4394
    } catch (IOException e) {
 
4395
      if (tempFile != null) {
 
4396
        tempFile.delete();
 
4397
      }
 
4398
      e.printStackTrace();
 
4399
    }
 
4400
  }
 
4401
 
 
4402
 
 
4403
  /**
 
4404
   * Saves bytes to a file to inside the sketch folder.
 
4405
   * The filename can be a relative path, i.e. "poo/bytefun.txt"
 
4406
   * would save to a file named "bytefun.txt" to a subfolder
 
4407
   * called 'poo' inside the sketch folder. If the in-between
 
4408
   * subfolders don't exist, they'll be created.
 
4409
   */
 
4410
  public void saveBytes(String filename, byte buffer[]) {
 
4411
    saveBytes(saveFile(filename), buffer);
 
4412
  }
 
4413
 
 
4414
 
 
4415
  /**
 
4416
   * Saves bytes to a specific File location specified by the user.
 
4417
   */
 
4418
  static public void saveBytes(File file, byte buffer[]) {
 
4419
    File tempFile = null;
 
4420
    try {
 
4421
      File parentDir = file.getParentFile();
 
4422
      tempFile = File.createTempFile(file.getName(), null, parentDir);
 
4423
 
 
4424
      /*
 
4425
      String filename = file.getAbsolutePath();
 
4426
      createPath(filename);
 
4427
      OutputStream output = new FileOutputStream(file);
 
4428
      if (file.getName().toLowerCase().endsWith(".gz")) {
 
4429
        output = new GZIPOutputStream(output);
 
4430
      }
 
4431
      */
 
4432
      OutputStream output = createOutput(tempFile);
 
4433
      saveBytes(output, buffer);
 
4434
      output.close();
 
4435
      output = null;
 
4436
 
 
4437
      if (!tempFile.renameTo(file)) {
 
4438
        System.err.println("Could not rename temporary file " +
 
4439
                           tempFile.getAbsolutePath());
 
4440
      }
 
4441
 
 
4442
    } catch (IOException e) {
 
4443
      System.err.println("error saving bytes to " + file);
 
4444
      if (tempFile != null) {
 
4445
        tempFile.delete();
 
4446
      }
 
4447
      e.printStackTrace();
 
4448
    }
 
4449
  }
 
4450
 
 
4451
 
 
4452
  /**
 
4453
   * Spews a buffer of bytes to an OutputStream.
 
4454
   */
 
4455
  static public void saveBytes(OutputStream output, byte buffer[]) {
 
4456
    try {
 
4457
      output.write(buffer);
 
4458
      output.flush();
 
4459
 
 
4460
    } catch (IOException e) {
 
4461
      e.printStackTrace();
 
4462
    }
 
4463
  }
 
4464
 
 
4465
  //
 
4466
 
 
4467
  public void saveStrings(String filename, String strings[]) {
 
4468
    saveStrings(saveFile(filename), strings);
 
4469
  }
 
4470
 
 
4471
 
 
4472
  static public void saveStrings(File file, String strings[]) {
 
4473
    saveStrings(createOutput(file), strings);
 
4474
    /*
 
4475
    try {
 
4476
      String location = file.getAbsolutePath();
 
4477
      createPath(location);
 
4478
      OutputStream output = new FileOutputStream(location);
 
4479
      if (file.getName().toLowerCase().endsWith(".gz")) {
 
4480
        output = new GZIPOutputStream(output);
 
4481
      }
 
4482
      saveStrings(output, strings);
 
4483
      output.close();
 
4484
 
 
4485
    } catch (IOException e) {
 
4486
      e.printStackTrace();
 
4487
    }
 
4488
    */
 
4489
  }
 
4490
 
 
4491
 
 
4492
  static public void saveStrings(OutputStream output, String strings[]) {
 
4493
    PrintWriter writer = createWriter(output);
 
4494
      for (int i = 0; i < strings.length; i++) {
 
4495
        writer.println(strings[i]);
 
4496
      }
 
4497
      writer.flush();
 
4498
    writer.close();
 
4499
  }
 
4500
 
 
4501
 
 
4502
  //////////////////////////////////////////////////////////////
 
4503
 
 
4504
 
 
4505
  /**
 
4506
   * Prepend the sketch folder path to the filename (or path) that is
 
4507
   * passed in. External libraries should use this function to save to
 
4508
   * the sketch folder.
 
4509
   * <p/>
 
4510
   * Note that when running as an applet inside a web browser,
 
4511
   * the sketchPath will be set to null, because security restrictions
 
4512
   * prevent applets from accessing that information.
 
4513
   * <p/>
 
4514
   * This will also cause an error if the sketch is not inited properly,
 
4515
   * meaning that init() was never called on the PApplet when hosted
 
4516
   * my some other main() or by other code. For proper use of init(),
 
4517
   * see the examples in the main description text for PApplet.
 
4518
   */
 
4519
  public String sketchPath(String where) {
 
4520
    if (sketchPath == null) {
 
4521
      return where;
 
4522
//      throw new RuntimeException("The applet was not inited properly, " +
 
4523
//                                 "or security restrictions prevented " +
 
4524
//                                 "it from determining its path.");
 
4525
    }
 
4526
    // isAbsolute() could throw an access exception, but so will writing
 
4527
    // to the local disk using the sketch path, so this is safe here.
 
4528
    // for 0120, added a try/catch anyways.
 
4529
    try {
 
4530
      if (new File(where).isAbsolute()) return where;
 
4531
    } catch (Exception e) { }
 
4532
 
 
4533
    return sketchPath + File.separator + where;
 
4534
  }
 
4535
 
 
4536
 
 
4537
  public File sketchFile(String where) {
 
4538
    return new File(sketchPath(where));
 
4539
  }
 
4540
 
 
4541
 
 
4542
  /**
 
4543
   * Returns a path inside the applet folder to save to. Like sketchPath(),
 
4544
   * but creates any in-between folders so that things save properly.
 
4545
   * <p/>
 
4546
   * All saveXxxx() functions use the path to the sketch folder, rather than
 
4547
   * its data folder. Once exported, the data folder will be found inside the
 
4548
   * jar file of the exported application or applet. In this case, it's not
 
4549
   * possible to save data into the jar file, because it will often be running
 
4550
   * from a server, or marked in-use if running from a local file system.
 
4551
   * With this in mind, saving to the data path doesn't make sense anyway.
 
4552
   * If you know you're running locally, and want to save to the data folder,
 
4553
   * use <TT>saveXxxx("data/blah.dat")</TT>.
 
4554
   */
 
4555
  public String savePath(String where) {
 
4556
    if (where == null) return null;
 
4557
    String filename = sketchPath(where);
 
4558
    createPath(filename);
 
4559
    return filename;
 
4560
  }
 
4561
 
 
4562
 
 
4563
  /**
 
4564
   * Identical to savePath(), but returns a File object.
 
4565
   */
 
4566
  public File saveFile(String where) {
 
4567
    return new File(savePath(where));
 
4568
  }
 
4569
 
 
4570
 
 
4571
  /**
 
4572
   * Return a full path to an item in the data folder.
 
4573
   * <p>
 
4574
   * In this method, the data path is defined not as the applet's actual
 
4575
   * data path, but a folder titled "data" in the sketch's working
 
4576
   * directory. When running inside the PDE, this will be the sketch's
 
4577
   * "data" folder. However, when exported (as application or applet),
 
4578
   * sketch's data folder is exported as part of the applications jar file,
 
4579
   * and it's not possible to read/write from the jar file in a generic way.
 
4580
   * If you need to read data from the jar file, you should use other methods
 
4581
   * such as createInput(), createReader(), or loadStrings().
 
4582
   */
 
4583
  public String dataPath(String where) {
 
4584
    // isAbsolute() could throw an access exception, but so will writing
 
4585
    // to the local disk using the sketch path, so this is safe here.
 
4586
    if (new File(where).isAbsolute()) return where;
 
4587
 
 
4588
    return sketchPath + File.separator + "data" + File.separator + where;
 
4589
  }
 
4590
 
 
4591
 
 
4592
  /**
 
4593
   * Return a full path to an item in the data folder as a File object.
 
4594
   * See the dataPath() method for more information.
 
4595
   */
 
4596
  public File dataFile(String where) {
 
4597
    return new File(dataPath(where));
 
4598
  }
 
4599
 
 
4600
 
 
4601
  /**
 
4602
   * Takes a path and creates any in-between folders if they don't
 
4603
   * already exist. Useful when trying to save to a subfolder that
 
4604
   * may not actually exist.
 
4605
   */
 
4606
  static public void createPath(String path) {
 
4607
    createPath(new File(path));
 
4608
  }
 
4609
 
 
4610
 
 
4611
  static public void createPath(File file) {
 
4612
    try {
 
4613
      String parent = file.getParent();
 
4614
      if (parent != null) {
 
4615
        File unit = new File(parent);
 
4616
        if (!unit.exists()) unit.mkdirs();
 
4617
      }
 
4618
    } catch (SecurityException se) {
 
4619
      System.err.println("You don't have permissions to create " +
 
4620
                         file.getAbsolutePath());
 
4621
    }
 
4622
  }
 
4623
 
 
4624
 
 
4625
 
 
4626
  //////////////////////////////////////////////////////////////
 
4627
 
 
4628
  // SORT
 
4629
 
 
4630
 
 
4631
  static public byte[] sort(byte what[]) {
 
4632
    return sort(what, what.length);
 
4633
  }
 
4634
 
 
4635
 
 
4636
  static public byte[] sort(byte[] what, int count) {
 
4637
    byte[] outgoing = new byte[what.length];
 
4638
    System.arraycopy(what, 0, outgoing, 0, what.length);
 
4639
    Arrays.sort(outgoing, 0, count);
 
4640
    return outgoing;
 
4641
  }
 
4642
 
 
4643
 
 
4644
  static public char[] sort(char what[]) {
 
4645
    return sort(what, what.length);
 
4646
  }
 
4647
 
 
4648
 
 
4649
  static public char[] sort(char[] what, int count) {
 
4650
    char[] outgoing = new char[what.length];
 
4651
    System.arraycopy(what, 0, outgoing, 0, what.length);
 
4652
    Arrays.sort(outgoing, 0, count);
 
4653
    return outgoing;
 
4654
  }
 
4655
 
 
4656
 
 
4657
  static public int[] sort(int what[]) {
 
4658
    return sort(what, what.length);
 
4659
  }
 
4660
 
 
4661
 
 
4662
  static public int[] sort(int[] what, int count) {
 
4663
    int[] outgoing = new int[what.length];
 
4664
    System.arraycopy(what, 0, outgoing, 0, what.length);
 
4665
    Arrays.sort(outgoing, 0, count);
 
4666
    return outgoing;
 
4667
  }
 
4668
 
 
4669
 
 
4670
  static public float[] sort(float what[]) {
 
4671
    return sort(what, what.length);
 
4672
  }
 
4673
 
 
4674
 
 
4675
  static public float[] sort(float[] what, int count) {
 
4676
    float[] outgoing = new float[what.length];
 
4677
    System.arraycopy(what, 0, outgoing, 0, what.length);
 
4678
    Arrays.sort(outgoing, 0, count);
 
4679
    return outgoing;
 
4680
  }
 
4681
 
 
4682
 
 
4683
  static public String[] sort(String what[]) {
 
4684
    return sort(what, what.length);
 
4685
  }
 
4686
 
 
4687
 
 
4688
  static public String[] sort(String[] what, int count) {
 
4689
    String[] outgoing = new String[what.length];
 
4690
    System.arraycopy(what, 0, outgoing, 0, what.length);
 
4691
    Arrays.sort(outgoing, 0, count);
 
4692
    return outgoing;
 
4693
  }
 
4694
 
 
4695
 
 
4696
 
 
4697
  //////////////////////////////////////////////////////////////
 
4698
 
 
4699
  // ARRAY UTILITIES
 
4700
 
 
4701
 
 
4702
  /**
 
4703
   * Calls System.arraycopy(), included here so that we can
 
4704
   * avoid people needing to learn about the System object
 
4705
   * before they can just copy an array.
 
4706
   */
 
4707
  static public void arrayCopy(Object src, int srcPosition,
 
4708
                               Object dst, int dstPosition,
 
4709
                               int length) {
 
4710
    System.arraycopy(src, srcPosition, dst, dstPosition, length);
 
4711
  }
 
4712
 
 
4713
 
 
4714
  /**
 
4715
   * Convenience method for arraycopy().
 
4716
   * Identical to <CODE>arraycopy(src, 0, dst, 0, length);</CODE>
 
4717
   */
 
4718
  static public void arrayCopy(Object src, Object dst, int length) {
 
4719
    System.arraycopy(src, 0, dst, 0, length);
 
4720
  }
 
4721
 
 
4722
 
 
4723
  /**
 
4724
   * Shortcut to copy the entire contents of
 
4725
   * the source into the destination array.
 
4726
   * Identical to <CODE>arraycopy(src, 0, dst, 0, src.length);</CODE>
 
4727
   */
 
4728
  static public void arrayCopy(Object src, Object dst) {
 
4729
    System.arraycopy(src, 0, dst, 0, Array.getLength(src));
 
4730
  }
 
4731
 
 
4732
  //
 
4733
 
 
4734
  /**
 
4735
   * @deprecated Use arrayCopy() instead.
 
4736
   */
 
4737
  static public void arraycopy(Object src, int srcPosition,
 
4738
                               Object dst, int dstPosition,
 
4739
                               int length) {
 
4740
    System.arraycopy(src, srcPosition, dst, dstPosition, length);
 
4741
  }
 
4742
 
 
4743
  /**
 
4744
   * @deprecated Use arrayCopy() instead.
 
4745
   */
 
4746
  static public void arraycopy(Object src, Object dst, int length) {
 
4747
    System.arraycopy(src, 0, dst, 0, length);
 
4748
  }
 
4749
 
 
4750
  /**
 
4751
   * @deprecated Use arrayCopy() instead.
 
4752
   */
 
4753
  static public void arraycopy(Object src, Object dst) {
 
4754
    System.arraycopy(src, 0, dst, 0, Array.getLength(src));
 
4755
  }
 
4756
 
 
4757
  //
 
4758
 
 
4759
  static public boolean[] expand(boolean list[]) {
 
4760
    return expand(list, list.length << 1);
 
4761
  }
 
4762
 
 
4763
  static public boolean[] expand(boolean list[], int newSize) {
 
4764
    boolean temp[] = new boolean[newSize];
 
4765
    System.arraycopy(list, 0, temp, 0, Math.min(newSize, list.length));
 
4766
    return temp;
 
4767
  }
 
4768
 
 
4769
 
 
4770
  static public byte[] expand(byte list[]) {
 
4771
    return expand(list, list.length << 1);
 
4772
  }
 
4773
 
 
4774
  static public byte[] expand(byte list[], int newSize) {
 
4775
    byte temp[] = new byte[newSize];
 
4776
    System.arraycopy(list, 0, temp, 0, Math.min(newSize, list.length));
 
4777
    return temp;
 
4778
  }
 
4779
 
 
4780
 
 
4781
  static public char[] expand(char list[]) {
 
4782
    return expand(list, list.length << 1);
 
4783
  }
 
4784
 
 
4785
  static public char[] expand(char list[], int newSize) {
 
4786
    char temp[] = new char[newSize];
 
4787
    System.arraycopy(list, 0, temp, 0, Math.min(newSize, list.length));
 
4788
    return temp;
 
4789
  }
 
4790
 
 
4791
 
 
4792
  static public int[] expand(int list[]) {
 
4793
    return expand(list, list.length << 1);
 
4794
  }
 
4795
 
 
4796
  static public int[] expand(int list[], int newSize) {
 
4797
    int temp[] = new int[newSize];
 
4798
    System.arraycopy(list, 0, temp, 0, Math.min(newSize, list.length));
 
4799
    return temp;
 
4800
  }
 
4801
 
 
4802
 
 
4803
  static public float[] expand(float list[]) {
 
4804
    return expand(list, list.length << 1);
 
4805
  }
 
4806
 
 
4807
  static public float[] expand(float list[], int newSize) {
 
4808
    float temp[] = new float[newSize];
 
4809
    System.arraycopy(list, 0, temp, 0, Math.min(newSize, list.length));
 
4810
    return temp;
 
4811
  }
 
4812
 
 
4813
 
 
4814
  static public String[] expand(String list[]) {
 
4815
    return expand(list, list.length << 1);
 
4816
  }
 
4817
 
 
4818
  static public String[] expand(String list[], int newSize) {
 
4819
    String temp[] = new String[newSize];
 
4820
    // in case the new size is smaller than list.length
 
4821
    System.arraycopy(list, 0, temp, 0, Math.min(newSize, list.length));
 
4822
    return temp;
 
4823
  }
 
4824
 
 
4825
 
 
4826
  static public Object expand(Object array) {
 
4827
    return expand(array, Array.getLength(array) << 1);
 
4828
  }
 
4829
 
 
4830
  static public Object expand(Object list, int newSize) {
 
4831
    Class<?> type = list.getClass().getComponentType();
 
4832
    Object temp = Array.newInstance(type, newSize);
 
4833
    System.arraycopy(list, 0, temp, 0,
 
4834
                     Math.min(Array.getLength(list), newSize));
 
4835
    return temp;
 
4836
  }
 
4837
 
 
4838
  //
 
4839
 
 
4840
  // contract() has been removed in revision 0124, use subset() instead.
 
4841
  // (expand() is also functionally equivalent)
 
4842
 
 
4843
  //
 
4844
 
 
4845
  static public byte[] append(byte b[], byte value) {
 
4846
    b = expand(b, b.length + 1);
 
4847
    b[b.length-1] = value;
 
4848
    return b;
 
4849
  }
 
4850
 
 
4851
  static public char[] append(char b[], char value) {
 
4852
    b = expand(b, b.length + 1);
 
4853
    b[b.length-1] = value;
 
4854
    return b;
 
4855
  }
 
4856
 
 
4857
  static public int[] append(int b[], int value) {
 
4858
    b = expand(b, b.length + 1);
 
4859
    b[b.length-1] = value;
 
4860
    return b;
 
4861
  }
 
4862
 
 
4863
  static public float[] append(float b[], float value) {
 
4864
    b = expand(b, b.length + 1);
 
4865
    b[b.length-1] = value;
 
4866
    return b;
 
4867
  }
 
4868
 
 
4869
  static public String[] append(String b[], String value) {
 
4870
    b = expand(b, b.length + 1);
 
4871
    b[b.length-1] = value;
 
4872
    return b;
 
4873
  }
 
4874
 
 
4875
  static public Object append(Object b, Object value) {
 
4876
    int length = Array.getLength(b);
 
4877
    b = expand(b, length + 1);
 
4878
    Array.set(b, length, value);
 
4879
    return b;
 
4880
  }
 
4881
 
 
4882
  //
 
4883
 
 
4884
  static public boolean[] shorten(boolean list[]) {
 
4885
    return subset(list, 0, list.length-1);
 
4886
  }
 
4887
 
 
4888
  static public byte[] shorten(byte list[]) {
 
4889
    return subset(list, 0, list.length-1);
 
4890
  }
 
4891
 
 
4892
  static public char[] shorten(char list[]) {
 
4893
    return subset(list, 0, list.length-1);
 
4894
  }
 
4895
 
 
4896
  static public int[] shorten(int list[]) {
 
4897
    return subset(list, 0, list.length-1);
 
4898
  }
 
4899
 
 
4900
  static public float[] shorten(float list[]) {
 
4901
    return subset(list, 0, list.length-1);
 
4902
  }
 
4903
 
 
4904
  static public String[] shorten(String list[]) {
 
4905
    return subset(list, 0, list.length-1);
 
4906
  }
 
4907
 
 
4908
  static public Object shorten(Object list) {
 
4909
    int length = Array.getLength(list);
 
4910
    return subset(list, 0, length - 1);
 
4911
  }
 
4912
 
 
4913
  //
 
4914
 
 
4915
  static final public boolean[] splice(boolean list[],
 
4916
                                       boolean v, int index) {
 
4917
    boolean outgoing[] = new boolean[list.length + 1];
 
4918
    System.arraycopy(list, 0, outgoing, 0, index);
 
4919
    outgoing[index] = v;
 
4920
    System.arraycopy(list, index, outgoing, index + 1,
 
4921
                     list.length - index);
 
4922
    return outgoing;
 
4923
  }
 
4924
 
 
4925
  static final public boolean[] splice(boolean list[],
 
4926
                                       boolean v[], int index) {
 
4927
    boolean outgoing[] = new boolean[list.length + v.length];
 
4928
    System.arraycopy(list, 0, outgoing, 0, index);
 
4929
    System.arraycopy(v, 0, outgoing, index, v.length);
 
4930
    System.arraycopy(list, index, outgoing, index + v.length,
 
4931
                     list.length - index);
 
4932
    return outgoing;
 
4933
  }
 
4934
 
 
4935
 
 
4936
  static final public byte[] splice(byte list[],
 
4937
                                    byte v, int index) {
 
4938
    byte outgoing[] = new byte[list.length + 1];
 
4939
    System.arraycopy(list, 0, outgoing, 0, index);
 
4940
    outgoing[index] = v;
 
4941
    System.arraycopy(list, index, outgoing, index + 1,
 
4942
                     list.length - index);
 
4943
    return outgoing;
 
4944
  }
 
4945
 
 
4946
  static final public byte[] splice(byte list[],
 
4947
                                    byte v[], int index) {
 
4948
    byte outgoing[] = new byte[list.length + v.length];
 
4949
    System.arraycopy(list, 0, outgoing, 0, index);
 
4950
    System.arraycopy(v, 0, outgoing, index, v.length);
 
4951
    System.arraycopy(list, index, outgoing, index + v.length,
 
4952
                     list.length - index);
 
4953
    return outgoing;
 
4954
  }
 
4955
 
 
4956
 
 
4957
  static final public char[] splice(char list[],
 
4958
                                    char v, int index) {
 
4959
    char outgoing[] = new char[list.length + 1];
 
4960
    System.arraycopy(list, 0, outgoing, 0, index);
 
4961
    outgoing[index] = v;
 
4962
    System.arraycopy(list, index, outgoing, index + 1,
 
4963
                     list.length - index);
 
4964
    return outgoing;
 
4965
  }
 
4966
 
 
4967
  static final public char[] splice(char list[],
 
4968
                                    char v[], int index) {
 
4969
    char outgoing[] = new char[list.length + v.length];
 
4970
    System.arraycopy(list, 0, outgoing, 0, index);
 
4971
    System.arraycopy(v, 0, outgoing, index, v.length);
 
4972
    System.arraycopy(list, index, outgoing, index + v.length,
 
4973
                     list.length - index);
 
4974
    return outgoing;
 
4975
  }
 
4976
 
 
4977
 
 
4978
  static final public int[] splice(int list[],
 
4979
                                   int v, int index) {
 
4980
    int outgoing[] = new int[list.length + 1];
 
4981
    System.arraycopy(list, 0, outgoing, 0, index);
 
4982
    outgoing[index] = v;
 
4983
    System.arraycopy(list, index, outgoing, index + 1,
 
4984
                     list.length - index);
 
4985
    return outgoing;
 
4986
  }
 
4987
 
 
4988
  static final public int[] splice(int list[],
 
4989
                                   int v[], int index) {
 
4990
    int outgoing[] = new int[list.length + v.length];
 
4991
    System.arraycopy(list, 0, outgoing, 0, index);
 
4992
    System.arraycopy(v, 0, outgoing, index, v.length);
 
4993
    System.arraycopy(list, index, outgoing, index + v.length,
 
4994
                     list.length - index);
 
4995
    return outgoing;
 
4996
  }
 
4997
 
 
4998
 
 
4999
  static final public float[] splice(float list[],
 
5000
                                     float v, int index) {
 
5001
    float outgoing[] = new float[list.length + 1];
 
5002
    System.arraycopy(list, 0, outgoing, 0, index);
 
5003
    outgoing[index] = v;
 
5004
    System.arraycopy(list, index, outgoing, index + 1,
 
5005
                     list.length - index);
 
5006
    return outgoing;
 
5007
  }
 
5008
 
 
5009
  static final public float[] splice(float list[],
 
5010
                                     float v[], int index) {
 
5011
    float outgoing[] = new float[list.length + v.length];
 
5012
    System.arraycopy(list, 0, outgoing, 0, index);
 
5013
    System.arraycopy(v, 0, outgoing, index, v.length);
 
5014
    System.arraycopy(list, index, outgoing, index + v.length,
 
5015
                     list.length - index);
 
5016
    return outgoing;
 
5017
  }
 
5018
 
 
5019
 
 
5020
  static final public String[] splice(String list[],
 
5021
                                      String v, int index) {
 
5022
    String outgoing[] = new String[list.length + 1];
 
5023
    System.arraycopy(list, 0, outgoing, 0, index);
 
5024
    outgoing[index] = v;
 
5025
    System.arraycopy(list, index, outgoing, index + 1,
 
5026
                     list.length - index);
 
5027
    return outgoing;
 
5028
  }
 
5029
 
 
5030
  static final public String[] splice(String list[],
 
5031
                                      String v[], int index) {
 
5032
    String outgoing[] = new String[list.length + v.length];
 
5033
    System.arraycopy(list, 0, outgoing, 0, index);
 
5034
    System.arraycopy(v, 0, outgoing, index, v.length);
 
5035
    System.arraycopy(list, index, outgoing, index + v.length,
 
5036
                     list.length - index);
 
5037
    return outgoing;
 
5038
  }
 
5039
 
 
5040
 
 
5041
  static final public Object splice(Object list, Object v, int index) {
 
5042
    Object[] outgoing = null;
 
5043
    int length = Array.getLength(list);
 
5044
 
 
5045
    // check whether item being spliced in is an array
 
5046
    if (v.getClass().getName().charAt(0) == '[') {
 
5047
      int vlength = Array.getLength(v);
 
5048
      outgoing = new Object[length + vlength];
 
5049
      System.arraycopy(list, 0, outgoing, 0, index);
 
5050
      System.arraycopy(v, 0, outgoing, index, vlength);
 
5051
      System.arraycopy(list, index, outgoing, index + vlength, length - index);
 
5052
 
 
5053
    } else {
 
5054
      outgoing = new Object[length + 1];
 
5055
      System.arraycopy(list, 0, outgoing, 0, index);
 
5056
      Array.set(outgoing, index, v);
 
5057
      System.arraycopy(list, index, outgoing, index + 1, length - index);
 
5058
    }
 
5059
    return outgoing;
 
5060
  }
 
5061
 
 
5062
  //
 
5063
 
 
5064
  static public boolean[] subset(boolean list[], int start) {
 
5065
    return subset(list, start, list.length - start);
 
5066
  }
 
5067
 
 
5068
  static public boolean[] subset(boolean list[], int start, int count) {
 
5069
    boolean output[] = new boolean[count];
 
5070
    System.arraycopy(list, start, output, 0, count);
 
5071
    return output;
 
5072
  }
 
5073
 
 
5074
 
 
5075
  static public byte[] subset(byte list[], int start) {
 
5076
    return subset(list, start, list.length - start);
 
5077
  }
 
5078
 
 
5079
  static public byte[] subset(byte list[], int start, int count) {
 
5080
    byte output[] = new byte[count];
 
5081
    System.arraycopy(list, start, output, 0, count);
 
5082
    return output;
 
5083
  }
 
5084
 
 
5085
 
 
5086
  static public char[] subset(char list[], int start) {
 
5087
    return subset(list, start, list.length - start);
 
5088
  }
 
5089
 
 
5090
  static public char[] subset(char list[], int start, int count) {
 
5091
    char output[] = new char[count];
 
5092
    System.arraycopy(list, start, output, 0, count);
 
5093
    return output;
 
5094
  }
 
5095
 
 
5096
 
 
5097
  static public int[] subset(int list[], int start) {
 
5098
    return subset(list, start, list.length - start);
 
5099
  }
 
5100
 
 
5101
  static public int[] subset(int list[], int start, int count) {
 
5102
    int output[] = new int[count];
 
5103
    System.arraycopy(list, start, output, 0, count);
 
5104
    return output;
 
5105
  }
 
5106
 
 
5107
 
 
5108
  static public float[] subset(float list[], int start) {
 
5109
    return subset(list, start, list.length - start);
 
5110
  }
 
5111
 
 
5112
  static public float[] subset(float list[], int start, int count) {
 
5113
    float output[] = new float[count];
 
5114
    System.arraycopy(list, start, output, 0, count);
 
5115
    return output;
 
5116
  }
 
5117
 
 
5118
 
 
5119
  static public String[] subset(String list[], int start) {
 
5120
    return subset(list, start, list.length - start);
 
5121
  }
 
5122
 
 
5123
  static public String[] subset(String list[], int start, int count) {
 
5124
    String output[] = new String[count];
 
5125
    System.arraycopy(list, start, output, 0, count);
 
5126
    return output;
 
5127
  }
 
5128
 
 
5129
 
 
5130
  static public Object subset(Object list, int start) {
 
5131
    int length = Array.getLength(list);
 
5132
    return subset(list, start, length - start);
 
5133
  }
 
5134
 
 
5135
  static public Object subset(Object list, int start, int count) {
 
5136
    Class<?> type = list.getClass().getComponentType();
 
5137
    Object outgoing = Array.newInstance(type, count);
 
5138
    System.arraycopy(list, start, outgoing, 0, count);
 
5139
    return outgoing;
 
5140
  }
 
5141
 
 
5142
  //
 
5143
 
 
5144
  static public boolean[] concat(boolean a[], boolean b[]) {
 
5145
    boolean c[] = new boolean[a.length + b.length];
 
5146
    System.arraycopy(a, 0, c, 0, a.length);
 
5147
    System.arraycopy(b, 0, c, a.length, b.length);
 
5148
    return c;
 
5149
  }
 
5150
 
 
5151
  static public byte[] concat(byte a[], byte b[]) {
 
5152
    byte c[] = new byte[a.length + b.length];
 
5153
    System.arraycopy(a, 0, c, 0, a.length);
 
5154
    System.arraycopy(b, 0, c, a.length, b.length);
 
5155
    return c;
 
5156
  }
 
5157
 
 
5158
  static public char[] concat(char a[], char b[]) {
 
5159
    char c[] = new char[a.length + b.length];
 
5160
    System.arraycopy(a, 0, c, 0, a.length);
 
5161
    System.arraycopy(b, 0, c, a.length, b.length);
 
5162
    return c;
 
5163
  }
 
5164
 
 
5165
  static public int[] concat(int a[], int b[]) {
 
5166
    int c[] = new int[a.length + b.length];
 
5167
    System.arraycopy(a, 0, c, 0, a.length);
 
5168
    System.arraycopy(b, 0, c, a.length, b.length);
 
5169
    return c;
 
5170
  }
 
5171
 
 
5172
  static public float[] concat(float a[], float b[]) {
 
5173
    float c[] = new float[a.length + b.length];
 
5174
    System.arraycopy(a, 0, c, 0, a.length);
 
5175
    System.arraycopy(b, 0, c, a.length, b.length);
 
5176
    return c;
 
5177
  }
 
5178
 
 
5179
  static public String[] concat(String a[], String b[]) {
 
5180
    String c[] = new String[a.length + b.length];
 
5181
    System.arraycopy(a, 0, c, 0, a.length);
 
5182
    System.arraycopy(b, 0, c, a.length, b.length);
 
5183
    return c;
 
5184
  }
 
5185
 
 
5186
  static public Object concat(Object a, Object b) {
 
5187
    Class<?> type = a.getClass().getComponentType();
 
5188
    int alength = Array.getLength(a);
 
5189
    int blength = Array.getLength(b);
 
5190
    Object outgoing = Array.newInstance(type, alength + blength);
 
5191
    System.arraycopy(a, 0, outgoing, 0, alength);
 
5192
    System.arraycopy(b, 0, outgoing, alength, blength);
 
5193
    return outgoing;
 
5194
  }
 
5195
 
 
5196
  //
 
5197
 
 
5198
  static public boolean[] reverse(boolean list[]) {
 
5199
    boolean outgoing[] = new boolean[list.length];
 
5200
    int length1 = list.length - 1;
 
5201
    for (int i = 0; i < list.length; i++) {
 
5202
      outgoing[i] = list[length1 - i];
 
5203
    }
 
5204
    return outgoing;
 
5205
  }
 
5206
 
 
5207
  static public byte[] reverse(byte list[]) {
 
5208
    byte outgoing[] = new byte[list.length];
 
5209
    int length1 = list.length - 1;
 
5210
    for (int i = 0; i < list.length; i++) {
 
5211
      outgoing[i] = list[length1 - i];
 
5212
    }
 
5213
    return outgoing;
 
5214
  }
 
5215
 
 
5216
  static public char[] reverse(char list[]) {
 
5217
    char outgoing[] = new char[list.length];
 
5218
    int length1 = list.length - 1;
 
5219
    for (int i = 0; i < list.length; i++) {
 
5220
      outgoing[i] = list[length1 - i];
 
5221
    }
 
5222
    return outgoing;
 
5223
  }
 
5224
 
 
5225
  static public int[] reverse(int list[]) {
 
5226
    int outgoing[] = new int[list.length];
 
5227
    int length1 = list.length - 1;
 
5228
    for (int i = 0; i < list.length; i++) {
 
5229
      outgoing[i] = list[length1 - i];
 
5230
    }
 
5231
    return outgoing;
 
5232
  }
 
5233
 
 
5234
  static public float[] reverse(float list[]) {
 
5235
    float outgoing[] = new float[list.length];
 
5236
    int length1 = list.length - 1;
 
5237
    for (int i = 0; i < list.length; i++) {
 
5238
      outgoing[i] = list[length1 - i];
 
5239
    }
 
5240
    return outgoing;
 
5241
  }
 
5242
 
 
5243
  static public String[] reverse(String list[]) {
 
5244
    String outgoing[] = new String[list.length];
 
5245
    int length1 = list.length - 1;
 
5246
    for (int i = 0; i < list.length; i++) {
 
5247
      outgoing[i] = list[length1 - i];
 
5248
    }
 
5249
    return outgoing;
 
5250
  }
 
5251
 
 
5252
  static public Object reverse(Object list) {
 
5253
    Class<?> type = list.getClass().getComponentType();
 
5254
    int length = Array.getLength(list);
 
5255
    Object outgoing = Array.newInstance(type, length);
 
5256
    for (int i = 0; i < length; i++) {
 
5257
      Array.set(outgoing, i, Array.get(list, (length - 1) - i));
 
5258
    }
 
5259
    return outgoing;
 
5260
  }
 
5261
 
 
5262
 
 
5263
 
 
5264
  //////////////////////////////////////////////////////////////
 
5265
 
 
5266
  // STRINGS
 
5267
 
 
5268
 
 
5269
  /**
 
5270
   * Remove whitespace characters from the beginning and ending
 
5271
   * of a String. Works like String.trim() but includes the
 
5272
   * unicode nbsp character as well.
 
5273
   */
 
5274
  static public String trim(String str) {
 
5275
    return str.replace('\u00A0', ' ').trim();
 
5276
  }
 
5277
 
 
5278
 
 
5279
  /**
 
5280
   * Trim the whitespace from a String array. This returns a new
 
5281
   * array and does not affect the passed-in array.
 
5282
   */
 
5283
  static public String[] trim(String[] array) {
 
5284
    String[] outgoing = new String[array.length];
 
5285
    for (int i = 0; i < array.length; i++) {
 
5286
      outgoing[i] = array[i].replace('\u00A0', ' ').trim();
 
5287
    }
 
5288
    return outgoing;
 
5289
  }
 
5290
 
 
5291
 
 
5292
  /**
 
5293
   * Join an array of Strings together as a single String,
 
5294
   * separated by the whatever's passed in for the separator.
 
5295
   */
 
5296
  static public String join(String str[], char separator) {
 
5297
    return join(str, String.valueOf(separator));
 
5298
  }
 
5299
 
 
5300
 
 
5301
  /**
 
5302
   * Join an array of Strings together as a single String,
 
5303
   * separated by the whatever's passed in for the separator.
 
5304
   * <P>
 
5305
   * To use this on numbers, first pass the array to nf() or nfs()
 
5306
   * to get a list of String objects, then use join on that.
 
5307
   * <PRE>
 
5308
   * e.g. String stuff[] = { "apple", "bear", "cat" };
 
5309
   *      String list = join(stuff, ", ");
 
5310
   *      // list is now "apple, bear, cat"</PRE>
 
5311
   */
 
5312
  static public String join(String str[], String separator) {
 
5313
    StringBuffer buffer = new StringBuffer();
 
5314
    for (int i = 0; i < str.length; i++) {
 
5315
      if (i != 0) buffer.append(separator);
 
5316
      buffer.append(str[i]);
 
5317
    }
 
5318
    return buffer.toString();
 
5319
  }
 
5320
 
 
5321
 
 
5322
  /**
 
5323
   * Split the provided String at wherever whitespace occurs.
 
5324
   * Multiple whitespace (extra spaces or tabs or whatever)
 
5325
   * between items will count as a single break.
 
5326
   * <P>
 
5327
   * The whitespace characters are "\t\n\r\f", which are the defaults
 
5328
   * for java.util.StringTokenizer, plus the unicode non-breaking space
 
5329
   * character, which is found commonly on files created by or used
 
5330
   * in conjunction with Mac OS X (character 160, or 0x00A0 in hex).
 
5331
   * <PRE>
 
5332
   * i.e. splitTokens("a b") -> { "a", "b" }
 
5333
   *      splitTokens("a    b") -> { "a", "b" }
 
5334
   *      splitTokens("a\tb") -> { "a", "b" }
 
5335
   *      splitTokens("a \t  b  ") -> { "a", "b" }</PRE>
 
5336
   */
 
5337
  static public String[] splitTokens(String what) {
 
5338
    return splitTokens(what, WHITESPACE);
 
5339
  }
 
5340
 
 
5341
 
 
5342
  /**
 
5343
   * Splits a string into pieces, using any of the chars in the
 
5344
   * String 'delim' as separator characters. For instance,
 
5345
   * in addition to white space, you might want to treat commas
 
5346
   * as a separator. The delimeter characters won't appear in
 
5347
   * the returned String array.
 
5348
   * <PRE>
 
5349
   * i.e. splitTokens("a, b", " ,") -> { "a", "b" }
 
5350
   * </PRE>
 
5351
   * To include all the whitespace possibilities, use the variable
 
5352
   * WHITESPACE, found in PConstants:
 
5353
   * <PRE>
 
5354
   * i.e. splitTokens("a   | b", WHITESPACE + "|");  ->  { "a", "b" }</PRE>
 
5355
   */
 
5356
  static public String[] splitTokens(String what, String delim) {
 
5357
    StringTokenizer toker = new StringTokenizer(what, delim);
 
5358
    String pieces[] = new String[toker.countTokens()];
 
5359
 
 
5360
    int index = 0;
 
5361
    while (toker.hasMoreTokens()) {
 
5362
      pieces[index++] = toker.nextToken();
 
5363
    }
 
5364
    return pieces;
 
5365
  }
 
5366
 
 
5367
 
 
5368
  /**
 
5369
   * Split a string into pieces along a specific character.
 
5370
   * Most commonly used to break up a String along a space or a tab
 
5371
   * character.
 
5372
   * <P>
 
5373
   * This operates differently than the others, where the
 
5374
   * single delimeter is the only breaking point, and consecutive
 
5375
   * delimeters will produce an empty string (""). This way,
 
5376
   * one can split on tab characters, but maintain the column
 
5377
   * alignments (of say an excel file) where there are empty columns.
 
5378
   */
 
5379
  static public String[] split(String what, char delim) {
 
5380
    // do this so that the exception occurs inside the user's
 
5381
    // program, rather than appearing to be a bug inside split()
 
5382
    if (what == null) return null;
 
5383
    //return split(what, String.valueOf(delim));  // huh
 
5384
 
 
5385
    char chars[] = what.toCharArray();
 
5386
    int splitCount = 0; //1;
 
5387
    for (int i = 0; i < chars.length; i++) {
 
5388
      if (chars[i] == delim) splitCount++;
 
5389
    }
 
5390
    // make sure that there is something in the input string
 
5391
    //if (chars.length > 0) {
 
5392
      // if the last char is a delimeter, get rid of it..
 
5393
      //if (chars[chars.length-1] == delim) splitCount--;
 
5394
      // on second thought, i don't agree with this, will disable
 
5395
    //}
 
5396
    if (splitCount == 0) {
 
5397
      String splits[] = new String[1];
 
5398
      splits[0] = new String(what);
 
5399
      return splits;
 
5400
    }
 
5401
    //int pieceCount = splitCount + 1;
 
5402
    String splits[] = new String[splitCount + 1];
 
5403
    int splitIndex = 0;
 
5404
    int startIndex = 0;
 
5405
    for (int i = 0; i < chars.length; i++) {
 
5406
      if (chars[i] == delim) {
 
5407
        splits[splitIndex++] =
 
5408
          new String(chars, startIndex, i-startIndex);
 
5409
        startIndex = i + 1;
 
5410
      }
 
5411
    }
 
5412
    //if (startIndex != chars.length) {
 
5413
      splits[splitIndex] =
 
5414
        new String(chars, startIndex, chars.length-startIndex);
 
5415
    //}
 
5416
    return splits;
 
5417
  }
 
5418
 
 
5419
 
 
5420
  /**
 
5421
   * Split a String on a specific delimiter. Unlike Java's String.split()
 
5422
   * method, this does not parse the delimiter as a regexp because it's more
 
5423
   * confusing than necessary, and String.split() is always available for
 
5424
   * those who want regexp.
 
5425
   */
 
5426
  static public String[] split(String what, String delim) {
 
5427
    ArrayList<String> items = new ArrayList<String>();
 
5428
    int index;
 
5429
    int offset = 0;
 
5430
    while ((index = what.indexOf(delim, offset)) != -1) {
 
5431
      items.add(what.substring(offset, index));
 
5432
      offset = index + delim.length();
 
5433
    }
 
5434
    items.add(what.substring(offset));
 
5435
    String[] outgoing = new String[items.size()];
 
5436
    items.toArray(outgoing);
 
5437
    return outgoing;
 
5438
  }
 
5439
 
 
5440
 
 
5441
  /**
 
5442
   * Match a string with a regular expression, and returns the match as an
 
5443
   * array. The first index is the matching expression, and array elements
 
5444
   * [1] and higher represent each of the groups (sequences found in parens).
 
5445
   *
 
5446
   * This uses multiline matching (Pattern.MULTILINE) and dotall mode
 
5447
   * (Pattern.DOTALL) by default, so that ^ and $ match the beginning and
 
5448
   * end of any lines found in the source, and the . operator will also
 
5449
   * pick up newline characters.
 
5450
   */
 
5451
  static public String[] match(String what, String regexp) {
 
5452
    Pattern p = Pattern.compile(regexp, Pattern.MULTILINE | Pattern.DOTALL);
 
5453
    Matcher m = p.matcher(what);
 
5454
    if (m.find()) {
 
5455
      int count = m.groupCount() + 1;
 
5456
      String[] groups = new String[count];
 
5457
      for (int i = 0; i < count; i++) {
 
5458
        groups[i] = m.group(i);
 
5459
      }
 
5460
      return groups;
 
5461
    }
 
5462
    return null;
 
5463
  }
 
5464
 
 
5465
 
 
5466
  /**
 
5467
   * Identical to match(), except that it returns an array of all matches in
 
5468
   * the specified String, rather than just the first.
 
5469
   */
 
5470
  static public String[][] matchAll(String what, String regexp) {
 
5471
    Pattern p = Pattern.compile(regexp, Pattern.MULTILINE | Pattern.DOTALL);
 
5472
    Matcher m = p.matcher(what);
 
5473
    ArrayList<String[]> results = new ArrayList<String[]>();
 
5474
    int count = m.groupCount() + 1;
 
5475
    while (m.find()) {
 
5476
      String[] groups = new String[count];
 
5477
      for (int i = 0; i < count; i++) {
 
5478
        groups[i] = m.group(i);
 
5479
      }
 
5480
      results.add(groups);
 
5481
    }
 
5482
    if (results.isEmpty()) {
 
5483
      return null;
 
5484
    }
 
5485
    String[][] matches = new String[results.size()][count];
 
5486
    for (int i = 0; i < matches.length; i++) {
 
5487
      matches[i] = (String[]) results.get(i);
 
5488
    }
 
5489
    return matches;
 
5490
  }
 
5491
 
 
5492
 
 
5493
 
 
5494
  //////////////////////////////////////////////////////////////
 
5495
 
 
5496
  // CASTING FUNCTIONS, INSERTED BY PREPROC
 
5497
 
 
5498
 
 
5499
  /**
 
5500
   * Convert a char to a boolean. 'T', 't', and '1' will become the
 
5501
   * boolean value true, while 'F', 'f', or '0' will become false.
 
5502
   */
 
5503
  /*
 
5504
  static final public boolean parseBoolean(char what) {
 
5505
    return ((what == 't') || (what == 'T') || (what == '1'));
 
5506
  }
 
5507
  */
 
5508
 
 
5509
  /**
 
5510
   * <p>Convert an integer to a boolean. Because of how Java handles upgrading
 
5511
   * numbers, this will also cover byte and char (as they will upgrade to
 
5512
   * an int without any sort of explicit cast).</p>
 
5513
   * <p>The preprocessor will convert boolean(what) to parseBoolean(what).</p>
 
5514
   * @return false if 0, true if any other number
 
5515
   */
 
5516
  static final public boolean parseBoolean(int what) {
 
5517
    return (what != 0);
 
5518
  }
 
5519
 
 
5520
  /*
 
5521
  // removed because this makes no useful sense
 
5522
  static final public boolean parseBoolean(float what) {
 
5523
    return (what != 0);
 
5524
  }
 
5525
  */
 
5526
 
 
5527
  /**
 
5528
   * Convert the string "true" or "false" to a boolean.
 
5529
   * @return true if 'what' is "true" or "TRUE", false otherwise
 
5530
   */
 
5531
  static final public boolean parseBoolean(String what) {
 
5532
    return new Boolean(what).booleanValue();
 
5533
  }
 
5534
 
 
5535
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
 
5536
 
 
5537
  /*
 
5538
  // removed, no need to introduce strange syntax from other languages
 
5539
  static final public boolean[] parseBoolean(char what[]) {
 
5540
    boolean outgoing[] = new boolean[what.length];
 
5541
    for (int i = 0; i < what.length; i++) {
 
5542
      outgoing[i] =
 
5543
        ((what[i] == 't') || (what[i] == 'T') || (what[i] == '1'));
 
5544
    }
 
5545
    return outgoing;
 
5546
  }
 
5547
  */
 
5548
 
 
5549
  /**
 
5550
   * Convert a byte array to a boolean array. Each element will be
 
5551
   * evaluated identical to the integer case, where a byte equal
 
5552
   * to zero will return false, and any other value will return true.
 
5553
   * @return array of boolean elements
 
5554
   */
 
5555
  static final public boolean[] parseBoolean(byte what[]) {
 
5556
    boolean outgoing[] = new boolean[what.length];
 
5557
    for (int i = 0; i < what.length; i++) {
 
5558
      outgoing[i] = (what[i] != 0);
 
5559
    }
 
5560
    return outgoing;
 
5561
  }
 
5562
 
 
5563
  /**
 
5564
   * Convert an int array to a boolean array. An int equal
 
5565
   * to zero will return false, and any other value will return true.
 
5566
   * @return array of boolean elements
 
5567
   */
 
5568
  static final public boolean[] parseBoolean(int what[]) {
 
5569
    boolean outgoing[] = new boolean[what.length];
 
5570
    for (int i = 0; i < what.length; i++) {
 
5571
      outgoing[i] = (what[i] != 0);
 
5572
    }
 
5573
    return outgoing;
 
5574
  }
 
5575
 
 
5576
  /*
 
5577
  // removed, not necessary... if necessary, convert to int array first
 
5578
  static final public boolean[] parseBoolean(float what[]) {
 
5579
    boolean outgoing[] = new boolean[what.length];
 
5580
    for (int i = 0; i < what.length; i++) {
 
5581
      outgoing[i] = (what[i] != 0);
 
5582
    }
 
5583
    return outgoing;
 
5584
  }
 
5585
  */
 
5586
 
 
5587
  static final public boolean[] parseBoolean(String what[]) {
 
5588
    boolean outgoing[] = new boolean[what.length];
 
5589
    for (int i = 0; i < what.length; i++) {
 
5590
      outgoing[i] = new Boolean(what[i]).booleanValue();
 
5591
    }
 
5592
    return outgoing;
 
5593
  }
 
5594
 
 
5595
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
 
5596
 
 
5597
  static final public byte parseByte(boolean what) {
 
5598
    return what ? (byte)1 : 0;
 
5599
  }
 
5600
 
 
5601
  static final public byte parseByte(char what) {
 
5602
    return (byte) what;
 
5603
  }
 
5604
 
 
5605
  static final public byte parseByte(int what) {
 
5606
    return (byte) what;
 
5607
  }
 
5608
 
 
5609
  static final public byte parseByte(float what) {
 
5610
    return (byte) what;
 
5611
  }
 
5612
 
 
5613
  /*
 
5614
  // nixed, no precedent
 
5615
  static final public byte[] parseByte(String what) {  // note: array[]
 
5616
    return what.getBytes();
 
5617
  }
 
5618
  */
 
5619
 
 
5620
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
 
5621
 
 
5622
  static final public byte[] parseByte(boolean what[]) {
 
5623
    byte outgoing[] = new byte[what.length];
 
5624
    for (int i = 0; i < what.length; i++) {
 
5625
      outgoing[i] = what[i] ? (byte)1 : 0;
 
5626
    }
 
5627
    return outgoing;
 
5628
  }
 
5629
 
 
5630
  static final public byte[] parseByte(char what[]) {
 
5631
    byte outgoing[] = new byte[what.length];
 
5632
    for (int i = 0; i < what.length; i++) {
 
5633
      outgoing[i] = (byte) what[i];
 
5634
    }
 
5635
    return outgoing;
 
5636
  }
 
5637
 
 
5638
  static final public byte[] parseByte(int what[]) {
 
5639
    byte outgoing[] = new byte[what.length];
 
5640
    for (int i = 0; i < what.length; i++) {
 
5641
      outgoing[i] = (byte) what[i];
 
5642
    }
 
5643
    return outgoing;
 
5644
  }
 
5645
 
 
5646
  static final public byte[] parseByte(float what[]) {
 
5647
    byte outgoing[] = new byte[what.length];
 
5648
    for (int i = 0; i < what.length; i++) {
 
5649
      outgoing[i] = (byte) what[i];
 
5650
    }
 
5651
    return outgoing;
 
5652
  }
 
5653
 
 
5654
  /*
 
5655
  static final public byte[][] parseByte(String what[]) {  // note: array[][]
 
5656
    byte outgoing[][] = new byte[what.length][];
 
5657
    for (int i = 0; i < what.length; i++) {
 
5658
      outgoing[i] = what[i].getBytes();
 
5659
    }
 
5660
    return outgoing;
 
5661
  }
 
5662
  */
 
5663
 
 
5664
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
 
5665
 
 
5666
  /*
 
5667
  static final public char parseChar(boolean what) {  // 0/1 or T/F ?
 
5668
    return what ? 't' : 'f';
 
5669
  }
 
5670
  */
 
5671
 
 
5672
  static final public char parseChar(byte what) {
 
5673
    return (char) (what & 0xff);
 
5674
  }
 
5675
 
 
5676
  static final public char parseChar(int what) {
 
5677
    return (char) what;
 
5678
  }
 
5679
 
 
5680
  /*
 
5681
  static final public char parseChar(float what) {  // nonsensical
 
5682
    return (char) what;
 
5683
  }
 
5684
 
 
5685
  static final public char[] parseChar(String what) {  // note: array[]
 
5686
    return what.toCharArray();
 
5687
  }
 
5688
  */
 
5689
 
 
5690
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
 
5691
 
 
5692
  /*
 
5693
  static final public char[] parseChar(boolean what[]) {  // 0/1 or T/F ?
 
5694
    char outgoing[] = new char[what.length];
 
5695
    for (int i = 0; i < what.length; i++) {
 
5696
      outgoing[i] = what[i] ? 't' : 'f';
 
5697
    }
 
5698
    return outgoing;
 
5699
  }
 
5700
  */
 
5701
 
 
5702
  static final public char[] parseChar(byte what[]) {
 
5703
    char outgoing[] = new char[what.length];
 
5704
    for (int i = 0; i < what.length; i++) {
 
5705
      outgoing[i] = (char) (what[i] & 0xff);
 
5706
    }
 
5707
    return outgoing;
 
5708
  }
 
5709
 
 
5710
  static final public char[] parseChar(int what[]) {
 
5711
    char outgoing[] = new char[what.length];
 
5712
    for (int i = 0; i < what.length; i++) {
 
5713
      outgoing[i] = (char) what[i];
 
5714
    }
 
5715
    return outgoing;
 
5716
  }
 
5717
 
 
5718
  /*
 
5719
  static final public char[] parseChar(float what[]) {  // nonsensical
 
5720
    char outgoing[] = new char[what.length];
 
5721
    for (int i = 0; i < what.length; i++) {
 
5722
      outgoing[i] = (char) what[i];
 
5723
    }
 
5724
    return outgoing;
 
5725
  }
 
5726
 
 
5727
  static final public char[][] parseChar(String what[]) {  // note: array[][]
 
5728
    char outgoing[][] = new char[what.length][];
 
5729
    for (int i = 0; i < what.length; i++) {
 
5730
      outgoing[i] = what[i].toCharArray();
 
5731
    }
 
5732
    return outgoing;
 
5733
  }
 
5734
  */
 
5735
 
 
5736
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
 
5737
 
 
5738
  static final public int parseInt(boolean what) {
 
5739
    return what ? 1 : 0;
 
5740
  }
 
5741
 
 
5742
  /**
 
5743
   * Note that parseInt() will un-sign a signed byte value.
 
5744
   */
 
5745
  static final public int parseInt(byte what) {
 
5746
    return what & 0xff;
 
5747
  }
 
5748
 
 
5749
  /**
 
5750
   * Note that parseInt('5') is unlike String in the sense that it
 
5751
   * won't return 5, but the ascii value. This is because ((int) someChar)
 
5752
   * returns the ascii value, and parseInt() is just longhand for the cast.
 
5753
   */
 
5754
  static final public int parseInt(char what) {
 
5755
    return what;
 
5756
  }
 
5757
 
 
5758
  /**
 
5759
   * Same as floor(), or an (int) cast.
 
5760
   */
 
5761
  static final public int parseInt(float what) {
 
5762
    return (int) what;
 
5763
  }
 
5764
 
 
5765
  /**
 
5766
   * Parse a String into an int value. Returns 0 if the value is bad.
 
5767
   */
 
5768
  static final public int parseInt(String what) {
 
5769
    return parseInt(what, 0);
 
5770
  }
 
5771
 
 
5772
  /**
 
5773
   * Parse a String to an int, and provide an alternate value that
 
5774
   * should be used when the number is invalid.
 
5775
   */
 
5776
  static final public int parseInt(String what, int otherwise) {
 
5777
    try {
 
5778
      int offset = what.indexOf('.');
 
5779
      if (offset == -1) {
 
5780
        return Integer.parseInt(what);
 
5781
      } else {
 
5782
        return Integer.parseInt(what.substring(0, offset));
 
5783
      }
 
5784
    } catch (NumberFormatException e) { }
 
5785
    return otherwise;
 
5786
  }
 
5787
 
 
5788
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
 
5789
 
 
5790
  static final public int[] parseInt(boolean what[]) {
 
5791
    int list[] = new int[what.length];
 
5792
    for (int i = 0; i < what.length; i++) {
 
5793
      list[i] = what[i] ? 1 : 0;
 
5794
    }
 
5795
    return list;
 
5796
  }
 
5797
 
 
5798
  static final public int[] parseInt(byte what[]) {  // note this unsigns
 
5799
    int list[] = new int[what.length];
 
5800
    for (int i = 0; i < what.length; i++) {
 
5801
      list[i] = (what[i] & 0xff);
 
5802
    }
 
5803
    return list;
 
5804
  }
 
5805
 
 
5806
  static final public int[] parseInt(char what[]) {
 
5807
    int list[] = new int[what.length];
 
5808
    for (int i = 0; i < what.length; i++) {
 
5809
      list[i] = what[i];
 
5810
    }
 
5811
    return list;
 
5812
  }
 
5813
 
 
5814
  static public int[] parseInt(float what[]) {
 
5815
    int inties[] = new int[what.length];
 
5816
    for (int i = 0; i < what.length; i++) {
 
5817
      inties[i] = (int)what[i];
 
5818
    }
 
5819
    return inties;
 
5820
  }
 
5821
 
 
5822
  /**
 
5823
   * Make an array of int elements from an array of String objects.
 
5824
   * If the String can't be parsed as a number, it will be set to zero.
 
5825
   *
 
5826
   * String s[] = { "1", "300", "44" };
 
5827
   * int numbers[] = parseInt(s);
 
5828
   *
 
5829
   * numbers will contain { 1, 300, 44 }
 
5830
   */
 
5831
  static public int[] parseInt(String what[]) {
 
5832
    return parseInt(what, 0);
 
5833
  }
 
5834
 
 
5835
  /**
 
5836
   * Make an array of int elements from an array of String objects.
 
5837
   * If the String can't be parsed as a number, its entry in the
 
5838
   * array will be set to the value of the "missing" parameter.
 
5839
   *
 
5840
   * String s[] = { "1", "300", "apple", "44" };
 
5841
   * int numbers[] = parseInt(s, 9999);
 
5842
   *
 
5843
   * numbers will contain { 1, 300, 9999, 44 }
 
5844
   */
 
5845
  static public int[] parseInt(String what[], int missing) {
 
5846
    int output[] = new int[what.length];
 
5847
    for (int i = 0; i < what.length; i++) {
 
5848
      try {
 
5849
        output[i] = Integer.parseInt(what[i]);
 
5850
      } catch (NumberFormatException e) {
 
5851
        output[i] = missing;
 
5852
      }
 
5853
    }
 
5854
    return output;
 
5855
  }
 
5856
 
 
5857
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
 
5858
 
 
5859
  /*
 
5860
  static final public float parseFloat(boolean what) {
 
5861
    return what ? 1 : 0;
 
5862
  }
 
5863
  */
 
5864
 
 
5865
  /**
 
5866
   * Convert an int to a float value. Also handles bytes because of
 
5867
   * Java's rules for upgrading values.
 
5868
   */
 
5869
  static final public float parseFloat(int what) {  // also handles byte
 
5870
    return (float)what;
 
5871
  }
 
5872
 
 
5873
  static final public float parseFloat(String what) {
 
5874
    return parseFloat(what, Float.NaN);
 
5875
  }
 
5876
 
 
5877
  static final public float parseFloat(String what, float otherwise) {
 
5878
    try {
 
5879
      return new Float(what).floatValue();
 
5880
    } catch (NumberFormatException e) { }
 
5881
 
 
5882
    return otherwise;
 
5883
  }
 
5884
 
 
5885
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
 
5886
 
 
5887
  /*
 
5888
  static final public float[] parseFloat(boolean what[]) {
 
5889
    float floaties[] = new float[what.length];
 
5890
    for (int i = 0; i < what.length; i++) {
 
5891
      floaties[i] = what[i] ? 1 : 0;
 
5892
    }
 
5893
    return floaties;
 
5894
  }
 
5895
 
 
5896
  static final public float[] parseFloat(char what[]) {
 
5897
    float floaties[] = new float[what.length];
 
5898
    for (int i = 0; i < what.length; i++) {
 
5899
      floaties[i] = (char) what[i];
 
5900
    }
 
5901
    return floaties;
 
5902
  }
 
5903
  */
 
5904
 
 
5905
  static final public float[] parseByte(byte what[]) {
 
5906
    float floaties[] = new float[what.length];
 
5907
    for (int i = 0; i < what.length; i++) {
 
5908
      floaties[i] = what[i];
 
5909
    }
 
5910
    return floaties;
 
5911
  }
 
5912
 
 
5913
  static final public float[] parseFloat(int what[]) {
 
5914
    float floaties[] = new float[what.length];
 
5915
    for (int i = 0; i < what.length; i++) {
 
5916
      floaties[i] = what[i];
 
5917
    }
 
5918
    return floaties;
 
5919
  }
 
5920
 
 
5921
  static final public float[] parseFloat(String what[]) {
 
5922
    return parseFloat(what, Float.NaN);
 
5923
  }
 
5924
 
 
5925
  static final public float[] parseFloat(String what[], float missing) {
 
5926
    float output[] = new float[what.length];
 
5927
    for (int i = 0; i < what.length; i++) {
 
5928
      try {
 
5929
        output[i] = new Float(what[i]).floatValue();
 
5930
      } catch (NumberFormatException e) {
 
5931
        output[i] = missing;
 
5932
      }
 
5933
    }
 
5934
    return output;
 
5935
  }
 
5936
 
 
5937
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
 
5938
 
 
5939
  static final public String str(boolean x) {
 
5940
    return String.valueOf(x);
 
5941
  }
 
5942
 
 
5943
  static final public String str(byte x) {
 
5944
    return String.valueOf(x);
 
5945
  }
 
5946
 
 
5947
  static final public String str(char x) {
 
5948
    return String.valueOf(x);
 
5949
  }
 
5950
 
 
5951
  static final public String str(int x) {
 
5952
    return String.valueOf(x);
 
5953
  }
 
5954
 
 
5955
  static final public String str(float x) {
 
5956
    return String.valueOf(x);
 
5957
  }
 
5958
 
 
5959
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
 
5960
 
 
5961
  static final public String[] str(boolean x[]) {
 
5962
    String s[] = new String[x.length];
 
5963
    for (int i = 0; i < x.length; i++) s[i] = String.valueOf(x[i]);
 
5964
    return s;
 
5965
  }
 
5966
 
 
5967
  static final public String[] str(byte x[]) {
 
5968
    String s[] = new String[x.length];
 
5969
    for (int i = 0; i < x.length; i++) s[i] = String.valueOf(x[i]);
 
5970
    return s;
 
5971
  }
 
5972
 
 
5973
  static final public String[] str(char x[]) {
 
5974
    String s[] = new String[x.length];
 
5975
    for (int i = 0; i < x.length; i++) s[i] = String.valueOf(x[i]);
 
5976
    return s;
 
5977
  }
 
5978
 
 
5979
  static final public String[] str(int x[]) {
 
5980
    String s[] = new String[x.length];
 
5981
    for (int i = 0; i < x.length; i++) s[i] = String.valueOf(x[i]);
 
5982
    return s;
 
5983
  }
 
5984
 
 
5985
  static final public String[] str(float x[]) {
 
5986
    String s[] = new String[x.length];
 
5987
    for (int i = 0; i < x.length; i++) s[i] = String.valueOf(x[i]);
 
5988
    return s;
 
5989
  }
 
5990
 
 
5991
 
 
5992
  //////////////////////////////////////////////////////////////
 
5993
 
 
5994
  // INT NUMBER FORMATTING
 
5995
 
 
5996
 
 
5997
  /**
 
5998
   * Integer number formatter.
 
5999
   */
 
6000
  static private NumberFormat int_nf;
 
6001
  static private int int_nf_digits;
 
6002
  static private boolean int_nf_commas;
 
6003
 
 
6004
 
 
6005
  static public String[] nf(int num[], int digits) {
 
6006
    String formatted[] = new String[num.length];
 
6007
    for (int i = 0; i < formatted.length; i++) {
 
6008
      formatted[i] = nf(num[i], digits);
 
6009
    }
 
6010
    return formatted;
 
6011
  }
 
6012
 
 
6013
 
 
6014
  static public String nf(int num, int digits) {
 
6015
    if ((int_nf != null) &&
 
6016
        (int_nf_digits == digits) &&
 
6017
        !int_nf_commas) {
 
6018
      return int_nf.format(num);
 
6019
    }
 
6020
 
 
6021
    int_nf = NumberFormat.getInstance();
 
6022
    int_nf.setGroupingUsed(false); // no commas
 
6023
    int_nf_commas = false;
 
6024
    int_nf.setMinimumIntegerDigits(digits);
 
6025
    int_nf_digits = digits;
 
6026
    return int_nf.format(num);
 
6027
  }
 
6028
 
 
6029
 
 
6030
  static public String[] nfc(int num[]) {
 
6031
    String formatted[] = new String[num.length];
 
6032
    for (int i = 0; i < formatted.length; i++) {
 
6033
      formatted[i] = nfc(num[i]);
 
6034
    }
 
6035
    return formatted;
 
6036
  }
 
6037
 
 
6038
 
 
6039
  static public String nfc(int num) {
 
6040
    if ((int_nf != null) &&
 
6041
        (int_nf_digits == 0) &&
 
6042
        int_nf_commas) {
 
6043
      return int_nf.format(num);
 
6044
    }
 
6045
 
 
6046
    int_nf = NumberFormat.getInstance();
 
6047
    int_nf.setGroupingUsed(true);
 
6048
    int_nf_commas = true;
 
6049
    int_nf.setMinimumIntegerDigits(0);
 
6050
    int_nf_digits = 0;
 
6051
    return int_nf.format(num);
 
6052
  }
 
6053
 
 
6054
 
 
6055
  /**
 
6056
   * number format signed (or space)
 
6057
   * Formats a number but leaves a blank space in the front
 
6058
   * when it's positive so that it can be properly aligned with
 
6059
   * numbers that have a negative sign in front of them.
 
6060
   */
 
6061
  static public String nfs(int num, int digits) {
 
6062
    return (num < 0) ? nf(num, digits) : (' ' + nf(num, digits));
 
6063
  }
 
6064
 
 
6065
  static public String[] nfs(int num[], int digits) {
 
6066
    String formatted[] = new String[num.length];
 
6067
    for (int i = 0; i < formatted.length; i++) {
 
6068
      formatted[i] = nfs(num[i], digits);
 
6069
    }
 
6070
    return formatted;
 
6071
  }
 
6072
 
 
6073
  //
 
6074
 
 
6075
  /**
 
6076
   * number format positive (or plus)
 
6077
   * Formats a number, always placing a - or + sign
 
6078
   * in the front when it's negative or positive.
 
6079
   */
 
6080
  static public String nfp(int num, int digits) {
 
6081
    return (num < 0) ? nf(num, digits) : ('+' + nf(num, digits));
 
6082
  }
 
6083
 
 
6084
  static public String[] nfp(int num[], int digits) {
 
6085
    String formatted[] = new String[num.length];
 
6086
    for (int i = 0; i < formatted.length; i++) {
 
6087
      formatted[i] = nfp(num[i], digits);
 
6088
    }
 
6089
    return formatted;
 
6090
  }
 
6091
 
 
6092
 
 
6093
 
 
6094
  //////////////////////////////////////////////////////////////
 
6095
 
 
6096
  // FLOAT NUMBER FORMATTING
 
6097
 
 
6098
 
 
6099
  static private NumberFormat float_nf;
 
6100
  static private int float_nf_left, float_nf_right;
 
6101
  static private boolean float_nf_commas;
 
6102
 
 
6103
 
 
6104
  static public String[] nf(float num[], int left, int right) {
 
6105
    String formatted[] = new String[num.length];
 
6106
    for (int i = 0; i < formatted.length; i++) {
 
6107
      formatted[i] = nf(num[i], left, right);
 
6108
    }
 
6109
    return formatted;
 
6110
  }
 
6111
 
 
6112
 
 
6113
  static public String nf(float num, int left, int right) {
 
6114
    if ((float_nf != null) &&
 
6115
        (float_nf_left == left) &&
 
6116
        (float_nf_right == right) &&
 
6117
        !float_nf_commas) {
 
6118
      return float_nf.format(num);
 
6119
    }
 
6120
 
 
6121
    float_nf = NumberFormat.getInstance();
 
6122
    float_nf.setGroupingUsed(false);
 
6123
    float_nf_commas = false;
 
6124
 
 
6125
    if (left != 0) float_nf.setMinimumIntegerDigits(left);
 
6126
    if (right != 0) {
 
6127
      float_nf.setMinimumFractionDigits(right);
 
6128
      float_nf.setMaximumFractionDigits(right);
 
6129
    }
 
6130
    float_nf_left = left;
 
6131
    float_nf_right = right;
 
6132
    return float_nf.format(num);
 
6133
  }
 
6134
 
 
6135
 
 
6136
  static public String[] nfc(float num[], int right) {
 
6137
    String formatted[] = new String[num.length];
 
6138
    for (int i = 0; i < formatted.length; i++) {
 
6139
      formatted[i] = nfc(num[i], right);
 
6140
    }
 
6141
    return formatted;
 
6142
  }
 
6143
 
 
6144
 
 
6145
  static public String nfc(float num, int right) {
 
6146
    if ((float_nf != null) &&
 
6147
        (float_nf_left == 0) &&
 
6148
        (float_nf_right == right) &&
 
6149
        float_nf_commas) {
 
6150
      return float_nf.format(num);
 
6151
    }
 
6152
 
 
6153
    float_nf = NumberFormat.getInstance();
 
6154
    float_nf.setGroupingUsed(true);
 
6155
    float_nf_commas = true;
 
6156
 
 
6157
    if (right != 0) {
 
6158
      float_nf.setMinimumFractionDigits(right);
 
6159
      float_nf.setMaximumFractionDigits(right);
 
6160
    }
 
6161
    float_nf_left = 0;
 
6162
    float_nf_right = right;
 
6163
    return float_nf.format(num);
 
6164
  }
 
6165
 
 
6166
 
 
6167
  /**
 
6168
   * Number formatter that takes into account whether the number
 
6169
   * has a sign (positive, negative, etc) in front of it.
 
6170
   */
 
6171
  static public String[] nfs(float num[], int left, int right) {
 
6172
    String formatted[] = new String[num.length];
 
6173
    for (int i = 0; i < formatted.length; i++) {
 
6174
      formatted[i] = nfs(num[i], left, right);
 
6175
    }
 
6176
    return formatted;
 
6177
  }
 
6178
 
 
6179
  static public String nfs(float num, int left, int right) {
 
6180
    return (num < 0) ? nf(num, left, right) :  (' ' + nf(num, left, right));
 
6181
  }
 
6182
 
 
6183
 
 
6184
  static public String[] nfp(float num[], int left, int right) {
 
6185
    String formatted[] = new String[num.length];
 
6186
    for (int i = 0; i < formatted.length; i++) {
 
6187
      formatted[i] = nfp(num[i], left, right);
 
6188
    }
 
6189
    return formatted;
 
6190
  }
 
6191
 
 
6192
  static public String nfp(float num, int left, int right) {
 
6193
    return (num < 0) ? nf(num, left, right) :  ('+' + nf(num, left, right));
 
6194
  }
 
6195
 
 
6196
 
 
6197
 
 
6198
  //////////////////////////////////////////////////////////////
 
6199
 
 
6200
  // HEX/BINARY CONVERSION
 
6201
 
 
6202
 
 
6203
  static final public String hex(byte what) {
 
6204
    return hex(what, 2);
 
6205
  }
 
6206
 
 
6207
  static final public String hex(char what) {
 
6208
    return hex(what, 4);
 
6209
  }
 
6210
 
 
6211
  static final public String hex(int what) {
 
6212
    return hex(what, 8);
 
6213
  }
 
6214
 
 
6215
  static final public String hex(int what, int digits) {
 
6216
    String stuff = Integer.toHexString(what).toUpperCase();
 
6217
 
 
6218
    int length = stuff.length();
 
6219
    if (length > digits) {
 
6220
      return stuff.substring(length - digits);
 
6221
 
 
6222
    } else if (length < digits) {
 
6223
      return "00000000".substring(8 - (digits-length)) + stuff;
 
6224
    }
 
6225
    return stuff;
 
6226
  }
 
6227
 
 
6228
  static final public int unhex(String what) {
 
6229
    // has to parse as a Long so that it'll work for numbers bigger than 2^31
 
6230
    return (int) (Long.parseLong(what, 16));
 
6231
  }
 
6232
 
 
6233
  //
 
6234
 
 
6235
  /**
 
6236
   * Returns a String that contains the binary value of a byte.
 
6237
   * The returned value will always have 8 digits.
 
6238
   */
 
6239
  static final public String binary(byte what) {
 
6240
    return binary(what, 8);
 
6241
  }
 
6242
 
 
6243
  /**
 
6244
   * Returns a String that contains the binary value of a char.
 
6245
   * The returned value will always have 16 digits because chars
 
6246
   * are two bytes long.
 
6247
   */
 
6248
  static final public String binary(char what) {
 
6249
    return binary(what, 16);
 
6250
  }
 
6251
 
 
6252
  /**
 
6253
   * Returns a String that contains the binary value of an int.
 
6254
   * The length depends on the size of the number itself.
 
6255
   * An int can be up to 32 binary digits, but that seems like
 
6256
   * overkill for almost any situation, so this function just
 
6257
   * auto-size. If you want a specific number of digits (like all 32)
 
6258
   * use binary(int what, int digits) to specify how many digits.
 
6259
   */
 
6260
  static final public String binary(int what) {
 
6261
    return Integer.toBinaryString(what);
 
6262
    //return binary(what, 32);
 
6263
  }
 
6264
 
 
6265
  /**
 
6266
   * Returns a String that contains the binary value of an int.
 
6267
   * The digits parameter determines how many digits will be used.
 
6268
   */
 
6269
  static final public String binary(int what, int digits) {
 
6270
    String stuff = Integer.toBinaryString(what);
 
6271
 
 
6272
    int length = stuff.length();
 
6273
    if (length > digits) {
 
6274
      return stuff.substring(length - digits);
 
6275
 
 
6276
    } else if (length < digits) {
 
6277
      int offset = 32 - (digits-length);
 
6278
      return "00000000000000000000000000000000".substring(offset) + stuff;
 
6279
    }
 
6280
    return stuff;
 
6281
  }
 
6282
 
 
6283
 
 
6284
  /**
 
6285
   * Unpack a binary String into an int.
 
6286
   * i.e. unbinary("00001000") would return 8.
 
6287
   */
 
6288
  static final public int unbinary(String what) {
 
6289
    return Integer.parseInt(what, 2);
 
6290
  }
 
6291
 
 
6292
 
 
6293
 
 
6294
  //////////////////////////////////////////////////////////////
 
6295
 
 
6296
  // COLOR FUNCTIONS
 
6297
 
 
6298
  // moved here so that they can work without
 
6299
  // the graphics actually being instantiated (outside setup)
 
6300
 
 
6301
 
 
6302
  public final int color(int gray) {
 
6303
    if (g == null) {
 
6304
      if (gray > 255) gray = 255; else if (gray < 0) gray = 0;
 
6305
      return 0xff000000 | (gray << 16) | (gray << 8) | gray;
 
6306
    }
 
6307
    return g.color(gray);
 
6308
  }
 
6309
 
 
6310
 
 
6311
  public final int color(float fgray) {
 
6312
    if (g == null) {
 
6313
      int gray = (int) fgray;
 
6314
      if (gray > 255) gray = 255; else if (gray < 0) gray = 0;
 
6315
      return 0xff000000 | (gray << 16) | (gray << 8) | gray;
 
6316
    }
 
6317
    return g.color(fgray);
 
6318
  }
 
6319
 
 
6320
 
 
6321
  /**
 
6322
   * As of 0116 this also takes color(#FF8800, alpha)
 
6323
   */
 
6324
  public final int color(int gray, int alpha) {
 
6325
    if (g == null) {
 
6326
      if (alpha > 255) alpha = 255; else if (alpha < 0) alpha = 0;
 
6327
      if (gray > 255) {
 
6328
        // then assume this is actually a #FF8800
 
6329
        return (alpha << 24) | (gray & 0xFFFFFF);
 
6330
      } else {
 
6331
        //if (gray > 255) gray = 255; else if (gray < 0) gray = 0;
 
6332
        return (alpha << 24) | (gray << 16) | (gray << 8) | gray;
 
6333
      }
 
6334
    }
 
6335
    return g.color(gray, alpha);
 
6336
  }
 
6337
 
 
6338
 
 
6339
  public final int color(float fgray, float falpha) {
 
6340
    if (g == null) {
 
6341
      int gray = (int) fgray;
 
6342
      int alpha = (int) falpha;
 
6343
      if (gray > 255) gray = 255; else if (gray < 0) gray = 0;
 
6344
      if (alpha > 255) alpha = 255; else if (alpha < 0) alpha = 0;
 
6345
      return 0xff000000 | (gray << 16) | (gray << 8) | gray;
 
6346
    }
 
6347
    return g.color(fgray, falpha);
 
6348
  }
 
6349
 
 
6350
 
 
6351
  public final int color(int x, int y, int z) {
 
6352
    if (g == null) {
 
6353
      if (x > 255) x = 255; else if (x < 0) x = 0;
 
6354
      if (y > 255) y = 255; else if (y < 0) y = 0;
 
6355
      if (z > 255) z = 255; else if (z < 0) z = 0;
 
6356
 
 
6357
      return 0xff000000 | (x << 16) | (y << 8) | z;
 
6358
    }
 
6359
    return g.color(x, y, z);
 
6360
  }
 
6361
 
 
6362
 
 
6363
  public final int color(float x, float y, float z) {
 
6364
    if (g == null) {
 
6365
      if (x > 255) x = 255; else if (x < 0) x = 0;
 
6366
      if (y > 255) y = 255; else if (y < 0) y = 0;
 
6367
      if (z > 255) z = 255; else if (z < 0) z = 0;
 
6368
 
 
6369
      return 0xff000000 | ((int)x << 16) | ((int)y << 8) | (int)z;
 
6370
    }
 
6371
    return g.color(x, y, z);
 
6372
  }
 
6373
 
 
6374
 
 
6375
  public final int color(int x, int y, int z, int a) {
 
6376
    if (g == null) {
 
6377
      if (a > 255) a = 255; else if (a < 0) a = 0;
 
6378
      if (x > 255) x = 255; else if (x < 0) x = 0;
 
6379
      if (y > 255) y = 255; else if (y < 0) y = 0;
 
6380
      if (z > 255) z = 255; else if (z < 0) z = 0;
 
6381
 
 
6382
      return (a << 24) | (x << 16) | (y << 8) | z;
 
6383
    }
 
6384
    return g.color(x, y, z, a);
 
6385
  }
 
6386
 
 
6387
 
 
6388
  public final int color(float x, float y, float z, float a) {
 
6389
    if (g == null) {
 
6390
      if (a > 255) a = 255; else if (a < 0) a = 0;
 
6391
      if (x > 255) x = 255; else if (x < 0) x = 0;
 
6392
      if (y > 255) y = 255; else if (y < 0) y = 0;
 
6393
      if (z > 255) z = 255; else if (z < 0) z = 0;
 
6394
 
 
6395
      return ((int)a << 24) | ((int)x << 16) | ((int)y << 8) | (int)z;
 
6396
    }
 
6397
    return g.color(x, y, z, a);
 
6398
  }
 
6399
 
 
6400
 
 
6401
 
 
6402
  //////////////////////////////////////////////////////////////
 
6403
 
 
6404
  // MAIN
 
6405
 
 
6406
 
 
6407
  /**
 
6408
   * Set this sketch to communicate its state back to the PDE.
 
6409
   * <p/>
 
6410
   * This uses the stderr stream to write positions of the window
 
6411
   * (so that it will be saved by the PDE for the next run) and
 
6412
   * notify on quit. See more notes in the Worker class.
 
6413
   */
 
6414
  public void setupExternalMessages() {
 
6415
 
 
6416
    frame.addComponentListener(new ComponentAdapter() {
 
6417
        public void componentMoved(ComponentEvent e) {
 
6418
          Point where = ((Frame) e.getSource()).getLocation();
 
6419
          System.err.println(PApplet.EXTERNAL_MOVE + " " +
 
6420
                             where.x + " " + where.y);
 
6421
          System.err.flush();  // doesn't seem to help or hurt
 
6422
        }
 
6423
      });
 
6424
 
 
6425
    frame.addWindowListener(new WindowAdapter() {
 
6426
        public void windowClosing(WindowEvent e) {
 
6427
//          System.err.println(PApplet.EXTERNAL_QUIT);
 
6428
//          System.err.flush();  // important
 
6429
//          System.exit(0);
 
6430
          exit();  // don't quit, need to just shut everything down (0133)
 
6431
        }
 
6432
      });
 
6433
  }
 
6434
 
 
6435
 
 
6436
  /**
 
6437
   * Set up a listener that will fire proper component resize events
 
6438
   * in cases where frame.setResizable(true) is called.
 
6439
   */
 
6440
  public void setupFrameResizeListener() {
 
6441
    frame.addComponentListener(new ComponentAdapter() {
 
6442
 
 
6443
        public void componentResized(ComponentEvent e) {
 
6444
          // Ignore bad resize events fired during setup to fix
 
6445
          // http://dev.processing.org/bugs/show_bug.cgi?id=341
 
6446
          // This should also fix the blank screen on Linux bug
 
6447
          // http://dev.processing.org/bugs/show_bug.cgi?id=282
 
6448
          if (frame.isResizable()) {
 
6449
            // might be multiple resize calls before visible (i.e. first
 
6450
            // when pack() is called, then when it's resized for use).
 
6451
            // ignore them because it's not the user resizing things.
 
6452
            Frame farm = (Frame) e.getComponent();
 
6453
            if (farm.isVisible()) {
 
6454
              Insets insets = farm.getInsets();
 
6455
              Dimension windowSize = farm.getSize();
 
6456
              int usableW = windowSize.width - insets.left - insets.right;
 
6457
              int usableH = windowSize.height - insets.top - insets.bottom;
 
6458
 
 
6459
              // the ComponentListener in PApplet will handle calling size()
 
6460
              setBounds(insets.left, insets.top, usableW, usableH);
 
6461
            }
 
6462
          }
 
6463
        }
 
6464
      });
 
6465
  }
 
6466
 
 
6467
 
 
6468
  /**
 
6469
   * GIF image of the Processing logo.
 
6470
   */
 
6471
  static public final byte[] ICON_IMAGE = {
 
6472
    71, 73, 70, 56, 57, 97, 16, 0, 16, 0, -77, 0, 0, 0, 0, 0, -1, -1, -1, 12,
 
6473
    12, 13, -15, -15, -14, 45, 57, 74, 54, 80, 111, 47, 71, 97, 62, 88, 117,
 
6474
    1, 14, 27, 7, 41, 73, 15, 52, 85, 2, 31, 55, 4, 54, 94, 18, 69, 109, 37,
 
6475
    87, 126, -1, -1, -1, 33, -7, 4, 1, 0, 0, 15, 0, 44, 0, 0, 0, 0, 16, 0, 16,
 
6476
    0, 0, 4, 122, -16, -107, 114, -86, -67, 83, 30, -42, 26, -17, -100, -45,
 
6477
    56, -57, -108, 48, 40, 122, -90, 104, 67, -91, -51, 32, -53, 77, -78, -100,
 
6478
    47, -86, 12, 76, -110, -20, -74, -101, 97, -93, 27, 40, 20, -65, 65, 48,
 
6479
    -111, 99, -20, -112, -117, -123, -47, -105, 24, 114, -112, 74, 69, 84, 25,
 
6480
    93, 88, -75, 9, 46, 2, 49, 88, -116, -67, 7, -19, -83, 60, 38, 3, -34, 2,
 
6481
    66, -95, 27, -98, 13, 4, -17, 55, 33, 109, 11, 11, -2, -128, 121, 123, 62,
 
6482
    91, 120, -128, 127, 122, 115, 102, 2, 119, 0, -116, -113, -119, 6, 102,
 
6483
    121, -108, -126, 5, 18, 6, 4, -102, -101, -100, 114, 15, 17, 0, 59
 
6484
  };
 
6485
 
 
6486
 
 
6487
  /**
 
6488
   * main() method for running this class from the command line.
 
6489
   * <P>
 
6490
   * <B>The options shown here are not yet finalized and will be
 
6491
   * changing over the next several releases.</B>
 
6492
   * <P>
 
6493
   * The simplest way to turn and applet into an application is to
 
6494
   * add the following code to your program:
 
6495
   * <PRE>static public void main(String args[]) {
 
6496
   *   PApplet.main(new String[] { "YourSketchName" });
 
6497
   * }</PRE>
 
6498
   * This will properly launch your applet from a double-clickable
 
6499
   * .jar or from the command line.
 
6500
   * <PRE>
 
6501
   * Parameters useful for launching or also used by the PDE:
 
6502
   *
 
6503
   * --location=x,y        upper-lefthand corner of where the applet
 
6504
   *                       should appear on screen. if not used,
 
6505
   *                       the default is to center on the main screen.
 
6506
   *
 
6507
   * --present             put the applet into full screen presentation
 
6508
   *                       mode. requires java 1.4 or later.
 
6509
   *
 
6510
   * --exclusive           use full screen exclusive mode when presenting.
 
6511
   *                       disables new windows or interaction with other
 
6512
   *                       monitors, this is like a "game" mode.
 
6513
   *
 
6514
   * --hide-stop           use to hide the stop button in situations where
 
6515
   *                       you don't want to allow users to exit. also
 
6516
   *                       see the FAQ on information for capturing the ESC
 
6517
   *                       key when running in presentation mode.
 
6518
   *
 
6519
   * --stop-color=#xxxxxx  color of the 'stop' text used to quit an
 
6520
   *                       sketch when it's in present mode.
 
6521
   *
 
6522
   * --bgcolor=#xxxxxx     background color of the window.
 
6523
   *
 
6524
   * --sketch-path         location of where to save files from functions
 
6525
   *                       like saveStrings() or saveFrame(). defaults to
 
6526
   *                       the folder that the java application was
 
6527
   *                       launched from, which means if this isn't set by
 
6528
   *                       the pde, everything goes into the same folder
 
6529
   *                       as processing.exe.
 
6530
   *
 
6531
   * --display=n           set what display should be used by this applet.
 
6532
   *                       displays are numbered starting from 1.
 
6533
   *
 
6534
   * Parameters used by Processing when running via the PDE
 
6535
   *
 
6536
   * --external            set when the applet is being used by the PDE
 
6537
   *
 
6538
   * --editor-location=x,y position of the upper-lefthand corner of the
 
6539
   *                       editor window, for placement of applet window
 
6540
   * </PRE>
 
6541
   */
 
6542
  static public void main(String args[]) {
 
6543
    // Disable abyssmally slow Sun renderer on OS X 10.5.
 
6544
    if (platform == MACOSX) {
 
6545
      // Only run this on OS X otherwise it can cause a permissions error.
 
6546
      // http://dev.processing.org/bugs/show_bug.cgi?id=976
 
6547
      System.setProperty("apple.awt.graphics.UseQuartz", "true");
 
6548
    }
 
6549
 
 
6550
    // This doesn't do anything.
 
6551
//    if (platform == WINDOWS) {
 
6552
//      // For now, disable the D3D renderer on Java 6u10 because
 
6553
//      // it causes problems with Present mode.
 
6554
//      // http://dev.processing.org/bugs/show_bug.cgi?id=1009
 
6555
//      System.setProperty("sun.java2d.d3d", "false");
 
6556
//    }
 
6557
 
 
6558
    if (args.length < 1) {
 
6559
      System.err.println("Usage: PApplet <appletname>");
 
6560
      System.err.println("For additional options, " +
 
6561
                         "see the Javadoc for PApplet");
 
6562
      System.exit(1);
 
6563
    }
 
6564
 
 
6565
    boolean external = false;
 
6566
    int[] location = null;
 
6567
    int[] editorLocation = null;
 
6568
 
 
6569
    String name = null;
 
6570
    boolean present = false;
 
6571
    boolean exclusive = false;
 
6572
    Color backgroundColor = Color.BLACK;
 
6573
    Color stopColor = Color.GRAY;
 
6574
    GraphicsDevice displayDevice = null;
 
6575
    boolean hideStop = false;
 
6576
 
 
6577
    String param = null, value = null;
 
6578
 
 
6579
    // try to get the user folder. if running under java web start,
 
6580
    // this may cause a security exception if the code is not signed.
 
6581
    // http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Integrate;action=display;num=1159386274
 
6582
    String folder = null;
 
6583
    try {
 
6584
      folder = System.getProperty("user.dir");
 
6585
    } catch (Exception e) { }
 
6586
 
 
6587
    int argIndex = 0;
 
6588
    while (argIndex < args.length) {
 
6589
      int equals = args[argIndex].indexOf('=');
 
6590
      if (equals != -1) {
 
6591
        param = args[argIndex].substring(0, equals);
 
6592
        value = args[argIndex].substring(equals + 1);
 
6593
 
 
6594
        if (param.equals(ARGS_EDITOR_LOCATION)) {
 
6595
          external = true;
 
6596
          editorLocation = parseInt(split(value, ','));
 
6597
 
 
6598
        } else if (param.equals(ARGS_DISPLAY)) {
 
6599
          int deviceIndex = Integer.parseInt(value) - 1;
 
6600
 
 
6601
          //DisplayMode dm = device.getDisplayMode();
 
6602
          //if ((dm.getWidth() == 1024) && (dm.getHeight() == 768)) {
 
6603
 
 
6604
          GraphicsEnvironment environment =
 
6605
            GraphicsEnvironment.getLocalGraphicsEnvironment();
 
6606
          GraphicsDevice devices[] = environment.getScreenDevices();
 
6607
          if ((deviceIndex >= 0) && (deviceIndex < devices.length)) {
 
6608
            displayDevice = devices[deviceIndex];
 
6609
          } else {
 
6610
            System.err.println("Display " + value + " does not exist, " +
 
6611
                               "using the default display instead.");
 
6612
          }
 
6613
 
 
6614
        } else if (param.equals(ARGS_BGCOLOR)) {
 
6615
          if (value.charAt(0) == '#') value = value.substring(1);
 
6616
          backgroundColor = new Color(Integer.parseInt(value, 16));
 
6617
 
 
6618
        } else if (param.equals(ARGS_STOP_COLOR)) {
 
6619
          if (value.charAt(0) == '#') value = value.substring(1);
 
6620
          stopColor = new Color(Integer.parseInt(value, 16));
 
6621
 
 
6622
        } else if (param.equals(ARGS_SKETCH_FOLDER)) {
 
6623
          folder = value;
 
6624
 
 
6625
        } else if (param.equals(ARGS_LOCATION)) {
 
6626
          location = parseInt(split(value, ','));
 
6627
        }
 
6628
 
 
6629
      } else {
 
6630
        if (args[argIndex].equals(ARGS_PRESENT)) {
 
6631
          present = true;
 
6632
 
 
6633
        } else if (args[argIndex].equals(ARGS_EXCLUSIVE)) {
 
6634
          exclusive = true;
 
6635
 
 
6636
        } else if (args[argIndex].equals(ARGS_HIDE_STOP)) {
 
6637
          hideStop = true;
 
6638
 
 
6639
        } else if (args[argIndex].equals(ARGS_EXTERNAL)) {
 
6640
          external = true;
 
6641
 
 
6642
        } else {
 
6643
          name = args[argIndex];
 
6644
          break;
 
6645
        }
 
6646
      }
 
6647
      argIndex++;
 
6648
    }
 
6649
 
 
6650
    // Set this property before getting into any GUI init code
 
6651
    //System.setProperty("com.apple.mrj.application.apple.menu.about.name", name);
 
6652
    // This )*)(*@#$ Apple crap don't work no matter where you put it
 
6653
    // (static method of the class, at the top of main, wherever)
 
6654
 
 
6655
    if (displayDevice == null) {
 
6656
      GraphicsEnvironment environment =
 
6657
        GraphicsEnvironment.getLocalGraphicsEnvironment();
 
6658
      displayDevice = environment.getDefaultScreenDevice();
 
6659
    }
 
6660
 
 
6661
    Frame frame = new Frame(displayDevice.getDefaultConfiguration());
 
6662
      /*
 
6663
      Frame frame = null;
 
6664
      if (displayDevice != null) {
 
6665
        frame = new Frame(displayDevice.getDefaultConfiguration());
 
6666
      } else {
 
6667
        frame = new Frame();
 
6668
      }
 
6669
      */
 
6670
      //Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
 
6671
 
 
6672
    // remove the grow box by default
 
6673
    // users who want it back can call frame.setResizable(true)
 
6674
    frame.setResizable(false);
 
6675
 
 
6676
    // Set the trimmings around the image
 
6677
    Image image = Toolkit.getDefaultToolkit().createImage(ICON_IMAGE);
 
6678
    frame.setIconImage(image);
 
6679
    frame.setTitle(name);
 
6680
 
 
6681
    final PApplet applet;
 
6682
    try {
 
6683
      Class<?> c = Thread.currentThread().getContextClassLoader().loadClass(name);
 
6684
      applet = (PApplet) c.newInstance();
 
6685
    } catch (Exception e) {
 
6686
      throw new RuntimeException(e);
 
6687
    }
 
6688
 
 
6689
    // these are needed before init/start
 
6690
    applet.frame = frame;
 
6691
    applet.sketchPath = folder;
 
6692
    applet.args = PApplet.subset(args, 1);
 
6693
    applet.external = external;
 
6694
 
 
6695
    // Need to save the window bounds at full screen,
 
6696
    // because pack() will cause the bounds to go to zero.
 
6697
    // http://dev.processing.org/bugs/show_bug.cgi?id=923
 
6698
    Rectangle fullScreenRect = null;
 
6699
 
 
6700
    // For 0149, moving this code (up to the pack() method) before init().
 
6701
    // For OpenGL (and perhaps other renderers in the future), a peer is
 
6702
    // needed before a GLDrawable can be created. So pack() needs to be
 
6703
    // called on the Frame before applet.init(), which itself calls size(),
 
6704
    // and launches the Thread that will kick off setup().
 
6705
    // http://dev.processing.org/bugs/show_bug.cgi?id=891
 
6706
    // http://dev.processing.org/bugs/show_bug.cgi?id=908
 
6707
    if (present) {
 
6708
      frame.setUndecorated(true);
 
6709
      frame.setBackground(backgroundColor);
 
6710
      if (exclusive) {
 
6711
        displayDevice.setFullScreenWindow(frame);
 
6712
        fullScreenRect = frame.getBounds();
 
6713
      } else {
 
6714
        DisplayMode mode = displayDevice.getDisplayMode();
 
6715
        fullScreenRect = new Rectangle(0, 0, mode.getWidth(), mode.getHeight());
 
6716
        frame.setBounds(fullScreenRect);
 
6717
        frame.setVisible(true);
 
6718
      }
 
6719
    }
 
6720
    frame.setLayout(null);
 
6721
    frame.add(applet);
 
6722
    if (present) {
 
6723
      frame.invalidate();
 
6724
    } else {
 
6725
      frame.pack();
 
6726
    }
 
6727
    // insufficient, places the 100x100 sketches offset strangely
 
6728
    //frame.validate();
 
6729
 
 
6730
    applet.init();
 
6731
 
 
6732
    // Wait until the applet has figured out its width.
 
6733
    // In a static mode app, this will be after setup() has completed,
 
6734
    // and the empty draw() has set "finished" to true.
 
6735
    // TODO make sure this won't hang if the applet has an exception.
 
6736
    while (applet.defaultSize && !applet.finished) {
 
6737
      //System.out.println("default size");
 
6738
      try {
 
6739
        Thread.sleep(5);
 
6740
 
 
6741
      } catch (InterruptedException e) {
 
6742
        //System.out.println("interrupt");
 
6743
      }
 
6744
    }
 
6745
    //println("not default size " + applet.width + " " + applet.height);
 
6746
    //println("  (g width/height is " + applet.g.width + "x" + applet.g.height + ")");
 
6747
 
 
6748
    if (present) {
 
6749
      // After the pack(), the screen bounds are gonna be 0s
 
6750
      frame.setBounds(fullScreenRect);
 
6751
      applet.setBounds((fullScreenRect.width - applet.width) / 2,
 
6752
                       (fullScreenRect.height - applet.height) / 2,
 
6753
                       applet.width, applet.height);
 
6754
 
 
6755
      if (!hideStop) {
 
6756
        Label label = new Label("stop");
 
6757
        label.setForeground(stopColor);
 
6758
        label.addMouseListener(new MouseAdapter() {
 
6759
            public void mousePressed(MouseEvent e) {
 
6760
              System.exit(0);
 
6761
            }
 
6762
          });
 
6763
        frame.add(label);
 
6764
 
 
6765
        Dimension labelSize = label.getPreferredSize();
 
6766
        // sometimes shows up truncated on mac
 
6767
        //System.out.println("label width is " + labelSize.width);
 
6768
        labelSize = new Dimension(100, labelSize.height);
 
6769
        label.setSize(labelSize);
 
6770
        label.setLocation(20, fullScreenRect.height - labelSize.height - 20);
 
6771
      }
 
6772
 
 
6773
      // not always running externally when in present mode
 
6774
      if (external) {
 
6775
        applet.setupExternalMessages();
 
6776
      }
 
6777
 
 
6778
    } else {  // if not presenting
 
6779
      // can't do pack earlier cuz present mode don't like it
 
6780
      // (can't go full screen with a frame after calling pack)
 
6781
      //        frame.pack();  // get insets. get more.
 
6782
      Insets insets = frame.getInsets();
 
6783
 
 
6784
      int windowW = Math.max(applet.width, MIN_WINDOW_WIDTH) +
 
6785
        insets.left + insets.right;
 
6786
      int windowH = Math.max(applet.height, MIN_WINDOW_HEIGHT) +
 
6787
        insets.top + insets.bottom;
 
6788
 
 
6789
      frame.setSize(windowW, windowH);
 
6790
 
 
6791
      if (location != null) {
 
6792
        // a specific location was received from PdeRuntime
 
6793
        // (applet has been run more than once, user placed window)
 
6794
        frame.setLocation(location[0], location[1]);
 
6795
 
 
6796
      } else if (external) {
 
6797
        int locationX = editorLocation[0] - 20;
 
6798
        int locationY = editorLocation[1];
 
6799
 
 
6800
        if (locationX - windowW > 10) {
 
6801
          // if it fits to the left of the window
 
6802
          frame.setLocation(locationX - windowW, locationY);
 
6803
 
 
6804
        } else {  // doesn't fit
 
6805
          // if it fits inside the editor window,
 
6806
          // offset slightly from upper lefthand corner
 
6807
          // so that it's plunked inside the text area
 
6808
          locationX = editorLocation[0] + 66;
 
6809
          locationY = editorLocation[1] + 66;
 
6810
 
 
6811
          if ((locationX + windowW > applet.screen.width - 33) ||
 
6812
              (locationY + windowH > applet.screen.height - 33)) {
 
6813
            // otherwise center on screen
 
6814
            locationX = (applet.screen.width - windowW) / 2;
 
6815
            locationY = (applet.screen.height - windowH) / 2;
 
6816
          }
 
6817
          frame.setLocation(locationX, locationY);
 
6818
        }
 
6819
      } else {  // just center on screen
 
6820
        frame.setLocation((applet.screen.width - applet.width) / 2,
 
6821
                          (applet.screen.height - applet.height) / 2);
 
6822
      }
 
6823
 
 
6824
      if (backgroundColor == Color.black) {  //BLACK) {
 
6825
        // this means no bg color unless specified
 
6826
        backgroundColor = SystemColor.control;
 
6827
      }
 
6828
      frame.setBackground(backgroundColor);
 
6829
 
 
6830
      int usableWindowH = windowH - insets.top - insets.bottom;
 
6831
      applet.setBounds((windowW - applet.width)/2,
 
6832
                       insets.top + (usableWindowH - applet.height)/2,
 
6833
                       applet.width, applet.height);
 
6834
 
 
6835
      if (external) {
 
6836
        applet.setupExternalMessages();
 
6837
 
 
6838
      } else {  // !external
 
6839
        frame.addWindowListener(new WindowAdapter() {
 
6840
            public void windowClosing(WindowEvent e) {
 
6841
              System.exit(0);
 
6842
            }
 
6843
          });
 
6844
      }
 
6845
 
 
6846
      // handle frame resizing events
 
6847
      applet.setupFrameResizeListener();
 
6848
 
 
6849
      // all set for rockin
 
6850
      if (applet.displayable()) {
 
6851
        frame.setVisible(true);
 
6852
      }
 
6853
    }
 
6854
 
 
6855
    applet.requestFocus(); // ask for keydowns
 
6856
    //System.out.println("exiting main()");
 
6857
  }
 
6858
 
 
6859
 
 
6860
  //////////////////////////////////////////////////////////////
 
6861
 
 
6862
 
 
6863
  /**
 
6864
   * Begin recording to a new renderer of the specified type, using the width
 
6865
   * and height of the main drawing surface.
 
6866
   */
 
6867
  public PGraphics beginRecord(String renderer, String filename) {
 
6868
    filename = insertFrame(filename);
 
6869
    PGraphics rec = createGraphics(width, height, renderer, filename);
 
6870
    beginRecord(rec);
 
6871
    return rec;
 
6872
  }
 
6873
 
 
6874
 
 
6875
  /**
 
6876
   * Begin recording (echoing) commands to the specified PGraphics object.
 
6877
   */
 
6878
  public void beginRecord(PGraphics recorder) {
 
6879
    this.recorder = recorder;
 
6880
    recorder.beginDraw();
 
6881
  }
 
6882
 
 
6883
 
 
6884
  public void endRecord() {
 
6885
    if (recorder != null) {
 
6886
      recorder.endDraw();
 
6887
      recorder.dispose();
 
6888
      recorder = null;
 
6889
    }
 
6890
  }
 
6891
 
 
6892
 
 
6893
  /**
 
6894
   * Begin recording raw shape data to a renderer of the specified type,
 
6895
   * using the width and height of the main drawing surface.
 
6896
   *
 
6897
   * If hashmarks (###) are found in the filename, they'll be replaced
 
6898
   * by the current frame number (frameCount).
 
6899
   */
 
6900
  public PGraphics beginRaw(String renderer, String filename) {
 
6901
    filename = insertFrame(filename);
 
6902
    PGraphics rec = createGraphics(width, height, renderer, filename);
 
6903
    g.beginRaw(rec);
 
6904
    return rec;
 
6905
  }
 
6906
 
 
6907
 
 
6908
  /**
 
6909
   * Begin recording raw shape data to the specified renderer.
 
6910
   *
 
6911
   * This simply echoes to g.beginRaw(), but since is placed here (rather than
 
6912
   * generated by preproc.pl) for clarity and so that it doesn't echo the
 
6913
   * command should beginRecord() be in use.
 
6914
   */
 
6915
  public void beginRaw(PGraphics rawGraphics) {
 
6916
    g.beginRaw(rawGraphics);
 
6917
  }
 
6918
 
 
6919
 
 
6920
  /**
 
6921
   * Stop recording raw shape data to the specified renderer.
 
6922
   *
 
6923
   * This simply echoes to g.beginRaw(), but since is placed here (rather than
 
6924
   * generated by preproc.pl) for clarity and so that it doesn't echo the
 
6925
   * command should beginRecord() be in use.
 
6926
   */
 
6927
  public void endRaw() {
 
6928
    g.endRaw();
 
6929
  }
 
6930
 
 
6931
 
 
6932
  //////////////////////////////////////////////////////////////
 
6933
 
 
6934
 
 
6935
  /**
 
6936
   * Override the g.pixels[] function to set the pixels[] array
 
6937
   * that's part of the PApplet object. Allows the use of
 
6938
   * pixels[] in the code, rather than g.pixels[].
 
6939
   */
 
6940
  public void loadPixels() {
 
6941
    g.loadPixels();
 
6942
    pixels = g.pixels;
 
6943
  }
 
6944
 
 
6945
 
 
6946
  public void updatePixels() {
 
6947
    g.updatePixels();
 
6948
  }
 
6949
 
 
6950
 
 
6951
  public void updatePixels(int x1, int y1, int x2, int y2) {
 
6952
    g.updatePixels(x1, y1, x2, y2);
 
6953
  }
 
6954
 
 
6955
 
 
6956
  //////////////////////////////////////////////////////////////
 
6957
 
 
6958
  // everything below this line is automatically generated. no touch.
 
6959
  // public functions for processing.core
 
6960
 
 
6961
 
 
6962
  public void flush() {
 
6963
    if (recorder != null) recorder.flush();
 
6964
    g.flush();
 
6965
  }
 
6966
 
 
6967
 
 
6968
  public void hint(int which) {
 
6969
    if (recorder != null) recorder.hint(which);
 
6970
    g.hint(which);
 
6971
  }
 
6972
 
 
6973
 
 
6974
  public void beginShape() {
 
6975
    if (recorder != null) recorder.beginShape();
 
6976
    g.beginShape();
 
6977
  }
 
6978
 
 
6979
 
 
6980
  public void beginShape(int kind) {
 
6981
    if (recorder != null) recorder.beginShape(kind);
 
6982
    g.beginShape(kind);
 
6983
  }
 
6984
 
 
6985
 
 
6986
  public void edge(boolean edge) {
 
6987
    if (recorder != null) recorder.edge(edge);
 
6988
    g.edge(edge);
 
6989
  }
 
6990
 
 
6991
 
 
6992
  public void normal(float nx, float ny, float nz) {
 
6993
    if (recorder != null) recorder.normal(nx, ny, nz);
 
6994
    g.normal(nx, ny, nz);
 
6995
  }
 
6996
 
 
6997
 
 
6998
  public void textureMode(int mode) {
 
6999
    if (recorder != null) recorder.textureMode(mode);
 
7000
    g.textureMode(mode);
 
7001
  }
 
7002
 
 
7003
 
 
7004
  public void texture(PImage image) {
 
7005
    if (recorder != null) recorder.texture(image);
 
7006
    g.texture(image);
 
7007
  }
 
7008
 
 
7009
 
 
7010
  public void vertex(float x, float y) {
 
7011
    if (recorder != null) recorder.vertex(x, y);
 
7012
    g.vertex(x, y);
 
7013
  }
 
7014
 
 
7015
 
 
7016
  public void vertex(float x, float y, float z) {
 
7017
    if (recorder != null) recorder.vertex(x, y, z);
 
7018
    g.vertex(x, y, z);
 
7019
  }
 
7020
 
 
7021
 
 
7022
  public void vertex(float[] v) {
 
7023
    if (recorder != null) recorder.vertex(v);
 
7024
    g.vertex(v);
 
7025
  }
 
7026
 
 
7027
 
 
7028
  public void vertex(float x, float y, float u, float v) {
 
7029
    if (recorder != null) recorder.vertex(x, y, u, v);
 
7030
    g.vertex(x, y, u, v);
 
7031
  }
 
7032
 
 
7033
 
 
7034
  public void vertex(float x, float y, float z, float u, float v) {
 
7035
    if (recorder != null) recorder.vertex(x, y, z, u, v);
 
7036
    g.vertex(x, y, z, u, v);
 
7037
  }
 
7038
 
 
7039
 
 
7040
  public void breakShape() {
 
7041
    if (recorder != null) recorder.breakShape();
 
7042
    g.breakShape();
 
7043
  }
 
7044
 
 
7045
 
 
7046
  public void endShape() {
 
7047
    if (recorder != null) recorder.endShape();
 
7048
    g.endShape();
 
7049
  }
 
7050
 
 
7051
 
 
7052
  public void endShape(int mode) {
 
7053
    if (recorder != null) recorder.endShape(mode);
 
7054
    g.endShape(mode);
 
7055
  }
 
7056
 
 
7057
 
 
7058
  public void bezierVertex(float x2, float y2,
 
7059
                           float x3, float y3,
 
7060
                           float x4, float y4) {
 
7061
    if (recorder != null) recorder.bezierVertex(x2, y2, x3, y3, x4, y4);
 
7062
    g.bezierVertex(x2, y2, x3, y3, x4, y4);
 
7063
  }
 
7064
 
 
7065
 
 
7066
  public void bezierVertex(float x2, float y2, float z2,
 
7067
                           float x3, float y3, float z3,
 
7068
                           float x4, float y4, float z4) {
 
7069
    if (recorder != null) recorder.bezierVertex(x2, y2, z2, x3, y3, z3, x4, y4, z4);
 
7070
    g.bezierVertex(x2, y2, z2, x3, y3, z3, x4, y4, z4);
 
7071
  }
 
7072
 
 
7073
 
 
7074
  public void curveVertex(float x, float y) {
 
7075
    if (recorder != null) recorder.curveVertex(x, y);
 
7076
    g.curveVertex(x, y);
 
7077
  }
 
7078
 
 
7079
 
 
7080
  public void curveVertex(float x, float y, float z) {
 
7081
    if (recorder != null) recorder.curveVertex(x, y, z);
 
7082
    g.curveVertex(x, y, z);
 
7083
  }
 
7084
 
 
7085
 
 
7086
  public void point(float x, float y) {
 
7087
    if (recorder != null) recorder.point(x, y);
 
7088
    g.point(x, y);
 
7089
  }
 
7090
 
 
7091
 
 
7092
  public void point(float x, float y, float z) {
 
7093
    if (recorder != null) recorder.point(x, y, z);
 
7094
    g.point(x, y, z);
 
7095
  }
 
7096
 
 
7097
 
 
7098
  public void line(float x1, float y1, float x2, float y2) {
 
7099
    if (recorder != null) recorder.line(x1, y1, x2, y2);
 
7100
    g.line(x1, y1, x2, y2);
 
7101
  }
 
7102
 
 
7103
 
 
7104
  public void line(float x1, float y1, float z1,
 
7105
                   float x2, float y2, float z2) {
 
7106
    if (recorder != null) recorder.line(x1, y1, z1, x2, y2, z2);
 
7107
    g.line(x1, y1, z1, x2, y2, z2);
 
7108
  }
 
7109
 
 
7110
 
 
7111
  public void triangle(float x1, float y1, float x2, float y2,
 
7112
                       float x3, float y3) {
 
7113
    if (recorder != null) recorder.triangle(x1, y1, x2, y2, x3, y3);
 
7114
    g.triangle(x1, y1, x2, y2, x3, y3);
 
7115
  }
 
7116
 
 
7117
 
 
7118
  public void quad(float x1, float y1, float x2, float y2,
 
7119
                   float x3, float y3, float x4, float y4) {
 
7120
    if (recorder != null) recorder.quad(x1, y1, x2, y2, x3, y3, x4, y4);
 
7121
    g.quad(x1, y1, x2, y2, x3, y3, x4, y4);
 
7122
  }
 
7123
 
 
7124
 
 
7125
  public void rectMode(int mode) {
 
7126
    if (recorder != null) recorder.rectMode(mode);
 
7127
    g.rectMode(mode);
 
7128
  }
 
7129
 
 
7130
 
 
7131
  public void rect(float a, float b, float c, float d) {
 
7132
    if (recorder != null) recorder.rect(a, b, c, d);
 
7133
    g.rect(a, b, c, d);
 
7134
  }
 
7135
 
 
7136
 
 
7137
  public void ellipseMode(int mode) {
 
7138
    if (recorder != null) recorder.ellipseMode(mode);
 
7139
    g.ellipseMode(mode);
 
7140
  }
 
7141
 
 
7142
 
 
7143
  public void ellipse(float a, float b, float c, float d) {
 
7144
    if (recorder != null) recorder.ellipse(a, b, c, d);
 
7145
    g.ellipse(a, b, c, d);
 
7146
  }
 
7147
 
 
7148
 
 
7149
  public void arc(float a, float b, float c, float d,
 
7150
                  float start, float stop) {
 
7151
    if (recorder != null) recorder.arc(a, b, c, d, start, stop);
 
7152
    g.arc(a, b, c, d, start, stop);
 
7153
  }
 
7154
 
 
7155
 
 
7156
  public void box(float size) {
 
7157
    if (recorder != null) recorder.box(size);
 
7158
    g.box(size);
 
7159
  }
 
7160
 
 
7161
 
 
7162
  public void box(float w, float h, float d) {
 
7163
    if (recorder != null) recorder.box(w, h, d);
 
7164
    g.box(w, h, d);
 
7165
  }
 
7166
 
 
7167
 
 
7168
  public void sphereDetail(int res) {
 
7169
    if (recorder != null) recorder.sphereDetail(res);
 
7170
    g.sphereDetail(res);
 
7171
  }
 
7172
 
 
7173
 
 
7174
  public void sphereDetail(int ures, int vres) {
 
7175
    if (recorder != null) recorder.sphereDetail(ures, vres);
 
7176
    g.sphereDetail(ures, vres);
 
7177
  }
 
7178
 
 
7179
 
 
7180
  public void sphere(float r) {
 
7181
    if (recorder != null) recorder.sphere(r);
 
7182
    g.sphere(r);
 
7183
  }
 
7184
 
 
7185
 
 
7186
  public float bezierPoint(float a, float b, float c, float d, float t) {
 
7187
    return g.bezierPoint(a, b, c, d, t);
 
7188
  }
 
7189
 
 
7190
 
 
7191
  public float bezierTangent(float a, float b, float c, float d, float t) {
 
7192
    return g.bezierTangent(a, b, c, d, t);
 
7193
  }
 
7194
 
 
7195
 
 
7196
  public void bezierDetail(int detail) {
 
7197
    if (recorder != null) recorder.bezierDetail(detail);
 
7198
    g.bezierDetail(detail);
 
7199
  }
 
7200
 
 
7201
 
 
7202
  public void bezier(float x1, float y1,
 
7203
                     float x2, float y2,
 
7204
                     float x3, float y3,
 
7205
                     float x4, float y4) {
 
7206
    if (recorder != null) recorder.bezier(x1, y1, x2, y2, x3, y3, x4, y4);
 
7207
    g.bezier(x1, y1, x2, y2, x3, y3, x4, y4);
 
7208
  }
 
7209
 
 
7210
 
 
7211
  public void bezier(float x1, float y1, float z1,
 
7212
                     float x2, float y2, float z2,
 
7213
                     float x3, float y3, float z3,
 
7214
                     float x4, float y4, float z4) {
 
7215
    if (recorder != null) recorder.bezier(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4);
 
7216
    g.bezier(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4);
 
7217
  }
 
7218
 
 
7219
 
 
7220
  public float curvePoint(float a, float b, float c, float d, float t) {
 
7221
    return g.curvePoint(a, b, c, d, t);
 
7222
  }
 
7223
 
 
7224
 
 
7225
  public float curveTangent(float a, float b, float c, float d, float t) {
 
7226
    return g.curveTangent(a, b, c, d, t);
 
7227
  }
 
7228
 
 
7229
 
 
7230
  public void curveDetail(int detail) {
 
7231
    if (recorder != null) recorder.curveDetail(detail);
 
7232
    g.curveDetail(detail);
 
7233
  }
 
7234
 
 
7235
 
 
7236
  public void curveTightness(float tightness) {
 
7237
    if (recorder != null) recorder.curveTightness(tightness);
 
7238
    g.curveTightness(tightness);
 
7239
  }
 
7240
 
 
7241
 
 
7242
  public void curve(float x1, float y1,
 
7243
                    float x2, float y2,
 
7244
                    float x3, float y3,
 
7245
                    float x4, float y4) {
 
7246
    if (recorder != null) recorder.curve(x1, y1, x2, y2, x3, y3, x4, y4);
 
7247
    g.curve(x1, y1, x2, y2, x3, y3, x4, y4);
 
7248
  }
 
7249
 
 
7250
 
 
7251
  public void curve(float x1, float y1, float z1,
 
7252
                    float x2, float y2, float z2,
 
7253
                    float x3, float y3, float z3,
 
7254
                    float x4, float y4, float z4) {
 
7255
    if (recorder != null) recorder.curve(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4);
 
7256
    g.curve(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4);
 
7257
  }
 
7258
 
 
7259
 
 
7260
  public void smooth() {
 
7261
    if (recorder != null) recorder.smooth();
 
7262
    g.smooth();
 
7263
  }
 
7264
 
 
7265
 
 
7266
  public void noSmooth() {
 
7267
    if (recorder != null) recorder.noSmooth();
 
7268
    g.noSmooth();
 
7269
  }
 
7270
 
 
7271
 
 
7272
  public void imageMode(int mode) {
 
7273
    if (recorder != null) recorder.imageMode(mode);
 
7274
    g.imageMode(mode);
 
7275
  }
 
7276
 
 
7277
 
 
7278
  public void image(PImage image, float x, float y) {
 
7279
    if (recorder != null) recorder.image(image, x, y);
 
7280
    g.image(image, x, y);
 
7281
  }
 
7282
 
 
7283
 
 
7284
  public void image(PImage image, float x, float y, float c, float d) {
 
7285
    if (recorder != null) recorder.image(image, x, y, c, d);
 
7286
    g.image(image, x, y, c, d);
 
7287
  }
 
7288
 
 
7289
 
 
7290
  public void image(PImage image,
 
7291
                    float a, float b, float c, float d,
 
7292
                    int u1, int v1, int u2, int v2) {
 
7293
    if (recorder != null) recorder.image(image, a, b, c, d, u1, v1, u2, v2);
 
7294
    g.image(image, a, b, c, d, u1, v1, u2, v2);
 
7295
  }
 
7296
 
 
7297
 
 
7298
  public void shapeMode(int mode) {
 
7299
    if (recorder != null) recorder.shapeMode(mode);
 
7300
    g.shapeMode(mode);
 
7301
  }
 
7302
 
 
7303
 
 
7304
  public void shape(PShape shape) {
 
7305
    if (recorder != null) recorder.shape(shape);
 
7306
    g.shape(shape);
 
7307
  }
 
7308
 
 
7309
 
 
7310
  public void shape(PShape shape, float x, float y) {
 
7311
    if (recorder != null) recorder.shape(shape, x, y);
 
7312
    g.shape(shape, x, y);
 
7313
  }
 
7314
 
 
7315
 
 
7316
  public void shape(PShape shape, float x, float y, float c, float d) {
 
7317
    if (recorder != null) recorder.shape(shape, x, y, c, d);
 
7318
    g.shape(shape, x, y, c, d);
 
7319
  }
 
7320
 
 
7321
 
 
7322
  public void textAlign(int align) {
 
7323
    if (recorder != null) recorder.textAlign(align);
 
7324
    g.textAlign(align);
 
7325
  }
 
7326
 
 
7327
 
 
7328
  public void textAlign(int alignX, int alignY) {
 
7329
    if (recorder != null) recorder.textAlign(alignX, alignY);
 
7330
    g.textAlign(alignX, alignY);
 
7331
  }
 
7332
 
 
7333
 
 
7334
  public float textAscent() {
 
7335
    return g.textAscent();
 
7336
  }
 
7337
 
 
7338
 
 
7339
  public float textDescent() {
 
7340
    return g.textDescent();
 
7341
  }
 
7342
 
 
7343
 
 
7344
  public void textFont(PFont which) {
 
7345
    if (recorder != null) recorder.textFont(which);
 
7346
    g.textFont(which);
 
7347
  }
 
7348
 
 
7349
 
 
7350
  public void textFont(PFont which, float size) {
 
7351
    if (recorder != null) recorder.textFont(which, size);
 
7352
    g.textFont(which, size);
 
7353
  }
 
7354
 
 
7355
 
 
7356
  public void textLeading(float leading) {
 
7357
    if (recorder != null) recorder.textLeading(leading);
 
7358
    g.textLeading(leading);
 
7359
  }
 
7360
 
 
7361
 
 
7362
  public void textMode(int mode) {
 
7363
    if (recorder != null) recorder.textMode(mode);
 
7364
    g.textMode(mode);
 
7365
  }
 
7366
 
 
7367
 
 
7368
  public void textSize(float size) {
 
7369
    if (recorder != null) recorder.textSize(size);
 
7370
    g.textSize(size);
 
7371
  }
 
7372
 
 
7373
 
 
7374
  public float textWidth(char c) {
 
7375
    return g.textWidth(c);
 
7376
  }
 
7377
 
 
7378
 
 
7379
  public float textWidth(String str) {
 
7380
    return g.textWidth(str);
 
7381
  }
 
7382
 
 
7383
 
 
7384
  public float textWidth(char[] chars, int start, int length) {
 
7385
    return g.textWidth(chars, start, length);
 
7386
  }
 
7387
 
 
7388
 
 
7389
  public void text(char c) {
 
7390
    if (recorder != null) recorder.text(c);
 
7391
    g.text(c);
 
7392
  }
 
7393
 
 
7394
 
 
7395
  public void text(char c, float x, float y) {
 
7396
    if (recorder != null) recorder.text(c, x, y);
 
7397
    g.text(c, x, y);
 
7398
  }
 
7399
 
 
7400
 
 
7401
  public void text(char c, float x, float y, float z) {
 
7402
    if (recorder != null) recorder.text(c, x, y, z);
 
7403
    g.text(c, x, y, z);
 
7404
  }
 
7405
 
 
7406
 
 
7407
  public void text(String str) {
 
7408
    if (recorder != null) recorder.text(str);
 
7409
    g.text(str);
 
7410
  }
 
7411
 
 
7412
 
 
7413
  public void text(String str, float x, float y) {
 
7414
    if (recorder != null) recorder.text(str, x, y);
 
7415
    g.text(str, x, y);
 
7416
  }
 
7417
 
 
7418
 
 
7419
  public void text(char[] chars, int start, int stop, float x, float y) {
 
7420
    if (recorder != null) recorder.text(chars, start, stop, x, y);
 
7421
    g.text(chars, start, stop, x, y);
 
7422
  }
 
7423
 
 
7424
 
 
7425
  public void text(String str, float x, float y, float z) {
 
7426
    if (recorder != null) recorder.text(str, x, y, z);
 
7427
    g.text(str, x, y, z);
 
7428
  }
 
7429
 
 
7430
 
 
7431
  public void text(char[] chars, int start, int stop, 
 
7432
                   float x, float y, float z) {
 
7433
    if (recorder != null) recorder.text(chars, start, stop, x, y, z);
 
7434
    g.text(chars, start, stop, x, y, z);
 
7435
  }
 
7436
 
 
7437
 
 
7438
  public void text(String str, float x1, float y1, float x2, float y2) {
 
7439
    if (recorder != null) recorder.text(str, x1, y1, x2, y2);
 
7440
    g.text(str, x1, y1, x2, y2);
 
7441
  }
 
7442
 
 
7443
 
 
7444
  public void text(String s, float x1, float y1, float x2, float y2, float z) {
 
7445
    if (recorder != null) recorder.text(s, x1, y1, x2, y2, z);
 
7446
    g.text(s, x1, y1, x2, y2, z);
 
7447
  }
 
7448
 
 
7449
 
 
7450
  public void text(int num, float x, float y) {
 
7451
    if (recorder != null) recorder.text(num, x, y);
 
7452
    g.text(num, x, y);
 
7453
  }
 
7454
 
 
7455
 
 
7456
  public void text(int num, float x, float y, float z) {
 
7457
    if (recorder != null) recorder.text(num, x, y, z);
 
7458
    g.text(num, x, y, z);
 
7459
  }
 
7460
 
 
7461
 
 
7462
  public void text(float num, float x, float y) {
 
7463
    if (recorder != null) recorder.text(num, x, y);
 
7464
    g.text(num, x, y);
 
7465
  }
 
7466
 
 
7467
 
 
7468
  public void text(float num, float x, float y, float z) {
 
7469
    if (recorder != null) recorder.text(num, x, y, z);
 
7470
    g.text(num, x, y, z);
 
7471
  }
 
7472
 
 
7473
 
 
7474
  public void pushMatrix() {
 
7475
    if (recorder != null) recorder.pushMatrix();
 
7476
    g.pushMatrix();
 
7477
  }
 
7478
 
 
7479
 
 
7480
  public void popMatrix() {
 
7481
    if (recorder != null) recorder.popMatrix();
 
7482
    g.popMatrix();
 
7483
  }
 
7484
 
 
7485
 
 
7486
  public void translate(float tx, float ty) {
 
7487
    if (recorder != null) recorder.translate(tx, ty);
 
7488
    g.translate(tx, ty);
 
7489
  }
 
7490
 
 
7491
 
 
7492
  public void translate(float tx, float ty, float tz) {
 
7493
    if (recorder != null) recorder.translate(tx, ty, tz);
 
7494
    g.translate(tx, ty, tz);
 
7495
  }
 
7496
 
 
7497
 
 
7498
  public void rotate(float angle) {
 
7499
    if (recorder != null) recorder.rotate(angle);
 
7500
    g.rotate(angle);
 
7501
  }
 
7502
 
 
7503
 
 
7504
  public void rotateX(float angle) {
 
7505
    if (recorder != null) recorder.rotateX(angle);
 
7506
    g.rotateX(angle);
 
7507
  }
 
7508
 
 
7509
 
 
7510
  public void rotateY(float angle) {
 
7511
    if (recorder != null) recorder.rotateY(angle);
 
7512
    g.rotateY(angle);
 
7513
  }
 
7514
 
 
7515
 
 
7516
  public void rotateZ(float angle) {
 
7517
    if (recorder != null) recorder.rotateZ(angle);
 
7518
    g.rotateZ(angle);
 
7519
  }
 
7520
 
 
7521
 
 
7522
  public void rotate(float angle, float vx, float vy, float vz) {
 
7523
    if (recorder != null) recorder.rotate(angle, vx, vy, vz);
 
7524
    g.rotate(angle, vx, vy, vz);
 
7525
  }
 
7526
 
 
7527
 
 
7528
  public void scale(float s) {
 
7529
    if (recorder != null) recorder.scale(s);
 
7530
    g.scale(s);
 
7531
  }
 
7532
 
 
7533
 
 
7534
  public void scale(float sx, float sy) {
 
7535
    if (recorder != null) recorder.scale(sx, sy);
 
7536
    g.scale(sx, sy);
 
7537
  }
 
7538
 
 
7539
 
 
7540
  public void scale(float x, float y, float z) {
 
7541
    if (recorder != null) recorder.scale(x, y, z);
 
7542
    g.scale(x, y, z);
 
7543
  }
 
7544
 
 
7545
 
 
7546
  public void resetMatrix() {
 
7547
    if (recorder != null) recorder.resetMatrix();
 
7548
    g.resetMatrix();
 
7549
  }
 
7550
 
 
7551
 
 
7552
  public void applyMatrix(PMatrix source) {
 
7553
    if (recorder != null) recorder.applyMatrix(source);
 
7554
    g.applyMatrix(source);
 
7555
  }
 
7556
 
 
7557
 
 
7558
  public void applyMatrix(PMatrix2D source) {
 
7559
    if (recorder != null) recorder.applyMatrix(source);
 
7560
    g.applyMatrix(source);
 
7561
  }
 
7562
 
 
7563
 
 
7564
  public void applyMatrix(float n00, float n01, float n02,
 
7565
                          float n10, float n11, float n12) {
 
7566
    if (recorder != null) recorder.applyMatrix(n00, n01, n02, n10, n11, n12);
 
7567
    g.applyMatrix(n00, n01, n02, n10, n11, n12);
 
7568
  }
 
7569
 
 
7570
 
 
7571
  public void applyMatrix(PMatrix3D source) {
 
7572
    if (recorder != null) recorder.applyMatrix(source);
 
7573
    g.applyMatrix(source);
 
7574
  }
 
7575
 
 
7576
 
 
7577
  public void applyMatrix(float n00, float n01, float n02, float n03,
 
7578
                          float n10, float n11, float n12, float n13,
 
7579
                          float n20, float n21, float n22, float n23,
 
7580
                          float n30, float n31, float n32, float n33) {
 
7581
    if (recorder != null) recorder.applyMatrix(n00, n01, n02, n03, n10, n11, n12, n13, n20, n21, n22, n23, n30, n31, n32, n33);
 
7582
    g.applyMatrix(n00, n01, n02, n03, n10, n11, n12, n13, n20, n21, n22, n23, n30, n31, n32, n33);
 
7583
  }
 
7584
 
 
7585
 
 
7586
  public PMatrix getMatrix() {
 
7587
    return g.getMatrix();
 
7588
  }
 
7589
 
 
7590
 
 
7591
  public PMatrix2D getMatrix(PMatrix2D target) {
 
7592
    return g.getMatrix(target);
 
7593
  }
 
7594
 
 
7595
 
 
7596
  public PMatrix3D getMatrix(PMatrix3D target) {
 
7597
    return g.getMatrix(target);
 
7598
  }
 
7599
 
 
7600
 
 
7601
  public void setMatrix(PMatrix source) {
 
7602
    if (recorder != null) recorder.setMatrix(source);
 
7603
    g.setMatrix(source);
 
7604
  }
 
7605
 
 
7606
 
 
7607
  public void setMatrix(PMatrix2D source) {
 
7608
    if (recorder != null) recorder.setMatrix(source);
 
7609
    g.setMatrix(source);
 
7610
  }
 
7611
 
 
7612
 
 
7613
  public void setMatrix(PMatrix3D source) {
 
7614
    if (recorder != null) recorder.setMatrix(source);
 
7615
    g.setMatrix(source);
 
7616
  }
 
7617
 
 
7618
 
 
7619
  public void printMatrix() {
 
7620
    if (recorder != null) recorder.printMatrix();
 
7621
    g.printMatrix();
 
7622
  }
 
7623
 
 
7624
 
 
7625
  public void beginCamera() {
 
7626
    if (recorder != null) recorder.beginCamera();
 
7627
    g.beginCamera();
 
7628
  }
 
7629
 
 
7630
 
 
7631
  public void endCamera() {
 
7632
    if (recorder != null) recorder.endCamera();
 
7633
    g.endCamera();
 
7634
  }
 
7635
 
 
7636
 
 
7637
  public void camera() {
 
7638
    if (recorder != null) recorder.camera();
 
7639
    g.camera();
 
7640
  }
 
7641
 
 
7642
 
 
7643
  public void camera(float eyeX, float eyeY, float eyeZ,
 
7644
                     float centerX, float centerY, float centerZ,
 
7645
                     float upX, float upY, float upZ) {
 
7646
    if (recorder != null) recorder.camera(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
 
7647
    g.camera(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
 
7648
  }
 
7649
 
 
7650
 
 
7651
  public void printCamera() {
 
7652
    if (recorder != null) recorder.printCamera();
 
7653
    g.printCamera();
 
7654
  }
 
7655
 
 
7656
 
 
7657
  public void ortho() {
 
7658
    if (recorder != null) recorder.ortho();
 
7659
    g.ortho();
 
7660
  }
 
7661
 
 
7662
 
 
7663
  public void ortho(float left, float right,
 
7664
                    float bottom, float top,
 
7665
                    float near, float far) {
 
7666
    if (recorder != null) recorder.ortho(left, right, bottom, top, near, far);
 
7667
    g.ortho(left, right, bottom, top, near, far);
 
7668
  }
 
7669
 
 
7670
 
 
7671
  public void perspective() {
 
7672
    if (recorder != null) recorder.perspective();
 
7673
    g.perspective();
 
7674
  }
 
7675
 
 
7676
 
 
7677
  public void perspective(float fovy, float aspect, float zNear, float zFar) {
 
7678
    if (recorder != null) recorder.perspective(fovy, aspect, zNear, zFar);
 
7679
    g.perspective(fovy, aspect, zNear, zFar);
 
7680
  }
 
7681
 
 
7682
 
 
7683
  public void frustum(float left, float right,
 
7684
                      float bottom, float top,
 
7685
                      float near, float far) {
 
7686
    if (recorder != null) recorder.frustum(left, right, bottom, top, near, far);
 
7687
    g.frustum(left, right, bottom, top, near, far);
 
7688
  }
 
7689
 
 
7690
 
 
7691
  public void printProjection() {
 
7692
    if (recorder != null) recorder.printProjection();
 
7693
    g.printProjection();
 
7694
  }
 
7695
 
 
7696
 
 
7697
  public float screenX(float x, float y) {
 
7698
    return g.screenX(x, y);
 
7699
  }
 
7700
 
 
7701
 
 
7702
  public float screenY(float x, float y) {
 
7703
    return g.screenY(x, y);
 
7704
  }
 
7705
 
 
7706
 
 
7707
  public float screenX(float x, float y, float z) {
 
7708
    return g.screenX(x, y, z);
 
7709
  }
 
7710
 
 
7711
 
 
7712
  public float screenY(float x, float y, float z) {
 
7713
    return g.screenY(x, y, z);
 
7714
  }
 
7715
 
 
7716
 
 
7717
  public float screenZ(float x, float y, float z) {
 
7718
    return g.screenZ(x, y, z);
 
7719
  }
 
7720
 
 
7721
 
 
7722
  public float modelX(float x, float y, float z) {
 
7723
    return g.modelX(x, y, z);
 
7724
  }
 
7725
 
 
7726
 
 
7727
  public float modelY(float x, float y, float z) {
 
7728
    return g.modelY(x, y, z);
 
7729
  }
 
7730
 
 
7731
 
 
7732
  public float modelZ(float x, float y, float z) {
 
7733
    return g.modelZ(x, y, z);
 
7734
  }
 
7735
 
 
7736
 
 
7737
  public void pushStyle() {
 
7738
    if (recorder != null) recorder.pushStyle();
 
7739
    g.pushStyle();
 
7740
  }
 
7741
 
 
7742
 
 
7743
  public void popStyle() {
 
7744
    if (recorder != null) recorder.popStyle();
 
7745
    g.popStyle();
 
7746
  }
 
7747
 
 
7748
 
 
7749
  public void style(PStyle s) {
 
7750
    if (recorder != null) recorder.style(s);
 
7751
    g.style(s);
 
7752
  }
 
7753
 
 
7754
 
 
7755
  public void strokeWeight(float weight) {
 
7756
    if (recorder != null) recorder.strokeWeight(weight);
 
7757
    g.strokeWeight(weight);
 
7758
  }
 
7759
 
 
7760
 
 
7761
  public void strokeJoin(int join) {
 
7762
    if (recorder != null) recorder.strokeJoin(join);
 
7763
    g.strokeJoin(join);
 
7764
  }
 
7765
 
 
7766
 
 
7767
  public void strokeCap(int cap) {
 
7768
    if (recorder != null) recorder.strokeCap(cap);
 
7769
    g.strokeCap(cap);
 
7770
  }
 
7771
 
 
7772
 
 
7773
  public void noStroke() {
 
7774
    if (recorder != null) recorder.noStroke();
 
7775
    g.noStroke();
 
7776
  }
 
7777
 
 
7778
 
 
7779
  public void stroke(int rgb) {
 
7780
    if (recorder != null) recorder.stroke(rgb);
 
7781
    g.stroke(rgb);
 
7782
  }
 
7783
 
 
7784
 
 
7785
  public void stroke(int rgb, float alpha) {
 
7786
    if (recorder != null) recorder.stroke(rgb, alpha);
 
7787
    g.stroke(rgb, alpha);
 
7788
  }
 
7789
 
 
7790
 
 
7791
  public void stroke(float gray) {
 
7792
    if (recorder != null) recorder.stroke(gray);
 
7793
    g.stroke(gray);
 
7794
  }
 
7795
 
 
7796
 
 
7797
  public void stroke(float gray, float alpha) {
 
7798
    if (recorder != null) recorder.stroke(gray, alpha);
 
7799
    g.stroke(gray, alpha);
 
7800
  }
 
7801
 
 
7802
 
 
7803
  public void stroke(float x, float y, float z) {
 
7804
    if (recorder != null) recorder.stroke(x, y, z);
 
7805
    g.stroke(x, y, z);
 
7806
  }
 
7807
 
 
7808
 
 
7809
  public void stroke(float x, float y, float z, float a) {
 
7810
    if (recorder != null) recorder.stroke(x, y, z, a);
 
7811
    g.stroke(x, y, z, a);
 
7812
  }
 
7813
 
 
7814
 
 
7815
  public void noTint() {
 
7816
    if (recorder != null) recorder.noTint();
 
7817
    g.noTint();
 
7818
  }
 
7819
 
 
7820
 
 
7821
  public void tint(int rgb) {
 
7822
    if (recorder != null) recorder.tint(rgb);
 
7823
    g.tint(rgb);
 
7824
  }
 
7825
 
 
7826
 
 
7827
  public void tint(int rgb, float alpha) {
 
7828
    if (recorder != null) recorder.tint(rgb, alpha);
 
7829
    g.tint(rgb, alpha);
 
7830
  }
 
7831
 
 
7832
 
 
7833
  public void tint(float gray) {
 
7834
    if (recorder != null) recorder.tint(gray);
 
7835
    g.tint(gray);
 
7836
  }
 
7837
 
 
7838
 
 
7839
  public void tint(float gray, float alpha) {
 
7840
    if (recorder != null) recorder.tint(gray, alpha);
 
7841
    g.tint(gray, alpha);
 
7842
  }
 
7843
 
 
7844
 
 
7845
  public void tint(float x, float y, float z) {
 
7846
    if (recorder != null) recorder.tint(x, y, z);
 
7847
    g.tint(x, y, z);
 
7848
  }
 
7849
 
 
7850
 
 
7851
  public void tint(float x, float y, float z, float a) {
 
7852
    if (recorder != null) recorder.tint(x, y, z, a);
 
7853
    g.tint(x, y, z, a);
 
7854
  }
 
7855
 
 
7856
 
 
7857
  public void noFill() {
 
7858
    if (recorder != null) recorder.noFill();
 
7859
    g.noFill();
 
7860
  }
 
7861
 
 
7862
 
 
7863
  public void fill(int rgb) {
 
7864
    if (recorder != null) recorder.fill(rgb);
 
7865
    g.fill(rgb);
 
7866
  }
 
7867
 
 
7868
 
 
7869
  public void fill(int rgb, float alpha) {
 
7870
    if (recorder != null) recorder.fill(rgb, alpha);
 
7871
    g.fill(rgb, alpha);
 
7872
  }
 
7873
 
 
7874
 
 
7875
  public void fill(float gray) {
 
7876
    if (recorder != null) recorder.fill(gray);
 
7877
    g.fill(gray);
 
7878
  }
 
7879
 
 
7880
 
 
7881
  public void fill(float gray, float alpha) {
 
7882
    if (recorder != null) recorder.fill(gray, alpha);
 
7883
    g.fill(gray, alpha);
 
7884
  }
 
7885
 
 
7886
 
 
7887
  public void fill(float x, float y, float z) {
 
7888
    if (recorder != null) recorder.fill(x, y, z);
 
7889
    g.fill(x, y, z);
 
7890
  }
 
7891
 
 
7892
 
 
7893
  public void fill(float x, float y, float z, float a) {
 
7894
    if (recorder != null) recorder.fill(x, y, z, a);
 
7895
    g.fill(x, y, z, a);
 
7896
  }
 
7897
 
 
7898
 
 
7899
  public void ambient(int rgb) {
 
7900
    if (recorder != null) recorder.ambient(rgb);
 
7901
    g.ambient(rgb);
 
7902
  }
 
7903
 
 
7904
 
 
7905
  public void ambient(float gray) {
 
7906
    if (recorder != null) recorder.ambient(gray);
 
7907
    g.ambient(gray);
 
7908
  }
 
7909
 
 
7910
 
 
7911
  public void ambient(float x, float y, float z) {
 
7912
    if (recorder != null) recorder.ambient(x, y, z);
 
7913
    g.ambient(x, y, z);
 
7914
  }
 
7915
 
 
7916
 
 
7917
  public void specular(int rgb) {
 
7918
    if (recorder != null) recorder.specular(rgb);
 
7919
    g.specular(rgb);
 
7920
  }
 
7921
 
 
7922
 
 
7923
  public void specular(float gray) {
 
7924
    if (recorder != null) recorder.specular(gray);
 
7925
    g.specular(gray);
 
7926
  }
 
7927
 
 
7928
 
 
7929
  public void specular(float x, float y, float z) {
 
7930
    if (recorder != null) recorder.specular(x, y, z);
 
7931
    g.specular(x, y, z);
 
7932
  }
 
7933
 
 
7934
 
 
7935
  public void shininess(float shine) {
 
7936
    if (recorder != null) recorder.shininess(shine);
 
7937
    g.shininess(shine);
 
7938
  }
 
7939
 
 
7940
 
 
7941
  public void emissive(int rgb) {
 
7942
    if (recorder != null) recorder.emissive(rgb);
 
7943
    g.emissive(rgb);
 
7944
  }
 
7945
 
 
7946
 
 
7947
  public void emissive(float gray) {
 
7948
    if (recorder != null) recorder.emissive(gray);
 
7949
    g.emissive(gray);
 
7950
  }
 
7951
 
 
7952
 
 
7953
  public void emissive(float x, float y, float z) {
 
7954
    if (recorder != null) recorder.emissive(x, y, z);
 
7955
    g.emissive(x, y, z);
 
7956
  }
 
7957
 
 
7958
 
 
7959
  public void lights() {
 
7960
    if (recorder != null) recorder.lights();
 
7961
    g.lights();
 
7962
  }
 
7963
 
 
7964
 
 
7965
  public void noLights() {
 
7966
    if (recorder != null) recorder.noLights();
 
7967
    g.noLights();
 
7968
  }
 
7969
 
 
7970
 
 
7971
  public void ambientLight(float red, float green, float blue) {
 
7972
    if (recorder != null) recorder.ambientLight(red, green, blue);
 
7973
    g.ambientLight(red, green, blue);
 
7974
  }
 
7975
 
 
7976
 
 
7977
  public void ambientLight(float red, float green, float blue,
 
7978
                           float x, float y, float z) {
 
7979
    if (recorder != null) recorder.ambientLight(red, green, blue, x, y, z);
 
7980
    g.ambientLight(red, green, blue, x, y, z);
 
7981
  }
 
7982
 
 
7983
 
 
7984
  public void directionalLight(float red, float green, float blue,
 
7985
                               float nx, float ny, float nz) {
 
7986
    if (recorder != null) recorder.directionalLight(red, green, blue, nx, ny, nz);
 
7987
    g.directionalLight(red, green, blue, nx, ny, nz);
 
7988
  }
 
7989
 
 
7990
 
 
7991
  public void pointLight(float red, float green, float blue,
 
7992
                         float x, float y, float z) {
 
7993
    if (recorder != null) recorder.pointLight(red, green, blue, x, y, z);
 
7994
    g.pointLight(red, green, blue, x, y, z);
 
7995
  }
 
7996
 
 
7997
 
 
7998
  public void spotLight(float red, float green, float blue,
 
7999
                        float x, float y, float z,
 
8000
                        float nx, float ny, float nz,
 
8001
                        float angle, float concentration) {
 
8002
    if (recorder != null) recorder.spotLight(red, green, blue, x, y, z, nx, ny, nz, angle, concentration);
 
8003
    g.spotLight(red, green, blue, x, y, z, nx, ny, nz, angle, concentration);
 
8004
  }
 
8005
 
 
8006
 
 
8007
  public void lightFalloff(float constant, float linear, float quadratic) {
 
8008
    if (recorder != null) recorder.lightFalloff(constant, linear, quadratic);
 
8009
    g.lightFalloff(constant, linear, quadratic);
 
8010
  }
 
8011
 
 
8012
 
 
8013
  public void lightSpecular(float x, float y, float z) {
 
8014
    if (recorder != null) recorder.lightSpecular(x, y, z);
 
8015
    g.lightSpecular(x, y, z);
 
8016
  }
 
8017
 
 
8018
 
 
8019
  public void background(int rgb) {
 
8020
    if (recorder != null) recorder.background(rgb);
 
8021
    g.background(rgb);
 
8022
  }
 
8023
 
 
8024
 
 
8025
  public void background(int rgb, float alpha) {
 
8026
    if (recorder != null) recorder.background(rgb, alpha);
 
8027
    g.background(rgb, alpha);
 
8028
  }
 
8029
 
 
8030
 
 
8031
  public void background(float gray) {
 
8032
    if (recorder != null) recorder.background(gray);
 
8033
    g.background(gray);
 
8034
  }
 
8035
 
 
8036
 
 
8037
  public void background(float gray, float alpha) {
 
8038
    if (recorder != null) recorder.background(gray, alpha);
 
8039
    g.background(gray, alpha);
 
8040
  }
 
8041
 
 
8042
 
 
8043
  public void background(float x, float y, float z) {
 
8044
    if (recorder != null) recorder.background(x, y, z);
 
8045
    g.background(x, y, z);
 
8046
  }
 
8047
 
 
8048
 
 
8049
  public void background(float x, float y, float z, float a) {
 
8050
    if (recorder != null) recorder.background(x, y, z, a);
 
8051
    g.background(x, y, z, a);
 
8052
  }
 
8053
 
 
8054
 
 
8055
  public void background(PImage image) {
 
8056
    if (recorder != null) recorder.background(image);
 
8057
    g.background(image);
 
8058
  }
 
8059
 
 
8060
 
 
8061
  public void colorMode(int mode) {
 
8062
    if (recorder != null) recorder.colorMode(mode);
 
8063
    g.colorMode(mode);
 
8064
  }
 
8065
 
 
8066
 
 
8067
  public void colorMode(int mode, float max) {
 
8068
    if (recorder != null) recorder.colorMode(mode, max);
 
8069
    g.colorMode(mode, max);
 
8070
  }
 
8071
 
 
8072
 
 
8073
  public void colorMode(int mode, float maxX, float maxY, float maxZ) {
 
8074
    if (recorder != null) recorder.colorMode(mode, maxX, maxY, maxZ);
 
8075
    g.colorMode(mode, maxX, maxY, maxZ);
 
8076
  }
 
8077
 
 
8078
 
 
8079
  public void colorMode(int mode,
 
8080
                        float maxX, float maxY, float maxZ, float maxA) {
 
8081
    if (recorder != null) recorder.colorMode(mode, maxX, maxY, maxZ, maxA);
 
8082
    g.colorMode(mode, maxX, maxY, maxZ, maxA);
 
8083
  }
 
8084
 
 
8085
 
 
8086
  public final float alpha(int what) {
 
8087
    return g.alpha(what);
 
8088
  }
 
8089
 
 
8090
 
 
8091
  public final float red(int what) {
 
8092
    return g.red(what);
 
8093
  }
 
8094
 
 
8095
 
 
8096
  public final float green(int what) {
 
8097
    return g.green(what);
 
8098
  }
 
8099
 
 
8100
 
 
8101
  public final float blue(int what) {
 
8102
    return g.blue(what);
 
8103
  }
 
8104
 
 
8105
 
 
8106
  public final float hue(int what) {
 
8107
    return g.hue(what);
 
8108
  }
 
8109
 
 
8110
 
 
8111
  public final float saturation(int what) {
 
8112
    return g.saturation(what);
 
8113
  }
 
8114
 
 
8115
 
 
8116
  public final float brightness(int what) {
 
8117
    return g.brightness(what);
 
8118
  }
 
8119
 
 
8120
 
 
8121
  public int lerpColor(int c1, int c2, float amt) {
 
8122
    return g.lerpColor(c1, c2, amt);
 
8123
  }
 
8124
 
 
8125
 
 
8126
  static public int lerpColor(int c1, int c2, float amt, int mode) {
 
8127
    return PGraphics.lerpColor(c1, c2, amt, mode);
 
8128
  }
 
8129
 
 
8130
 
 
8131
  public boolean displayable() {
 
8132
    return g.displayable();
 
8133
  }
 
8134
 
 
8135
 
 
8136
  public void setCache(Object parent, Object storage) {
 
8137
    if (recorder != null) recorder.setCache(parent, storage);
 
8138
    g.setCache(parent, storage);
 
8139
  }
 
8140
 
 
8141
 
 
8142
  public Object getCache(Object parent) {
 
8143
    return g.getCache(parent);
 
8144
  }
 
8145
 
 
8146
 
 
8147
  public void removeCache(Object parent) {
 
8148
    if (recorder != null) recorder.removeCache(parent);
 
8149
    g.removeCache(parent);
 
8150
  }
 
8151
 
 
8152
 
 
8153
  public int get(int x, int y) {
 
8154
    return g.get(x, y);
 
8155
  }
 
8156
 
 
8157
 
 
8158
  public PImage get(int x, int y, int w, int h) {
 
8159
    return g.get(x, y, w, h);
 
8160
  }
 
8161
 
 
8162
 
 
8163
  public PImage get() {
 
8164
    return g.get();
 
8165
  }
 
8166
 
 
8167
 
 
8168
  public void set(int x, int y, int c) {
 
8169
    if (recorder != null) recorder.set(x, y, c);
 
8170
    g.set(x, y, c);
 
8171
  }
 
8172
 
 
8173
 
 
8174
  public void set(int x, int y, PImage src) {
 
8175
    if (recorder != null) recorder.set(x, y, src);
 
8176
    g.set(x, y, src);
 
8177
  }
 
8178
 
 
8179
 
 
8180
  public void mask(int alpha[]) {
 
8181
    if (recorder != null) recorder.mask(alpha);
 
8182
    g.mask(alpha);
 
8183
  }
 
8184
 
 
8185
 
 
8186
  public void mask(PImage alpha) {
 
8187
    if (recorder != null) recorder.mask(alpha);
 
8188
    g.mask(alpha);
 
8189
  }
 
8190
 
 
8191
 
 
8192
  public void filter(int kind) {
 
8193
    if (recorder != null) recorder.filter(kind);
 
8194
    g.filter(kind);
 
8195
  }
 
8196
 
 
8197
 
 
8198
  public void filter(int kind, float param) {
 
8199
    if (recorder != null) recorder.filter(kind, param);
 
8200
    g.filter(kind, param);
 
8201
  }
 
8202
 
 
8203
 
 
8204
  public void copy(int sx, int sy, int sw, int sh,
 
8205
                   int dx, int dy, int dw, int dh) {
 
8206
    if (recorder != null) recorder.copy(sx, sy, sw, sh, dx, dy, dw, dh);
 
8207
    g.copy(sx, sy, sw, sh, dx, dy, dw, dh);
 
8208
  }
 
8209
 
 
8210
 
 
8211
  public void copy(PImage src,
 
8212
                   int sx, int sy, int sw, int sh,
 
8213
                   int dx, int dy, int dw, int dh) {
 
8214
    if (recorder != null) recorder.copy(src, sx, sy, sw, sh, dx, dy, dw, dh);
 
8215
    g.copy(src, sx, sy, sw, sh, dx, dy, dw, dh);
 
8216
  }
 
8217
 
 
8218
 
 
8219
  static public int blendColor(int c1, int c2, int mode) {
 
8220
    return PGraphics.blendColor(c1, c2, mode);
 
8221
  }
 
8222
 
 
8223
 
 
8224
  public void blend(int sx, int sy, int sw, int sh,
 
8225
                    int dx, int dy, int dw, int dh, int mode) {
 
8226
    if (recorder != null) recorder.blend(sx, sy, sw, sh, dx, dy, dw, dh, mode);
 
8227
    g.blend(sx, sy, sw, sh, dx, dy, dw, dh, mode);
 
8228
  }
 
8229
 
 
8230
 
 
8231
  public void blend(PImage src,
 
8232
                    int sx, int sy, int sw, int sh,
 
8233
                    int dx, int dy, int dw, int dh, int mode) {
 
8234
    if (recorder != null) recorder.blend(src, sx, sy, sw, sh, dx, dy, dw, dh, mode);
 
8235
    g.blend(src, sx, sy, sw, sh, dx, dy, dw, dh, mode);
 
8236
  }
 
8237
}