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

« back to all changes in this revision

Viewing changes to src/processing/core/PGraphics.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; either
 
12
  version 2.1 of the License, or (at your option) any later version.
 
13
 
 
14
  This library is distributed in the hope that it will be useful,
 
15
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
17
  Lesser General Public License for more details.
 
18
 
 
19
  You should have received a copy of the GNU Lesser General
 
20
  Public License along with this library; if not, write to the
 
21
  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 
22
  Boston, MA  02111-1307  USA
 
23
*/
 
24
 
 
25
package processing.core;
 
26
 
 
27
import java.awt.*;
 
28
import java.util.HashMap;
 
29
 
 
30
 
 
31
/**
 
32
 * Main graphics and rendering context, as well as the base API implementation.
 
33
 *
 
34
 * <h2>Subclassing and initializing PGraphics objects</h2>
 
35
 * Starting in release 0149, subclasses of PGraphics are handled differently.
 
36
 * The constructor for subclasses takes no parameters, instead a series of
 
37
 * functions are called by the hosting PApplet to specify its attributes.
 
38
 * <ul>
 
39
 * <li>setParent(PApplet) - is called to specify the parent PApplet.
 
40
 * <li>setPrimary(boolean) - called with true if this PGraphics will be the
 
41
 * primary drawing surface used by the sketch, or false if not.
 
42
 * <li>setPath(String) - called when the renderer needs a filename or output
 
43
 * path, such as with the PDF or DXF renderers.
 
44
 * <li>setSize(int, int) - this is called last, at which point it's safe for
 
45
 * the renderer to complete its initialization routine.
 
46
 * </ul>
 
47
 * The functions were broken out because of the growing number of parameters
 
48
 * such as these that might be used by a renderer, yet with the exception of
 
49
 * setSize(), it's not clear which will be necessary. So while the size could
 
50
 * be passed in to the constructor instead of a setSize() function, a function
 
51
 * would still be needed that would notify the renderer that it was time to
 
52
 * finish its initialization. Thus, setSize() simply does both.
 
53
 *
 
54
 * <h2>Know your rights: public vs. private methods</h2>
 
55
 * Methods that are protected are often subclassed by other renderers, however
 
56
 * they are not set 'public' because they shouldn't be part of the user-facing
 
57
 * public API accessible from PApplet. That is, we don't want sketches calling
 
58
 * textModeCheck() or vertexTexture() directly.
 
59
 *
 
60
 * <h2>Handling warnings and exceptions</h2>
 
61
 * Methods that are unavailable generally show a warning, unless their lack of
 
62
 * availability will soon cause another exception. For instance, if a method
 
63
 * like getMatrix() returns null because it is unavailable, an exception will
 
64
 * be thrown stating that the method is unavailable, rather than waiting for
 
65
 * the NullPointerException that will occur when the sketch tries to use that
 
66
 * method. As of release 0149, warnings will only be shown once, and exceptions
 
67
 * have been changed to warnings where possible.
 
68
 *
 
69
 * <h2>Using xxxxImpl() for subclassing smoothness</h2>
 
70
 * The xxxImpl() methods are generally renderer-specific handling for some
 
71
 * subset if tasks for a particular function (vague enough for you?) For
 
72
 * instance, imageImpl() handles drawing an image whose x/y/w/h and u/v coords
 
73
 * have been specified, and screen placement (independent of imageMode) has
 
74
 * been determined. There's no point in all renderers implementing the
 
75
 * <tt>if (imageMode == BLAH)</tt> placement/sizing logic, so that's handled
 
76
 * by PGraphics, which then calls imageImpl() once all that is figured out.
 
77
 *
 
78
 * <h2>His brother PImage</h2>
 
79
 * PGraphics subclasses PImage so that it can be drawn and manipulated in a
 
80
 * similar fashion. As such, many methods are inherited from PGraphics,
 
81
 * though many are unavailable: for instance, resize() is not likely to be
 
82
 * implemented; the same goes for mask(), depending on the situation.
 
83
 *
 
84
 * <h2>What's in PGraphics, what ain't</h2>
 
85
 * For the benefit of subclasses, as much as possible has been placed inside
 
86
 * PGraphics. For instance, bezier interpolation code and implementations of
 
87
 * the strokeCap() method (that simply sets the strokeCap variable) are
 
88
 * handled here. Features that will vary widely between renderers are located
 
89
 * inside the subclasses themselves. For instance, all matrix handling code
 
90
 * is per-renderer: Java 2D uses its own AffineTransform, P2D uses a PMatrix2D,
 
91
 * and PGraphics3D needs to keep continually update forward and reverse
 
92
 * transformations. A proper (future) OpenGL implementation will have all its
 
93
 * matrix madness handled by the card. Lighting also falls under this
 
94
 * category, however the base material property settings (emissive, specular,
 
95
 * et al.) are handled in PGraphics because they use the standard colorMode()
 
96
 * logic. Subclasses should override methods like emissiveFromCalc(), which
 
97
 * is a point where a valid color has been defined internally, and can be
 
98
 * applied in some manner based on the calcXxxx values.
 
99
 *
 
100
 * <h2>What's in the PGraphics documentation, what ain't</h2>
 
101
 * Some things are noted here, some things are not. For public API, always
 
102
 * refer to the <a href="http://processing.org/reference">reference</A>
 
103
 * on Processing.org for proper explanations. <b>No attempt has been made to
 
104
 * keep the javadoc up to date or complete.</b> It's an enormous task for
 
105
 * which we simply do not have the time. That is, it's not something that
 
106
 * to be done once&mdash;it's a matter of keeping the multiple references
 
107
 * synchronized (to say nothing of the translation issues), while targeting
 
108
 * them for their separate audiences. Ouch.
 
109
 */
 
110
public class PGraphics extends PImage implements PConstants {
 
111
 
 
112
  // ........................................................
 
113
 
 
114
  // width and height are already inherited from PImage
 
115
 
 
116
 
 
117
  /// width minus one (useful for many calculations)
 
118
  protected int width1;
 
119
 
 
120
  /// height minus one (useful for many calculations)
 
121
  protected int height1;
 
122
 
 
123
  /// width * height (useful for many calculations)
 
124
  public int pixelCount;
 
125
 
 
126
  /// true if smoothing is enabled (read-only)
 
127
  public boolean smooth = false;
 
128
 
 
129
  // ........................................................
 
130
 
 
131
  /// true if defaults() has been called a first time
 
132
  protected boolean settingsInited;
 
133
 
 
134
  /// set to a PGraphics object being used inside a beginRaw/endRaw() block
 
135
  protected PGraphics raw;
 
136
 
 
137
  // ........................................................
 
138
 
 
139
  /** path to the file being saved for this renderer (if any) */
 
140
  protected String path;
 
141
 
 
142
  /**
 
143
   * true if this is the main drawing surface for a particular sketch.
 
144
   * This would be set to false for an offscreen buffer or if it were
 
145
   * created any other way than size(). When this is set, the listeners
 
146
   * are also added to the sketch.
 
147
   */
 
148
  protected boolean primarySurface;
 
149
 
 
150
  // ........................................................
 
151
 
 
152
  /**
 
153
   * Array of hint[] items. These are hacks to get around various
 
154
   * temporary workarounds inside the environment.
 
155
   * <p/>
 
156
   * Note that this array cannot be static, as a hint() may result in a
 
157
   * runtime change specific to a renderer. For instance, calling
 
158
   * hint(DISABLE_DEPTH_TEST) has to call glDisable() right away on an
 
159
   * instance of PGraphicsOpenGL.
 
160
   * <p/>
 
161
   * The hints[] array is allocated early on because it might
 
162
   * be used inside beginDraw(), allocate(), etc.
 
163
   */
 
164
  protected boolean[] hints = new boolean[HINT_COUNT];
 
165
 
 
166
 
 
167
  ////////////////////////////////////////////////////////////
 
168
 
 
169
  // STYLE PROPERTIES
 
170
 
 
171
  // Also inherits imageMode() and smooth() (among others) from PImage.
 
172
 
 
173
  /** The current colorMode */
 
174
  public int colorMode; // = RGB;
 
175
 
 
176
  /** Max value for red (or hue) set by colorMode */
 
177
  public float colorModeX; // = 255;
 
178
 
 
179
  /** Max value for green (or saturation) set by colorMode */
 
180
  public float colorModeY; // = 255;
 
181
 
 
182
  /** Max value for blue (or value) set by colorMode */
 
183
  public float colorModeZ; // = 255;
 
184
 
 
185
  /** Max value for alpha set by colorMode */
 
186
  public float colorModeA; // = 255;
 
187
 
 
188
  /** True if colors are not in the range 0..1 */
 
189
  boolean colorModeScale; // = true;
 
190
 
 
191
  /** True if colorMode(RGB, 255) */
 
192
  boolean colorModeDefault; // = true;
 
193
 
 
194
  // ........................................................
 
195
 
 
196
  // Tint color for images
 
197
 
 
198
  /**
 
199
   * True if tint() is enabled (read-only).
 
200
   *
 
201
   * Using tint/tintColor seems a better option for naming than
 
202
   * tintEnabled/tint because the latter seems ugly, even though
 
203
   * g.tint as the actual color seems a little more intuitive,
 
204
   * it's just that g.tintEnabled is even more unintuitive.
 
205
   * Same goes for fill and stroke, et al.
 
206
   */
 
207
  public boolean tint;
 
208
 
 
209
  /** tint that was last set (read-only) */
 
210
  public int tintColor;
 
211
 
 
212
  protected boolean tintAlpha;
 
213
  protected float tintR, tintG, tintB, tintA;
 
214
  protected int tintRi, tintGi, tintBi, tintAi;
 
215
 
 
216
  // ........................................................
 
217
 
 
218
  // Fill color
 
219
 
 
220
  /** true if fill() is enabled, (read-only) */
 
221
  public boolean fill;
 
222
 
 
223
  /** fill that was last set (read-only) */
 
224
  public int fillColor = 0xffFFFFFF;
 
225
 
 
226
  protected boolean fillAlpha;
 
227
  protected float fillR, fillG, fillB, fillA;
 
228
  protected int fillRi, fillGi, fillBi, fillAi;
 
229
 
 
230
  // ........................................................
 
231
 
 
232
  // Stroke color
 
233
 
 
234
  /** true if stroke() is enabled, (read-only) */
 
235
  public boolean stroke;
 
236
 
 
237
  /** stroke that was last set (read-only) */
 
238
  public int strokeColor = 0xff000000;
 
239
 
 
240
  protected boolean strokeAlpha;
 
241
  protected float strokeR, strokeG, strokeB, strokeA;
 
242
  protected int strokeRi, strokeGi, strokeBi, strokeAi;
 
243
 
 
244
  // ........................................................
 
245
 
 
246
  // Additional stroke properties
 
247
 
 
248
  static protected final float DEFAULT_STROKE_WEIGHT = 1;
 
249
  static protected final int DEFAULT_STROKE_JOIN = MITER;
 
250
  static protected final int DEFAULT_STROKE_CAP = ROUND;
 
251
 
 
252
  /**
 
253
   * Last value set by strokeWeight() (read-only). This has a default
 
254
   * setting, rather than fighting with renderers about whether that
 
255
   * renderer supports thick lines.
 
256
   */
 
257
  public float strokeWeight = DEFAULT_STROKE_WEIGHT;
 
258
 
 
259
  /**
 
260
   * Set by strokeJoin() (read-only). This has a default setting
 
261
   * so that strokeJoin() need not be called by defaults,
 
262
   * because subclasses may not implement it (i.e. PGraphicsGL)
 
263
   */
 
264
  public int strokeJoin = DEFAULT_STROKE_JOIN;
 
265
 
 
266
  /**
 
267
   * Set by strokeCap() (read-only). This has a default setting
 
268
   * so that strokeCap() need not be called by defaults,
 
269
   * because subclasses may not implement it (i.e. PGraphicsGL)
 
270
   */
 
271
  public int strokeCap = DEFAULT_STROKE_CAP;
 
272
 
 
273
  // ........................................................
 
274
 
 
275
  // Shape placement properties
 
276
 
 
277
  // imageMode() is inherited from PImage
 
278
 
 
279
  /** The current rect mode (read-only) */
 
280
  public int rectMode;
 
281
 
 
282
  /** The current ellipse mode (read-only) */
 
283
  public int ellipseMode;
 
284
 
 
285
  /** The current shape alignment mode (read-only) */
 
286
  public int shapeMode;
 
287
 
 
288
  /** The current image alignment (read-only) */
 
289
  public int imageMode = CORNER;
 
290
 
 
291
  // ........................................................
 
292
 
 
293
  // Text and font properties
 
294
 
 
295
  /** The current text font (read-only) */
 
296
  public PFont textFont;
 
297
 
 
298
  /** The current text align (read-only) */
 
299
  public int textAlign = LEFT;
 
300
 
 
301
  /** The current vertical text alignment (read-only) */
 
302
  public int textAlignY = BASELINE;
 
303
 
 
304
  /** The current text mode (read-only) */
 
305
  public int textMode = MODEL;
 
306
 
 
307
  /** The current text size (read-only) */
 
308
  public float textSize;
 
309
 
 
310
  /** The current text leading (read-only) */
 
311
  public float textLeading;
 
312
 
 
313
  // ........................................................
 
314
 
 
315
  // Material properties
 
316
 
 
317
//  PMaterial material;
 
318
//  PMaterial[] materialStack;
 
319
//  int materialStackPointer;
 
320
 
 
321
  public float ambientR, ambientG, ambientB;
 
322
  public float specularR, specularG, specularB;
 
323
  public float emissiveR, emissiveG, emissiveB;
 
324
  public float shininess;
 
325
 
 
326
 
 
327
  // Style stack
 
328
 
 
329
  static final int STYLE_STACK_DEPTH = 64;
 
330
  PStyle[] styleStack = new PStyle[STYLE_STACK_DEPTH];
 
331
  int styleStackDepth;
 
332
 
 
333
 
 
334
  ////////////////////////////////////////////////////////////
 
335
 
 
336
 
 
337
  /** Last background color that was set, zero if an image */
 
338
  public int backgroundColor = 0xffCCCCCC;
 
339
 
 
340
  protected boolean backgroundAlpha;
 
341
  protected float backgroundR, backgroundG, backgroundB, backgroundA;
 
342
  protected int backgroundRi, backgroundGi, backgroundBi, backgroundAi;
 
343
 
 
344
  // ........................................................
 
345
 
 
346
  /**
 
347
   * Current model-view matrix transformation of the form m[row][column],
 
348
   * which is a "column vector" (as opposed to "row vector") matrix.
 
349
   */
 
350
//  PMatrix matrix;
 
351
//  public float m00, m01, m02, m03;
 
352
//  public float m10, m11, m12, m13;
 
353
//  public float m20, m21, m22, m23;
 
354
//  public float m30, m31, m32, m33;
 
355
 
 
356
//  static final int MATRIX_STACK_DEPTH = 32;
 
357
//  float[][] matrixStack = new float[MATRIX_STACK_DEPTH][16];
 
358
//  float[][] matrixInvStack = new float[MATRIX_STACK_DEPTH][16];
 
359
//  int matrixStackDepth;
 
360
 
 
361
  static final int MATRIX_STACK_DEPTH = 32;
 
362
 
 
363
  // ........................................................
 
364
 
 
365
  /**
 
366
   * Java AWT Image object associated with this renderer. For P2D and P3D,
 
367
   * this will be associated with their MemoryImageSource. For PGraphicsJava2D,
 
368
   * it will be the offscreen drawing buffer.
 
369
   */
 
370
  public Image image;
 
371
 
 
372
  // ........................................................
 
373
 
 
374
  // internal color for setting/calculating
 
375
  protected float calcR, calcG, calcB, calcA;
 
376
  protected int calcRi, calcGi, calcBi, calcAi;
 
377
  protected int calcColor;
 
378
  protected boolean calcAlpha;
 
379
 
 
380
  /** The last RGB value converted to HSB */
 
381
  int cacheHsbKey;
 
382
  /** Result of the last conversion to HSB */
 
383
  float[] cacheHsbValue = new float[3];
 
384
 
 
385
  // ........................................................
 
386
 
 
387
  /**
 
388
   * Type of shape passed to beginShape(),
 
389
   * zero if no shape is currently being drawn.
 
390
   */
 
391
  protected int shape;
 
392
 
 
393
  // vertices
 
394
  static final int DEFAULT_VERTICES = 512;
 
395
  protected float vertices[][] =
 
396
    new float[DEFAULT_VERTICES][VERTEX_FIELD_COUNT];
 
397
  protected int vertexCount; // total number of vertices
 
398
 
 
399
  // ........................................................
 
400
 
 
401
  protected boolean bezierInited = false;
 
402
  public int bezierDetail = 20;
 
403
 
 
404
  // used by both curve and bezier, so just init here
 
405
  protected PMatrix3D bezierBasisMatrix =
 
406
    new PMatrix3D(-1,  3, -3,  1,
 
407
                   3, -6,  3,  0,
 
408
                  -3,  3,  0,  0,
 
409
                   1,  0,  0,  0);
 
410
 
 
411
  //protected PMatrix3D bezierForwardMatrix;
 
412
  protected PMatrix3D bezierDrawMatrix;
 
413
 
 
414
  // ........................................................
 
415
 
 
416
  protected boolean curveInited = false;
 
417
  protected int curveDetail = 20;
 
418
  public float curveTightness = 0;
 
419
  // catmull-rom basis matrix, perhaps with optional s parameter
 
420
  protected PMatrix3D curveBasisMatrix;
 
421
  protected PMatrix3D curveDrawMatrix;
 
422
 
 
423
  protected PMatrix3D bezierBasisInverse;
 
424
  protected PMatrix3D curveToBezierMatrix;
 
425
 
 
426
  // ........................................................
 
427
 
 
428
  // spline vertices
 
429
 
 
430
  protected float curveVertices[][];
 
431
  protected int curveVertexCount;
 
432
 
 
433
  // ........................................................
 
434
 
 
435
  // precalculate sin/cos lookup tables [toxi]
 
436
  // circle resolution is determined from the actual used radii
 
437
  // passed to ellipse() method. this will automatically take any
 
438
  // scale transformations into account too
 
439
 
 
440
  // [toxi 031031]
 
441
  // changed table's precision to 0.5 degree steps
 
442
  // introduced new vars for more flexible code
 
443
  static final protected float sinLUT[];
 
444
  static final protected float cosLUT[];
 
445
  static final protected float SINCOS_PRECISION = 0.5f;
 
446
  static final protected int SINCOS_LENGTH = (int) (360f / SINCOS_PRECISION);
 
447
  static {
 
448
    sinLUT = new float[SINCOS_LENGTH];
 
449
    cosLUT = new float[SINCOS_LENGTH];
 
450
    for (int i = 0; i < SINCOS_LENGTH; i++) {
 
451
      sinLUT[i] = (float) Math.sin(i * DEG_TO_RAD * SINCOS_PRECISION);
 
452
      cosLUT[i] = (float) Math.cos(i * DEG_TO_RAD * SINCOS_PRECISION);
 
453
    }
 
454
  }
 
455
 
 
456
  // ........................................................
 
457
 
 
458
  /** The current font if a Java version of it is installed */
 
459
  //protected Font textFontNative;
 
460
 
 
461
  /** Metrics for the current native Java font */
 
462
  //protected FontMetrics textFontNativeMetrics;
 
463
 
 
464
  /** Last text position, because text often mixed on lines together */
 
465
  protected float textX, textY, textZ;
 
466
 
 
467
  /**
 
468
   * Internal buffer used by the text() functions
 
469
   * because the String object is slow
 
470
   */
 
471
  protected char[] textBuffer = new char[8 * 1024];
 
472
  protected char[] textWidthBuffer = new char[8 * 1024];
 
473
 
 
474
  protected int textBreakCount;
 
475
  protected int[] textBreakStart;
 
476
  protected int[] textBreakStop;
 
477
 
 
478
  // ........................................................
 
479
 
 
480
  public boolean edge = true;
 
481
 
 
482
  // ........................................................
 
483
 
 
484
  /// normal calculated per triangle
 
485
  static protected final int NORMAL_MODE_AUTO = 0;
 
486
  /// one normal manually specified per shape
 
487
  static protected final int NORMAL_MODE_SHAPE = 1;
 
488
  /// normals specified for each shape vertex
 
489
  static protected final int NORMAL_MODE_VERTEX = 2;
 
490
 
 
491
  /// Current mode for normals, one of AUTO, SHAPE, or VERTEX
 
492
  protected int normalMode;
 
493
 
 
494
  /// Keep track of how many calls to normal, to determine the mode.
 
495
  //protected int normalCount;
 
496
 
 
497
  /** Current normal vector. */
 
498
  public float normalX, normalY, normalZ;
 
499
 
 
500
  // ........................................................
 
501
 
 
502
  /**
 
503
   * Sets whether texture coordinates passed to
 
504
   * vertex() calls will be based on coordinates that are
 
505
   * based on the IMAGE or NORMALIZED.
 
506
   */
 
507
  public int textureMode;
 
508
 
 
509
  /**
 
510
   * Current horizontal coordinate for texture, will always
 
511
   * be between 0 and 1, even if using textureMode(IMAGE).
 
512
   */
 
513
  public float textureU;
 
514
 
 
515
  /** Current vertical coordinate for texture, see above. */
 
516
  public float textureV;
 
517
 
 
518
  /** Current image being used as a texture */
 
519
  public PImage textureImage;
 
520
 
 
521
  // ........................................................
 
522
 
 
523
  // [toxi031031] new & faster sphere code w/ support flexibile resolutions
 
524
  // will be set by sphereDetail() or 1st call to sphere()
 
525
  float sphereX[], sphereY[], sphereZ[];
 
526
 
 
527
  /// Number of U steps (aka "theta") around longitudinally spanning 2*pi
 
528
  public int sphereDetailU = 0;
 
529
  /// Number of V steps (aka "phi") along latitudinally top-to-bottom spanning pi
 
530
  public int sphereDetailV = 0;
 
531
 
 
532
 
 
533
  //////////////////////////////////////////////////////////////
 
534
 
 
535
  // INTERNAL
 
536
 
 
537
 
 
538
  /**
 
539
   * Constructor for the PGraphics object. Use this to ensure that
 
540
   * the defaults get set properly. In a subclass, use this(w, h)
 
541
   * as the first line of a subclass' constructor to properly set
 
542
   * the internal fields and defaults.
 
543
   */
 
544
  public PGraphics() {
 
545
  }
 
546
 
 
547
 
 
548
  public void setParent(PApplet parent) {  // ignore
 
549
    this.parent = parent;
 
550
  }
 
551
 
 
552
 
 
553
  /**
 
554
   * Set (or unset) this as the main drawing surface. Meaning that it can
 
555
   * safely be set to opaque (and given a default gray background), or anything
 
556
   * else that goes along with that.
 
557
   */
 
558
  public void setPrimary(boolean primary) {  // ignore
 
559
    this.primarySurface = primary;
 
560
 
 
561
    // base images must be opaque (for performance and general
 
562
    // headache reasons.. argh, a semi-transparent opengl surface?)
 
563
    // use createGraphics() if you want a transparent surface.
 
564
    if (primarySurface) {
 
565
      format = RGB;
 
566
    }
 
567
  }
 
568
 
 
569
 
 
570
  public void setPath(String path) {  // ignore
 
571
    this.path = path;
 
572
  }
 
573
 
 
574
 
 
575
  /**
 
576
   * The final step in setting up a renderer, set its size of this renderer.
 
577
   * This was formerly handled by the constructor, but instead it's been broken
 
578
   * out so that setParent/setPrimary/setPath can be handled differently.
 
579
   *
 
580
   * Important that this is ignored by preproc.pl because otherwise it will
 
581
   * override setSize() in PApplet/Applet/Component, which will 1) not call
 
582
   * super.setSize(), and 2) will cause the renderer to be resized from the
 
583
   * event thread (EDT), causing a nasty crash as it collides with the
 
584
   * animation thread.
 
585
   */
 
586
  public void setSize(int w, int h) {  // ignore
 
587
    width = w;
 
588
    height = h;
 
589
    width1 = width - 1;
 
590
    height1 = height - 1;
 
591
 
 
592
    allocate();
 
593
    reapplySettings();
 
594
  }
 
595
 
 
596
 
 
597
  /**
 
598
   * Allocate memory for this renderer. Generally will need to be implemented
 
599
   * for all renderers.
 
600
   */
 
601
  protected void allocate() { }
 
602
 
 
603
 
 
604
  /**
 
605
   * Handle any takedown for this graphics context.
 
606
   * <p>
 
607
   * This is called when a sketch is shut down and this renderer was
 
608
   * specified using the size() command, or inside endRecord() and
 
609
   * endRaw(), in order to shut things off.
 
610
   */
 
611
  public void dispose() {  // ignore
 
612
  }
 
613
 
 
614
 
 
615
 
 
616
  //////////////////////////////////////////////////////////////
 
617
 
 
618
  // FRAME
 
619
 
 
620
 
 
621
  /**
 
622
   * Some renderers have requirements re: when they are ready to draw.
 
623
   */
 
624
  public boolean canDraw() {  // ignore
 
625
    return true;
 
626
  }
 
627
 
 
628
 
 
629
  /**
 
630
   * Prepares the PGraphics for drawing.
 
631
   * <p/>
 
632
   * When creating your own PGraphics, you should call this before
 
633
   * drawing anything.
 
634
   */
 
635
  public void beginDraw() {  // ignore
 
636
  }
 
637
 
 
638
 
 
639
  /**
 
640
   * This will finalize rendering so that it can be shown on-screen.
 
641
   * <p/>
 
642
   * When creating your own PGraphics, you should call this when
 
643
   * you're finished drawing.
 
644
   */
 
645
  public void endDraw() {  // ignore
 
646
  }
 
647
 
 
648
 
 
649
  public void flush() {
 
650
    // no-op, mostly for P3D to write sorted stuff
 
651
  }
 
652
 
 
653
 
 
654
  protected void checkSettings() {
 
655
    if (!settingsInited) defaultSettings();
 
656
  }
 
657
 
 
658
 
 
659
  /**
 
660
   * Set engine's default values. This has to be called by PApplet,
 
661
   * somewhere inside setup() or draw() because it talks to the
 
662
   * graphics buffer, meaning that for subclasses like OpenGL, there
 
663
   * needs to be a valid graphics context to mess with otherwise
 
664
   * you'll get some good crashing action.
 
665
   *
 
666
   * This is currently called by checkSettings(), during beginDraw().
 
667
   */
 
668
  protected void defaultSettings() {  // ignore
 
669
//    System.out.println("PGraphics.defaultSettings() " + width + " " + height);
 
670
 
 
671
    noSmooth();  // 0149
 
672
 
 
673
    colorMode(RGB, 255);
 
674
    fill(255);
 
675
    stroke(0);
 
676
    // other stroke attributes are set in the initializers
 
677
    // inside the class (see above, strokeWeight = 1 et al)
 
678
 
 
679
    // init shape stuff
 
680
    shape = 0;
 
681
 
 
682
    // init matrices (must do before lights)
 
683
    //matrixStackDepth = 0;
 
684
 
 
685
    rectMode(CORNER);
 
686
    ellipseMode(DIAMETER);
 
687
 
 
688
    // no current font
 
689
    textFont = null;
 
690
    textSize = 12;
 
691
    textLeading = 14;
 
692
    textAlign = LEFT;
 
693
    textMode = MODEL;
 
694
 
 
695
    // if this fella is associated with an applet, then clear its background.
 
696
    // if it's been created by someone else through createGraphics,
 
697
    // they have to call background() themselves, otherwise everything gets
 
698
    // a gray background (when just a transparent surface or an empty pdf
 
699
    // is what's desired).
 
700
    // this background() call is for the Java 2D and OpenGL renderers.
 
701
    if (primarySurface) {
 
702
      //System.out.println("main drawing surface bg " + getClass().getName());
 
703
      background(backgroundColor);
 
704
    }
 
705
 
 
706
    settingsInited = true;
 
707
    // defaultSettings() overlaps reapplySettings(), don't do both
 
708
    //reapplySettings = false;
 
709
  }
 
710
 
 
711
 
 
712
  /**
 
713
   * Re-apply current settings. Some methods, such as textFont(), require that
 
714
   * their methods be called (rather than simply setting the textFont variable)
 
715
   * because they affect the graphics context, or they require parameters from
 
716
   * the context (e.g. getting native fonts for text).
 
717
   *
 
718
   * This will only be called from an allocate(), which is only called from
 
719
   * size(), which is safely called from inside beginDraw(). And it cannot be
 
720
   * called before defaultSettings(), so we should be safe.
 
721
   */
 
722
  protected void reapplySettings() {
 
723
//    System.out.println("attempting reapplySettings()");
 
724
    if (!settingsInited) return;  // if this is the initial setup, no need to reapply
 
725
 
 
726
//    System.out.println("  doing reapplySettings");
 
727
//    new Exception().printStackTrace(System.out);
 
728
 
 
729
    colorMode(colorMode, colorModeX, colorModeY, colorModeZ);
 
730
    if (fill) {
 
731
//      PApplet.println("  fill " + PApplet.hex(fillColor));
 
732
      fill(fillColor);
 
733
    } else {
 
734
      noFill();
 
735
    }
 
736
    if (stroke) {
 
737
      stroke(strokeColor);
 
738
 
 
739
      // The if() statements should be handled inside the functions,
 
740
      // otherwise an actual reset/revert won't work properly.
 
741
      //if (strokeWeight != DEFAULT_STROKE_WEIGHT) {
 
742
      strokeWeight(strokeWeight);
 
743
      //}
 
744
//      if (strokeCap != DEFAULT_STROKE_CAP) {
 
745
      strokeCap(strokeCap);
 
746
//      }
 
747
//      if (strokeJoin != DEFAULT_STROKE_JOIN) {
 
748
      strokeJoin(strokeJoin);
 
749
//      }
 
750
    } else {
 
751
      noStroke();
 
752
    }
 
753
    if (tint) {
 
754
      tint(tintColor);
 
755
    } else {
 
756
      noTint();
 
757
    }
 
758
    if (smooth) {
 
759
      smooth();
 
760
    } else {
 
761
      // Don't bother setting this, cuz it'll anger P3D.
 
762
      noSmooth();
 
763
    }
 
764
    if (textFont != null) {
 
765
//      System.out.println("  textFont in reapply is " + textFont);
 
766
      // textFont() resets the leading, so save it in case it's changed
 
767
      float saveLeading = textLeading;
 
768
      textFont(textFont, textSize);
 
769
      textLeading(saveLeading);
 
770
    }
 
771
    textMode(textMode);
 
772
    textAlign(textAlign, textAlignY);
 
773
    background(backgroundColor);
 
774
 
 
775
    //reapplySettings = false;
 
776
  }
 
777
 
 
778
 
 
779
  //////////////////////////////////////////////////////////////
 
780
 
 
781
  // HINTS
 
782
 
 
783
  /**
 
784
   * Enable a hint option.
 
785
   * <P>
 
786
   * For the most part, hints are temporary api quirks,
 
787
   * for which a proper api hasn't been properly worked out.
 
788
   * for instance SMOOTH_IMAGES existed because smooth()
 
789
   * wasn't yet implemented, but it will soon go away.
 
790
   * <P>
 
791
   * They also exist for obscure features in the graphics
 
792
   * engine, like enabling/disabling single pixel lines
 
793
   * that ignore the zbuffer, the way they do in alphabot.
 
794
   * <P>
 
795
   * Current hint options:
 
796
   * <UL>
 
797
   * <LI><TT>DISABLE_DEPTH_TEST</TT> -
 
798
   * turns off the z-buffer in the P3D or OPENGL renderers.
 
799
   * </UL>
 
800
   */
 
801
  public void hint(int which) {
 
802
    if (which > 0) {
 
803
      hints[which] = true;
 
804
    } else {
 
805
      hints[-which] = false;
 
806
    }
 
807
  }
 
808
 
 
809
 
 
810
 
 
811
  //////////////////////////////////////////////////////////////
 
812
 
 
813
  // VERTEX SHAPES
 
814
 
 
815
  /**
 
816
   * Start a new shape of type POLYGON
 
817
   */
 
818
  public void beginShape() {
 
819
    beginShape(POLYGON);
 
820
  }
 
821
 
 
822
 
 
823
  /**
 
824
   * Start a new shape.
 
825
   * <P>
 
826
   * <B>Differences between beginShape() and line() and point() methods.</B>
 
827
   * <P>
 
828
   * beginShape() is intended to be more flexible at the expense of being
 
829
   * a little more complicated to use. it handles more complicated shapes
 
830
   * that can consist of many connected lines (so you get joins) or lines
 
831
   * mixed with curves.
 
832
   * <P>
 
833
   * The line() and point() command are for the far more common cases
 
834
   * (particularly for our audience) that simply need to draw a line
 
835
   * or a point on the screen.
 
836
   * <P>
 
837
   * From the code side of things, line() may or may not call beginShape()
 
838
   * to do the drawing. In the beta code, they do, but in the alpha code,
 
839
   * they did not. they might be implemented one way or the other depending
 
840
   * on tradeoffs of runtime efficiency vs. implementation efficiency &mdash
 
841
   * meaning the speed that things run at vs. the speed it takes me to write
 
842
   * the code and maintain it. for beta, the latter is most important so
 
843
   * that's how things are implemented.
 
844
   */
 
845
  public void beginShape(int kind) {
 
846
    shape = kind;
 
847
  }
 
848
 
 
849
 
 
850
  /**
 
851
   * Sets whether the upcoming vertex is part of an edge.
 
852
   * Equivalent to glEdgeFlag(), for people familiar with OpenGL.
 
853
   */
 
854
  public void edge(boolean edge) {
 
855
   this.edge = edge;
 
856
  }
 
857
 
 
858
 
 
859
  /**
 
860
   * Sets the current normal vector. Only applies with 3D rendering
 
861
   * and inside a beginShape/endShape block.
 
862
   * <P/>
 
863
   * This is for drawing three dimensional shapes and surfaces,
 
864
   * allowing you to specify a vector perpendicular to the surface
 
865
   * of the shape, which determines how lighting affects it.
 
866
   * <P/>
 
867
   * For the most part, PGraphics3D will attempt to automatically
 
868
   * assign normals to shapes, but since that's imperfect,
 
869
   * this is a better option when you want more control.
 
870
   * <P/>
 
871
   * For people familiar with OpenGL, this function is basically
 
872
   * identical to glNormal3f().
 
873
   */
 
874
  public void normal(float nx, float ny, float nz) {
 
875
    normalX = nx;
 
876
    normalY = ny;
 
877
    normalZ = nz;
 
878
 
 
879
    // if drawing a shape and the normal hasn't been set yet,
 
880
    // then we need to set the normals for each vertex so far
 
881
    if (shape != 0) {
 
882
      if (normalMode == NORMAL_MODE_AUTO) {
 
883
        // either they set the normals, or they don't [0149]
 
884
//        for (int i = vertex_start; i < vertexCount; i++) {
 
885
//          vertices[i][NX] = normalX;
 
886
//          vertices[i][NY] = normalY;
 
887
//          vertices[i][NZ] = normalZ;
 
888
//        }
 
889
        // One normal per begin/end shape
 
890
        normalMode = NORMAL_MODE_SHAPE;
 
891
 
 
892
      } else if (normalMode == NORMAL_MODE_SHAPE) {
 
893
        // a separate normal for each vertex
 
894
        normalMode = NORMAL_MODE_VERTEX;
 
895
      }
 
896
    }
 
897
  }
 
898
 
 
899
 
 
900
  /**
 
901
   * Set texture mode to either to use coordinates based on the IMAGE
 
902
   * (more intuitive for new users) or NORMALIZED (better for advanced chaps)
 
903
   */
 
904
  public void textureMode(int mode) {
 
905
    this.textureMode = mode;
 
906
  }
 
907
 
 
908
 
 
909
  /**
 
910
   * Set texture image for current shape.
 
911
   * Needs to be called between @see beginShape and @see endShape
 
912
   *
 
913
   * @param image reference to a PImage object
 
914
   */
 
915
  public void texture(PImage image) {
 
916
    textureImage = image;
 
917
  }
 
918
 
 
919
 
 
920
  protected void vertexCheck() {
 
921
    if (vertexCount == vertices.length) {
 
922
      float temp[][] = new float[vertexCount << 1][VERTEX_FIELD_COUNT];
 
923
      System.arraycopy(vertices, 0, temp, 0, vertexCount);
 
924
      vertices = temp;
 
925
    }
 
926
  }
 
927
 
 
928
 
 
929
  public void vertex(float x, float y) {
 
930
    vertexCheck();
 
931
    float[] vertex = vertices[vertexCount];
 
932
 
 
933
    curveVertexCount = 0;
 
934
 
 
935
    vertex[X] = x;
 
936
    vertex[Y] = y;
 
937
 
 
938
    vertex[EDGE] = edge ? 1 : 0;
 
939
 
 
940
//    if (fill) {
 
941
//      vertex[R] = fillR;
 
942
//      vertex[G] = fillG;
 
943
//      vertex[B] = fillB;
 
944
//      vertex[A] = fillA;
 
945
//    }
 
946
    if (fill || textureImage != null) {
 
947
      if (textureImage == null) {
 
948
        vertex[R] = fillR;
 
949
        vertex[G] = fillG;
 
950
        vertex[B] = fillB;
 
951
        vertex[A] = fillA;
 
952
      } else {
 
953
        if (tint) {
 
954
          vertex[R] = tintR;
 
955
          vertex[G] = tintG;
 
956
          vertex[B] = tintB;
 
957
          vertex[A] = tintA;
 
958
        } else {
 
959
          vertex[R] = 1;
 
960
          vertex[G] = 1;
 
961
          vertex[B] = 1;
 
962
          vertex[A] = 1;
 
963
        }
 
964
      }
 
965
    }
 
966
 
 
967
    if (stroke) {
 
968
      vertex[SR] = strokeR;
 
969
      vertex[SG] = strokeG;
 
970
      vertex[SB] = strokeB;
 
971
      vertex[SA] = strokeA;
 
972
      vertex[SW] = strokeWeight;
 
973
    }
 
974
 
 
975
    if (textureImage != null) {
 
976
      vertex[U] = textureU;
 
977
      vertex[V] = textureV;
 
978
    }
 
979
 
 
980
    vertexCount++;
 
981
  }
 
982
 
 
983
 
 
984
  public void vertex(float x, float y, float z) {
 
985
    vertexCheck();
 
986
    float[] vertex = vertices[vertexCount];
 
987
 
 
988
    // only do this if we're using an irregular (POLYGON) shape that
 
989
    // will go through the triangulator. otherwise it'll do thinks like
 
990
    // disappear in mathematically odd ways
 
991
    // http://dev.processing.org/bugs/show_bug.cgi?id=444
 
992
    if (shape == POLYGON) {
 
993
      if (vertexCount > 0) {
 
994
        float pvertex[] = vertices[vertexCount-1];
 
995
        if ((Math.abs(pvertex[X] - x) < EPSILON) &&
 
996
            (Math.abs(pvertex[Y] - y) < EPSILON) &&
 
997
            (Math.abs(pvertex[Z] - z) < EPSILON)) {
 
998
          // this vertex is identical, don't add it,
 
999
          // because it will anger the triangulator
 
1000
          return;
 
1001
        }
 
1002
      }
 
1003
    }
 
1004
 
 
1005
    // User called vertex(), so that invalidates anything queued up for curve
 
1006
    // vertices. If this is internally called by curveVertexSegment,
 
1007
    // then curveVertexCount will be saved and restored.
 
1008
    curveVertexCount = 0;
 
1009
 
 
1010
    vertex[X] = x;
 
1011
    vertex[Y] = y;
 
1012
    vertex[Z] = z;
 
1013
 
 
1014
    vertex[EDGE] = edge ? 1 : 0;
 
1015
 
 
1016
    if (fill || textureImage != null) {
 
1017
      if (textureImage == null) {
 
1018
        vertex[R] = fillR;
 
1019
        vertex[G] = fillG;
 
1020
        vertex[B] = fillB;
 
1021
        vertex[A] = fillA;
 
1022
      } else {
 
1023
        if (tint) {
 
1024
          vertex[R] = tintR;
 
1025
          vertex[G] = tintG;
 
1026
          vertex[B] = tintB;
 
1027
          vertex[A] = tintA;
 
1028
        } else {
 
1029
          vertex[R] = 1;
 
1030
          vertex[G] = 1;
 
1031
          vertex[B] = 1;
 
1032
          vertex[A] = 1;
 
1033
        }
 
1034
      }
 
1035
 
 
1036
      vertex[AR] = ambientR;
 
1037
      vertex[AG] = ambientG;
 
1038
      vertex[AB] = ambientB;
 
1039
 
 
1040
      vertex[SPR] = specularR;
 
1041
      vertex[SPG] = specularG;
 
1042
      vertex[SPB] = specularB;
 
1043
      //vertex[SPA] = specularA;
 
1044
 
 
1045
      vertex[SHINE] = shininess;
 
1046
 
 
1047
      vertex[ER] = emissiveR;
 
1048
      vertex[EG] = emissiveG;
 
1049
      vertex[EB] = emissiveB;
 
1050
    }
 
1051
 
 
1052
    if (stroke) {
 
1053
      vertex[SR] = strokeR;
 
1054
      vertex[SG] = strokeG;
 
1055
      vertex[SB] = strokeB;
 
1056
      vertex[SA] = strokeA;
 
1057
      vertex[SW] = strokeWeight;
 
1058
    }
 
1059
 
 
1060
    if (textureImage != null) {
 
1061
      vertex[U] = textureU;
 
1062
      vertex[V] = textureV;
 
1063
    }
 
1064
 
 
1065
    vertex[NX] = normalX;
 
1066
    vertex[NY] = normalY;
 
1067
    vertex[NZ] = normalZ;
 
1068
 
 
1069
    vertex[BEEN_LIT] = 0;
 
1070
 
 
1071
    vertexCount++;
 
1072
  }
 
1073
 
 
1074
 
 
1075
  /**
 
1076
   * Used by renderer subclasses or PShape to efficiently pass in already
 
1077
   * formatted vertex information.
 
1078
   * @param v vertex parameters, as a float array of length VERTEX_FIELD_COUNT
 
1079
   */
 
1080
  public void vertex(float[] v) {
 
1081
    vertexCheck();
 
1082
    curveVertexCount = 0;
 
1083
    float[] vertex = vertices[vertexCount];
 
1084
    System.arraycopy(v, 0, vertex, 0, VERTEX_FIELD_COUNT);
 
1085
    vertexCount++;
 
1086
  }
 
1087
 
 
1088
 
 
1089
  public void vertex(float x, float y, float u, float v) {
 
1090
    vertexTexture(u, v);
 
1091
    vertex(x, y);
 
1092
  }
 
1093
 
 
1094
 
 
1095
  public void vertex(float x, float y, float z, float u, float v) {
 
1096
    vertexTexture(u, v);
 
1097
    vertex(x, y, z);
 
1098
  }
 
1099
 
 
1100
 
 
1101
  /**
 
1102
   * Internal method to copy all style information for the given vertex.
 
1103
   * Can be overridden by subclasses to handle only properties pertinent to
 
1104
   * that renderer. (e.g. no need to copy the emissive color in P2D)
 
1105
   */
 
1106
//  protected void vertexStyle() {
 
1107
//  }
 
1108
 
 
1109
 
 
1110
  /**
 
1111
   * Set (U, V) coords for the next vertex in the current shape.
 
1112
   * This is ugly as its own function, and will (almost?) always be
 
1113
   * coincident with a call to vertex. As of beta, this was moved to
 
1114
   * the protected method you see here, and called from an optional
 
1115
   * param of and overloaded vertex().
 
1116
   * <p/>
 
1117
   * The parameters depend on the current textureMode. When using
 
1118
   * textureMode(IMAGE), the coordinates will be relative to the size
 
1119
   * of the image texture, when used with textureMode(NORMAL),
 
1120
   * they'll be in the range 0..1.
 
1121
   * <p/>
 
1122
   * Used by both PGraphics2D (for images) and PGraphics3D.
 
1123
   */
 
1124
  protected void vertexTexture(float u, float v) {
 
1125
    if (textureImage == null) {
 
1126
      throw new RuntimeException("You must first call texture() before " +
 
1127
                                 "using u and v coordinates with vertex()");
 
1128
    }
 
1129
    if (textureMode == IMAGE) {
 
1130
      u /= (float) textureImage.width;
 
1131
      v /= (float) textureImage.height;
 
1132
    }
 
1133
 
 
1134
    textureU = u;
 
1135
    textureV = v;
 
1136
 
 
1137
    if (textureU < 0) textureU = 0;
 
1138
    else if (textureU > 1) textureU = 1;
 
1139
 
 
1140
    if (textureV < 0) textureV = 0;
 
1141
    else if (textureV > 1) textureV = 1;
 
1142
  }
 
1143
 
 
1144
 
 
1145
  /** This feature is in testing, do not use or rely upon its implementation */
 
1146
  public void breakShape() {
 
1147
    showWarning("This renderer cannot currently handle concave shapes, " +
 
1148
                "or shapes with holes.");
 
1149
  }
 
1150
 
 
1151
 
 
1152
  public void endShape() {
 
1153
    endShape(OPEN);
 
1154
  }
 
1155
 
 
1156
 
 
1157
  public void endShape(int mode) {
 
1158
  }
 
1159
 
 
1160
 
 
1161
 
 
1162
  //////////////////////////////////////////////////////////////
 
1163
 
 
1164
  // CURVE/BEZIER VERTEX HANDLING
 
1165
 
 
1166
 
 
1167
  protected void bezierVertexCheck() {
 
1168
    if (shape == 0 || shape != POLYGON) {
 
1169
      throw new RuntimeException("beginShape() or beginShape(POLYGON) " +
 
1170
                                 "must be used before bezierVertex()");
 
1171
    }
 
1172
    if (vertexCount == 0) {
 
1173
      throw new RuntimeException("vertex() must be used at least once" +
 
1174
                                 "before bezierVertex()");
 
1175
    }
 
1176
  }
 
1177
 
 
1178
 
 
1179
  public void bezierVertex(float x2, float y2,
 
1180
                           float x3, float y3,
 
1181
                           float x4, float y4) {
 
1182
    bezierInitCheck();
 
1183
    bezierVertexCheck();
 
1184
    PMatrix3D draw = bezierDrawMatrix;
 
1185
 
 
1186
    float[] prev = vertices[vertexCount-1];
 
1187
    float x1 = prev[X];
 
1188
    float y1 = prev[Y];
 
1189
 
 
1190
    float xplot1 = draw.m10*x1 + draw.m11*x2 + draw.m12*x3 + draw.m13*x4;
 
1191
    float xplot2 = draw.m20*x1 + draw.m21*x2 + draw.m22*x3 + draw.m23*x4;
 
1192
    float xplot3 = draw.m30*x1 + draw.m31*x2 + draw.m32*x3 + draw.m33*x4;
 
1193
 
 
1194
    float yplot1 = draw.m10*y1 + draw.m11*y2 + draw.m12*y3 + draw.m13*y4;
 
1195
    float yplot2 = draw.m20*y1 + draw.m21*y2 + draw.m22*y3 + draw.m23*y4;
 
1196
    float yplot3 = draw.m30*y1 + draw.m31*y2 + draw.m32*y3 + draw.m33*y4;
 
1197
 
 
1198
    for (int j = 0; j < bezierDetail; j++) {
 
1199
      x1 += xplot1; xplot1 += xplot2; xplot2 += xplot3;
 
1200
      y1 += yplot1; yplot1 += yplot2; yplot2 += yplot3;
 
1201
      vertex(x1, y1);
 
1202
    }
 
1203
  }
 
1204
 
 
1205
 
 
1206
  public void bezierVertex(float x2, float y2, float z2,
 
1207
                           float x3, float y3, float z3,
 
1208
                           float x4, float y4, float z4) {
 
1209
    bezierInitCheck();
 
1210
    bezierVertexCheck();
 
1211
    PMatrix3D draw = bezierDrawMatrix;
 
1212
 
 
1213
    float[] prev = vertices[vertexCount-1];
 
1214
    float x1 = prev[X];
 
1215
    float y1 = prev[Y];
 
1216
    float z1 = prev[Z];
 
1217
 
 
1218
    float xplot1 = draw.m10*x1 + draw.m11*x2 + draw.m12*x3 + draw.m13*x4;
 
1219
    float xplot2 = draw.m20*x1 + draw.m21*x2 + draw.m22*x3 + draw.m23*x4;
 
1220
    float xplot3 = draw.m30*x1 + draw.m31*x2 + draw.m32*x3 + draw.m33*x4;
 
1221
 
 
1222
    float yplot1 = draw.m10*y1 + draw.m11*y2 + draw.m12*y3 + draw.m13*y4;
 
1223
    float yplot2 = draw.m20*y1 + draw.m21*y2 + draw.m22*y3 + draw.m23*y4;
 
1224
    float yplot3 = draw.m30*y1 + draw.m31*y2 + draw.m32*y3 + draw.m33*y4;
 
1225
 
 
1226
    float zplot1 = draw.m10*z1 + draw.m11*z2 + draw.m12*z3 + draw.m13*z4;
 
1227
    float zplot2 = draw.m20*z1 + draw.m21*z2 + draw.m22*z3 + draw.m23*z4;
 
1228
    float zplot3 = draw.m30*z1 + draw.m31*z2 + draw.m32*z3 + draw.m33*z4;
 
1229
 
 
1230
    for (int j = 0; j < bezierDetail; j++) {
 
1231
      x1 += xplot1; xplot1 += xplot2; xplot2 += xplot3;
 
1232
      y1 += yplot1; yplot1 += yplot2; yplot2 += yplot3;
 
1233
      z1 += zplot1; zplot1 += zplot2; zplot2 += zplot3;
 
1234
      vertex(x1, y1, z1);
 
1235
    }
 
1236
  }
 
1237
 
 
1238
 
 
1239
  /**
 
1240
   * Perform initialization specific to curveVertex(), and handle standard
 
1241
   * error modes. Can be overridden by subclasses that need the flexibility.
 
1242
   */
 
1243
  protected void curveVertexCheck() {
 
1244
    if (shape != POLYGON) {
 
1245
      throw new RuntimeException("You must use beginShape() or " +
 
1246
                                 "beginShape(POLYGON) before curveVertex()");
 
1247
    }
 
1248
    // to improve code init time, allocate on first use.
 
1249
    if (curveVertices == null) {
 
1250
      curveVertices = new float[128][3];
 
1251
    }
 
1252
 
 
1253
    if (curveVertexCount == curveVertices.length) {
 
1254
      // Can't use PApplet.expand() cuz it doesn't do the copy properly
 
1255
      float[][] temp = new float[curveVertexCount << 1][3];
 
1256
      System.arraycopy(curveVertices, 0, temp, 0, curveVertexCount);
 
1257
      curveVertices = temp;
 
1258
    }
 
1259
    curveInitCheck();
 
1260
  }
 
1261
 
 
1262
 
 
1263
  public void curveVertex(float x, float y) {
 
1264
    curveVertexCheck();
 
1265
    float[] vertex = curveVertices[curveVertexCount];
 
1266
    vertex[X] = x;
 
1267
    vertex[Y] = y;
 
1268
    curveVertexCount++;
 
1269
 
 
1270
    // draw a segment if there are enough points
 
1271
    if (curveVertexCount > 3) {
 
1272
      curveVertexSegment(curveVertices[curveVertexCount-4][X],
 
1273
                         curveVertices[curveVertexCount-4][Y],
 
1274
                         curveVertices[curveVertexCount-3][X],
 
1275
                         curveVertices[curveVertexCount-3][Y],
 
1276
                         curveVertices[curveVertexCount-2][X],
 
1277
                         curveVertices[curveVertexCount-2][Y],
 
1278
                         curveVertices[curveVertexCount-1][X],
 
1279
                         curveVertices[curveVertexCount-1][Y]);
 
1280
    }
 
1281
  }
 
1282
 
 
1283
 
 
1284
  public void curveVertex(float x, float y, float z) {
 
1285
    curveVertexCheck();
 
1286
    float[] vertex = curveVertices[curveVertexCount];
 
1287
    vertex[X] = x;
 
1288
    vertex[Y] = y;
 
1289
    vertex[Z] = z;
 
1290
    curveVertexCount++;
 
1291
 
 
1292
    // draw a segment if there are enough points
 
1293
    if (curveVertexCount > 3) {
 
1294
      curveVertexSegment(curveVertices[curveVertexCount-4][X],
 
1295
                         curveVertices[curveVertexCount-4][Y],
 
1296
                         curveVertices[curveVertexCount-4][Z],
 
1297
                         curveVertices[curveVertexCount-3][X],
 
1298
                         curveVertices[curveVertexCount-3][Y],
 
1299
                         curveVertices[curveVertexCount-3][Z],
 
1300
                         curveVertices[curveVertexCount-2][X],
 
1301
                         curveVertices[curveVertexCount-2][Y],
 
1302
                         curveVertices[curveVertexCount-2][Z],
 
1303
                         curveVertices[curveVertexCount-1][X],
 
1304
                         curveVertices[curveVertexCount-1][Y],
 
1305
                         curveVertices[curveVertexCount-1][Z]);
 
1306
    }
 
1307
  }
 
1308
 
 
1309
 
 
1310
  /**
 
1311
   * Handle emitting a specific segment of Catmull-Rom curve. This can be
 
1312
   * overridden by subclasses that need more efficient rendering options.
 
1313
   */
 
1314
  protected void curveVertexSegment(float x1, float y1,
 
1315
                                    float x2, float y2,
 
1316
                                    float x3, float y3,
 
1317
                                    float x4, float y4) {
 
1318
    float x0 = x2;
 
1319
    float y0 = y2;
 
1320
 
 
1321
    PMatrix3D draw = curveDrawMatrix;
 
1322
 
 
1323
    float xplot1 = draw.m10*x1 + draw.m11*x2 + draw.m12*x3 + draw.m13*x4;
 
1324
    float xplot2 = draw.m20*x1 + draw.m21*x2 + draw.m22*x3 + draw.m23*x4;
 
1325
    float xplot3 = draw.m30*x1 + draw.m31*x2 + draw.m32*x3 + draw.m33*x4;
 
1326
 
 
1327
    float yplot1 = draw.m10*y1 + draw.m11*y2 + draw.m12*y3 + draw.m13*y4;
 
1328
    float yplot2 = draw.m20*y1 + draw.m21*y2 + draw.m22*y3 + draw.m23*y4;
 
1329
    float yplot3 = draw.m30*y1 + draw.m31*y2 + draw.m32*y3 + draw.m33*y4;
 
1330
 
 
1331
    // vertex() will reset splineVertexCount, so save it
 
1332
    int savedCount = curveVertexCount;
 
1333
 
 
1334
    vertex(x0, y0);
 
1335
    for (int j = 0; j < curveDetail; j++) {
 
1336
      x0 += xplot1; xplot1 += xplot2; xplot2 += xplot3;
 
1337
      y0 += yplot1; yplot1 += yplot2; yplot2 += yplot3;
 
1338
      vertex(x0, y0);
 
1339
    }
 
1340
    curveVertexCount = savedCount;
 
1341
  }
 
1342
 
 
1343
 
 
1344
  /**
 
1345
   * Handle emitting a specific segment of Catmull-Rom curve. This can be
 
1346
   * overridden by subclasses that need more efficient rendering options.
 
1347
   */
 
1348
  protected void curveVertexSegment(float x1, float y1, float z1,
 
1349
                                    float x2, float y2, float z2,
 
1350
                                    float x3, float y3, float z3,
 
1351
                                    float x4, float y4, float z4) {
 
1352
    float x0 = x2;
 
1353
    float y0 = y2;
 
1354
    float z0 = z2;
 
1355
 
 
1356
    PMatrix3D draw = curveDrawMatrix;
 
1357
 
 
1358
    float xplot1 = draw.m10*x1 + draw.m11*x2 + draw.m12*x3 + draw.m13*x4;
 
1359
    float xplot2 = draw.m20*x1 + draw.m21*x2 + draw.m22*x3 + draw.m23*x4;
 
1360
    float xplot3 = draw.m30*x1 + draw.m31*x2 + draw.m32*x3 + draw.m33*x4;
 
1361
 
 
1362
    float yplot1 = draw.m10*y1 + draw.m11*y2 + draw.m12*y3 + draw.m13*y4;
 
1363
    float yplot2 = draw.m20*y1 + draw.m21*y2 + draw.m22*y3 + draw.m23*y4;
 
1364
    float yplot3 = draw.m30*y1 + draw.m31*y2 + draw.m32*y3 + draw.m33*y4;
 
1365
 
 
1366
    // vertex() will reset splineVertexCount, so save it
 
1367
    int savedCount = curveVertexCount;
 
1368
 
 
1369
    float zplot1 = draw.m10*z1 + draw.m11*z2 + draw.m12*z3 + draw.m13*z4;
 
1370
    float zplot2 = draw.m20*z1 + draw.m21*z2 + draw.m22*z3 + draw.m23*z4;
 
1371
    float zplot3 = draw.m30*z1 + draw.m31*z2 + draw.m32*z3 + draw.m33*z4;
 
1372
 
 
1373
    vertex(x0, y0, z0);
 
1374
    for (int j = 0; j < curveDetail; j++) {
 
1375
      x0 += xplot1; xplot1 += xplot2; xplot2 += xplot3;
 
1376
      y0 += yplot1; yplot1 += yplot2; yplot2 += yplot3;
 
1377
      z0 += zplot1; zplot1 += zplot2; zplot2 += zplot3;
 
1378
      vertex(x0, y0, z0);
 
1379
    }
 
1380
    curveVertexCount = savedCount;
 
1381
  }
 
1382
 
 
1383
 
 
1384
 
 
1385
  //////////////////////////////////////////////////////////////
 
1386
 
 
1387
  // SIMPLE SHAPES WITH ANALOGUES IN beginShape()
 
1388
 
 
1389
 
 
1390
  public void point(float x, float y) {
 
1391
    beginShape(POINTS);
 
1392
    vertex(x, y);
 
1393
    endShape();
 
1394
  }
 
1395
 
 
1396
 
 
1397
  public void point(float x, float y, float z) {
 
1398
    beginShape(POINTS);
 
1399
    vertex(x, y, z);
 
1400
    endShape();
 
1401
  }
 
1402
 
 
1403
 
 
1404
  public void line(float x1, float y1, float x2, float y2) {
 
1405
    beginShape(LINES);
 
1406
    vertex(x1, y1);
 
1407
    vertex(x2, y2);
 
1408
    endShape();
 
1409
  }
 
1410
 
 
1411
 
 
1412
  public void line(float x1, float y1, float z1,
 
1413
                   float x2, float y2, float z2) {
 
1414
    beginShape(LINES);
 
1415
    vertex(x1, y1, z1);
 
1416
    vertex(x2, y2, z2);
 
1417
    endShape();
 
1418
  }
 
1419
 
 
1420
 
 
1421
  public void triangle(float x1, float y1, float x2, float y2,
 
1422
                       float x3, float y3) {
 
1423
    beginShape(TRIANGLES);
 
1424
    vertex(x1, y1);
 
1425
    vertex(x2, y2);
 
1426
    vertex(x3, y3);
 
1427
    endShape();
 
1428
  }
 
1429
 
 
1430
 
 
1431
  public void quad(float x1, float y1, float x2, float y2,
 
1432
                   float x3, float y3, float x4, float y4) {
 
1433
    beginShape(QUADS);
 
1434
    vertex(x1, y1);
 
1435
    vertex(x2, y2);
 
1436
    vertex(x3, y3);
 
1437
    vertex(x4, y4);
 
1438
    endShape();
 
1439
  }
 
1440
 
 
1441
 
 
1442
 
 
1443
  //////////////////////////////////////////////////////////////
 
1444
 
 
1445
  // RECT
 
1446
 
 
1447
 
 
1448
  public void rectMode(int mode) {
 
1449
    rectMode = mode;
 
1450
  }
 
1451
 
 
1452
 
 
1453
  public void rect(float a, float b, float c, float d) {
 
1454
    float hradius, vradius;
 
1455
    switch (rectMode) {
 
1456
    case CORNERS:
 
1457
      break;
 
1458
    case CORNER:
 
1459
      c += a; d += b;
 
1460
      break;
 
1461
    case RADIUS:
 
1462
      hradius = c;
 
1463
      vradius = d;
 
1464
      c = a + hradius;
 
1465
      d = b + vradius;
 
1466
      a -= hradius;
 
1467
      b -= vradius;
 
1468
      break;
 
1469
    case CENTER:
 
1470
      hradius = c / 2.0f;
 
1471
      vradius = d / 2.0f;
 
1472
      c = a + hradius;
 
1473
      d = b + vradius;
 
1474
      a -= hradius;
 
1475
      b -= vradius;
 
1476
    }
 
1477
 
 
1478
    if (a > c) {
 
1479
      float temp = a; a = c; c = temp;
 
1480
    }
 
1481
 
 
1482
    if (b > d) {
 
1483
      float temp = b; b = d; d = temp;
 
1484
    }
 
1485
 
 
1486
    rectImpl(a, b, c, d);
 
1487
  }
 
1488
 
 
1489
 
 
1490
  protected void rectImpl(float x1, float y1, float x2, float y2) {
 
1491
    quad(x1, y1,  x2, y1,  x2, y2,  x1, y2);
 
1492
  }
 
1493
 
 
1494
 
 
1495
 
 
1496
  //////////////////////////////////////////////////////////////
 
1497
 
 
1498
  // ELLIPSE AND ARC
 
1499
 
 
1500
 
 
1501
  public void ellipseMode(int mode) {
 
1502
    ellipseMode = mode;
 
1503
  }
 
1504
 
 
1505
 
 
1506
  public void ellipse(float a, float b, float c, float d) {
 
1507
    float x = a;
 
1508
    float y = b;
 
1509
    float w = c;
 
1510
    float h = d;
 
1511
 
 
1512
    if (ellipseMode == CORNERS) {
 
1513
      w = c - a;
 
1514
      h = d - b;
 
1515
 
 
1516
    } else if (ellipseMode == RADIUS) {
 
1517
      x = a - c;
 
1518
      y = b - d;
 
1519
      w = c * 2;
 
1520
      h = d * 2;
 
1521
 
 
1522
    } else if (ellipseMode == DIAMETER) {
 
1523
      x = a - c/2f;
 
1524
      y = b - d/2f;
 
1525
    }
 
1526
 
 
1527
    if (w < 0) {  // undo negative width
 
1528
      x += w;
 
1529
      w = -w;
 
1530
    }
 
1531
 
 
1532
    if (h < 0) {  // undo negative height
 
1533
      y += h;
 
1534
      h = -h;
 
1535
    }
 
1536
 
 
1537
    ellipseImpl(x, y, w, h);
 
1538
  }
 
1539
 
 
1540
 
 
1541
  protected void ellipseImpl(float x, float y, float w, float h) {
 
1542
  }
 
1543
 
 
1544
 
 
1545
  /**
 
1546
   * Identical parameters and placement to ellipse,
 
1547
   * but draws only an arc of that ellipse.
 
1548
   * <p/>
 
1549
   * start and stop are always radians because angleMode() was goofy.
 
1550
   * ellipseMode() sets the placement.
 
1551
   * <p/>
 
1552
   * also tries to be smart about start < stop.
 
1553
   */
 
1554
  public void arc(float a, float b, float c, float d,
 
1555
                  float start, float stop) {
 
1556
    float x = a;
 
1557
    float y = b;
 
1558
    float w = c;
 
1559
    float h = d;
 
1560
 
 
1561
    if (ellipseMode == CORNERS) {
 
1562
      w = c - a;
 
1563
      h = d - b;
 
1564
 
 
1565
    } else if (ellipseMode == RADIUS) {
 
1566
      x = a - c;
 
1567
      y = b - d;
 
1568
      w = c * 2;
 
1569
      h = d * 2;
 
1570
 
 
1571
    } else if (ellipseMode == CENTER) {
 
1572
      x = a - c/2f;
 
1573
      y = b - d/2f;
 
1574
    }
 
1575
 
 
1576
    // make sure this loop will exit before starting while
 
1577
    if (Float.isInfinite(start) || Float.isInfinite(stop)) return;
 
1578
//    while (stop < start) stop += TWO_PI;
 
1579
    if (stop < start) return;  // why bother
 
1580
    
 
1581
    // make sure that we're starting at a useful point
 
1582
    while (start < 0) {
 
1583
      start += TWO_PI;
 
1584
      stop += TWO_PI;
 
1585
    }
 
1586
 
 
1587
    if (stop - start > TWO_PI) {
 
1588
      start = 0;
 
1589
      stop = TWO_PI;
 
1590
    }
 
1591
 
 
1592
    arcImpl(x, y, w, h, start, stop);
 
1593
  }
 
1594
 
 
1595
 
 
1596
  /**
 
1597
   * Start and stop are in radians, converted by the parent function.
 
1598
   * Note that the radians can be greater (or less) than TWO_PI.
 
1599
   * This is so that an arc can be drawn that crosses zero mark,
 
1600
   * and the user will still collect $200.
 
1601
   */
 
1602
  protected void arcImpl(float x, float y, float w, float h,
 
1603
                         float start, float stop) {
 
1604
  }
 
1605
 
 
1606
 
 
1607
 
 
1608
  //////////////////////////////////////////////////////////////
 
1609
 
 
1610
  // BOX
 
1611
 
 
1612
 
 
1613
  public void box(float size) {
 
1614
    box(size, size, size);
 
1615
  }
 
1616
 
 
1617
 
 
1618
  // TODO not the least bit efficient, it even redraws lines
 
1619
  // along the vertices. ugly ugly ugly!
 
1620
  public void box(float w, float h, float d) {
 
1621
    float x1 = -w/2f; float x2 = w/2f;
 
1622
    float y1 = -h/2f; float y2 = h/2f;
 
1623
    float z1 = -d/2f; float z2 = d/2f;
 
1624
 
 
1625
    beginShape(QUADS);
 
1626
 
 
1627
    // front
 
1628
    normal(0, 0, 1);
 
1629
    vertex(x1, y1, z1);
 
1630
    vertex(x2, y1, z1);
 
1631
    vertex(x2, y2, z1);
 
1632
    vertex(x1, y2, z1);
 
1633
 
 
1634
    // right
 
1635
    normal(1, 0, 0);
 
1636
    vertex(x2, y1, z1);
 
1637
    vertex(x2, y1, z2);
 
1638
    vertex(x2, y2, z2);
 
1639
    vertex(x2, y2, z1);
 
1640
 
 
1641
    // back
 
1642
    normal(0, 0, -1);
 
1643
    vertex(x2, y1, z2);
 
1644
    vertex(x1, y1, z2);
 
1645
    vertex(x1, y2, z2);
 
1646
    vertex(x2, y2, z2);
 
1647
 
 
1648
    // left
 
1649
    normal(-1, 0, 0);
 
1650
    vertex(x1, y1, z2);
 
1651
    vertex(x1, y1, z1);
 
1652
    vertex(x1, y2, z1);
 
1653
    vertex(x1, y2, z2);
 
1654
 
 
1655
    // top
 
1656
    normal(0, 1, 0);
 
1657
    vertex(x1, y1, z2);
 
1658
    vertex(x2, y1, z2);
 
1659
    vertex(x2, y1, z1);
 
1660
    vertex(x1, y1, z1);
 
1661
 
 
1662
    // bottom
 
1663
    normal(0, -1, 0);
 
1664
    vertex(x1, y2, z1);
 
1665
    vertex(x2, y2, z1);
 
1666
    vertex(x2, y2, z2);
 
1667
    vertex(x1, y2, z2);
 
1668
 
 
1669
    endShape();
 
1670
  }
 
1671
 
 
1672
 
 
1673
 
 
1674
  //////////////////////////////////////////////////////////////
 
1675
 
 
1676
  // SPHERE
 
1677
 
 
1678
 
 
1679
  public void sphereDetail(int res) {
 
1680
    sphereDetail(res, res);
 
1681
  }
 
1682
 
 
1683
 
 
1684
  /**
 
1685
   * Set the detail level for approximating a sphere. The ures and vres params
 
1686
   * control the horizontal and vertical resolution.
 
1687
   *
 
1688
   * Code for sphereDetail() submitted by toxi [031031].
 
1689
   * Code for enhanced u/v version from davbol [080801].
 
1690
   */
 
1691
  public void sphereDetail(int ures, int vres) {
 
1692
    if (ures < 3) ures = 3; // force a minimum res
 
1693
    if (vres < 2) vres = 2; // force a minimum res
 
1694
    if ((ures == sphereDetailU) && (vres == sphereDetailV)) return;
 
1695
 
 
1696
    float delta = (float)SINCOS_LENGTH/ures;
 
1697
    float[] cx = new float[ures];
 
1698
    float[] cz = new float[ures];
 
1699
    // calc unit circle in XZ plane
 
1700
    for (int i = 0; i < ures; i++) {
 
1701
      cx[i] = cosLUT[(int) (i*delta) % SINCOS_LENGTH];
 
1702
      cz[i] = sinLUT[(int) (i*delta) % SINCOS_LENGTH];
 
1703
    }
 
1704
    // computing vertexlist
 
1705
    // vertexlist starts at south pole
 
1706
    int vertCount = ures * (vres-1) + 2;
 
1707
    int currVert = 0;
 
1708
 
 
1709
    // re-init arrays to store vertices
 
1710
    sphereX = new float[vertCount];
 
1711
    sphereY = new float[vertCount];
 
1712
    sphereZ = new float[vertCount];
 
1713
 
 
1714
    float angle_step = (SINCOS_LENGTH*0.5f)/vres;
 
1715
    float angle = angle_step;
 
1716
 
 
1717
    // step along Y axis
 
1718
    for (int i = 1; i < vres; i++) {
 
1719
      float curradius = sinLUT[(int) angle % SINCOS_LENGTH];
 
1720
      float currY = -cosLUT[(int) angle % SINCOS_LENGTH];
 
1721
      for (int j = 0; j < ures; j++) {
 
1722
        sphereX[currVert] = cx[j] * curradius;
 
1723
        sphereY[currVert] = currY;
 
1724
        sphereZ[currVert++] = cz[j] * curradius;
 
1725
      }
 
1726
      angle += angle_step;
 
1727
    }
 
1728
    sphereDetailU = ures;
 
1729
    sphereDetailV = vres;
 
1730
  }
 
1731
 
 
1732
 
 
1733
  /**
 
1734
   * Draw a sphere with radius r centered at coordinate 0, 0, 0.
 
1735
   * <P>
 
1736
   * Implementation notes:
 
1737
   * <P>
 
1738
   * cache all the points of the sphere in a static array
 
1739
   * top and bottom are just a bunch of triangles that land
 
1740
   * in the center point
 
1741
   * <P>
 
1742
   * sphere is a series of concentric circles who radii vary
 
1743
   * along the shape, based on, er.. cos or something
 
1744
   * <PRE>
 
1745
   * [toxi 031031] new sphere code. removed all multiplies with
 
1746
   * radius, as scale() will take care of that anyway
 
1747
   *
 
1748
   * [toxi 031223] updated sphere code (removed modulos)
 
1749
   * and introduced sphereAt(x,y,z,r)
 
1750
   * to avoid additional translate()'s on the user/sketch side
 
1751
   *
 
1752
   * [davbol 080801] now using separate sphereDetailU/V
 
1753
   * </PRE>
 
1754
   */
 
1755
  public void sphere(float r) {
 
1756
    if ((sphereDetailU < 3) || (sphereDetailV < 2)) {
 
1757
      sphereDetail(30);
 
1758
    }
 
1759
 
 
1760
    pushMatrix();
 
1761
    scale(r);
 
1762
    edge(false);
 
1763
 
 
1764
    // 1st ring from south pole
 
1765
    beginShape(TRIANGLE_STRIP);
 
1766
    for (int i = 0; i < sphereDetailU; i++) {
 
1767
      normal(0, -1, 0);
 
1768
      vertex(0, -1, 0);
 
1769
      normal(sphereX[i], sphereY[i], sphereZ[i]);
 
1770
      vertex(sphereX[i], sphereY[i], sphereZ[i]);
 
1771
    }
 
1772
    //normal(0, -1, 0);
 
1773
    vertex(0, -1, 0);
 
1774
    normal(sphereX[0], sphereY[0], sphereZ[0]);
 
1775
    vertex(sphereX[0], sphereY[0], sphereZ[0]);
 
1776
    endShape();
 
1777
 
 
1778
    int v1,v11,v2;
 
1779
 
 
1780
    // middle rings
 
1781
    int voff = 0;
 
1782
    for (int i = 2; i < sphereDetailV; i++) {
 
1783
      v1 = v11 = voff;
 
1784
      voff += sphereDetailU;
 
1785
      v2 = voff;
 
1786
      beginShape(TRIANGLE_STRIP);
 
1787
      for (int j = 0; j < sphereDetailU; j++) {
 
1788
        normal(sphereX[v1], sphereY[v1], sphereZ[v1]);
 
1789
        vertex(sphereX[v1], sphereY[v1], sphereZ[v1++]);
 
1790
        normal(sphereX[v2], sphereY[v2], sphereZ[v2]);
 
1791
        vertex(sphereX[v2], sphereY[v2], sphereZ[v2++]);
 
1792
      }
 
1793
      // close each ring
 
1794
      v1 = v11;
 
1795
      v2 = voff;
 
1796
      normal(sphereX[v1], sphereY[v1], sphereZ[v1]);
 
1797
      vertex(sphereX[v1], sphereY[v1], sphereZ[v1]);
 
1798
      normal(sphereX[v2], sphereY[v2], sphereZ[v2]);
 
1799
      vertex(sphereX[v2], sphereY[v2], sphereZ[v2]);
 
1800
      endShape();
 
1801
    }
 
1802
 
 
1803
    // add the northern cap
 
1804
    beginShape(TRIANGLE_STRIP);
 
1805
    for (int i = 0; i < sphereDetailU; i++) {
 
1806
      v2 = voff + i;
 
1807
      normal(sphereX[v2], sphereY[v2], sphereZ[v2]);
 
1808
      vertex(sphereX[v2], sphereY[v2], sphereZ[v2]);
 
1809
      normal(0, 1, 0);
 
1810
      vertex(0, 1, 0);
 
1811
    }
 
1812
    normal(sphereX[voff], sphereY[voff], sphereZ[voff]);
 
1813
    vertex(sphereX[voff], sphereY[voff], sphereZ[voff]);
 
1814
    normal(0, 1, 0);
 
1815
    vertex(0, 1, 0);
 
1816
    endShape();
 
1817
 
 
1818
    edge(true);
 
1819
    popMatrix();
 
1820
  }
 
1821
 
 
1822
 
 
1823
 
 
1824
  //////////////////////////////////////////////////////////////
 
1825
 
 
1826
  // BEZIER
 
1827
 
 
1828
 
 
1829
  /**
 
1830
   * Evalutes quadratic bezier at point t for points a, b, c, d.
 
1831
   * t varies between 0 and 1, and a and d are the on curve points,
 
1832
   * b and c are the control points. this can be done once with the
 
1833
   * x coordinates and a second time with the y coordinates to get
 
1834
   * the location of a bezier curve at t.
 
1835
   * <P>
 
1836
   * For instance, to convert the following example:<PRE>
 
1837
   * stroke(255, 102, 0);
 
1838
   * line(85, 20, 10, 10);
 
1839
   * line(90, 90, 15, 80);
 
1840
   * stroke(0, 0, 0);
 
1841
   * bezier(85, 20, 10, 10, 90, 90, 15, 80);
 
1842
   *
 
1843
   * // draw it in gray, using 10 steps instead of the default 20
 
1844
   * // this is a slower way to do it, but useful if you need
 
1845
   * // to do things with the coordinates at each step
 
1846
   * stroke(128);
 
1847
   * beginShape(LINE_STRIP);
 
1848
   * for (int i = 0; i <= 10; i++) {
 
1849
   *   float t = i / 10.0f;
 
1850
   *   float x = bezierPoint(85, 10, 90, 15, t);
 
1851
   *   float y = bezierPoint(20, 10, 90, 80, t);
 
1852
   *   vertex(x, y);
 
1853
   * }
 
1854
   * endShape();</PRE>
 
1855
   */
 
1856
  public float bezierPoint(float a, float b, float c, float d, float t) {
 
1857
    float t1 = 1.0f - t;
 
1858
    return a*t1*t1*t1 + 3*b*t*t1*t1 + 3*c*t*t*t1 + d*t*t*t;
 
1859
  }
 
1860
 
 
1861
 
 
1862
  /**
 
1863
   * Provide the tangent at the given point on the bezier curve.
 
1864
   * Fix from davbol for 0136.
 
1865
   */
 
1866
  public float bezierTangent(float a, float b, float c, float d, float t) {
 
1867
    return (3*t*t * (-a+3*b-3*c+d) +
 
1868
            6*t * (a-2*b+c) +
 
1869
            3 * (-a+b));
 
1870
  }
 
1871
 
 
1872
 
 
1873
  protected void bezierInitCheck() {
 
1874
    if (!bezierInited) {
 
1875
      bezierInit();
 
1876
    }
 
1877
  }
 
1878
 
 
1879
 
 
1880
  protected void bezierInit() {
 
1881
    // overkill to be broken out, but better parity with the curve stuff below
 
1882
    bezierDetail(bezierDetail);
 
1883
    bezierInited = true;
 
1884
  }
 
1885
 
 
1886
 
 
1887
  public void bezierDetail(int detail) {
 
1888
    bezierDetail = detail;
 
1889
 
 
1890
    if (bezierDrawMatrix == null) {
 
1891
      bezierDrawMatrix = new PMatrix3D();
 
1892
    }
 
1893
 
 
1894
    // setup matrix for forward differencing to speed up drawing
 
1895
    splineForward(detail, bezierDrawMatrix);
 
1896
 
 
1897
    // multiply the basis and forward diff matrices together
 
1898
    // saves much time since this needn't be done for each curve
 
1899
    //mult_spline_matrix(bezierForwardMatrix, bezier_basis, bezierDrawMatrix, 4);
 
1900
    //bezierDrawMatrix.set(bezierForwardMatrix);
 
1901
    bezierDrawMatrix.apply(bezierBasisMatrix);
 
1902
  }
 
1903
 
 
1904
 
 
1905
  /**
 
1906
   * Draw a cubic bezier curve. The first and last points are
 
1907
   * the on-curve points. The middle two are the 'control' points,
 
1908
   * or 'handles' in an application like Illustrator.
 
1909
   * <P>
 
1910
   * Identical to typing:
 
1911
   * <PRE>beginShape();
 
1912
   * vertex(x1, y1);
 
1913
   * bezierVertex(x2, y2, x3, y3, x4, y4);
 
1914
   * endShape();
 
1915
   * </PRE>
 
1916
   * In Postscript-speak, this would be:
 
1917
   * <PRE>moveto(x1, y1);
 
1918
   * curveto(x2, y2, x3, y3, x4, y4);</PRE>
 
1919
   * If you were to try and continue that curve like so:
 
1920
   * <PRE>curveto(x5, y5, x6, y6, x7, y7);</PRE>
 
1921
   * This would be done in processing by adding these statements:
 
1922
   * <PRE>bezierVertex(x5, y5, x6, y6, x7, y7)
 
1923
   * </PRE>
 
1924
   * To draw a quadratic (instead of cubic) curve,
 
1925
   * use the control point twice by doubling it:
 
1926
   * <PRE>bezier(x1, y1, cx, cy, cx, cy, x2, y2);</PRE>
 
1927
   */
 
1928
  public void bezier(float x1, float y1,
 
1929
                     float x2, float y2,
 
1930
                     float x3, float y3,
 
1931
                     float x4, float y4) {
 
1932
    beginShape();
 
1933
    vertex(x1, y1);
 
1934
    bezierVertex(x2, y2, x3, y3, x4, y4);
 
1935
    endShape();
 
1936
  }
 
1937
 
 
1938
 
 
1939
  public void bezier(float x1, float y1, float z1,
 
1940
                     float x2, float y2, float z2,
 
1941
                     float x3, float y3, float z3,
 
1942
                     float x4, float y4, float z4) {
 
1943
    beginShape();
 
1944
    vertex(x1, y1, z1);
 
1945
    bezierVertex(x2, y2, z2,
 
1946
                 x3, y3, z3,
 
1947
                 x4, y4, z4);
 
1948
    endShape();
 
1949
  }
 
1950
 
 
1951
 
 
1952
 
 
1953
  //////////////////////////////////////////////////////////////
 
1954
 
 
1955
  // CATMULL-ROM CURVE
 
1956
 
 
1957
 
 
1958
  /**
 
1959
   * Get a location along a catmull-rom curve segment.
 
1960
   *
 
1961
   * @param t Value between zero and one for how far along the segment
 
1962
   */
 
1963
  public float curvePoint(float a, float b, float c, float d, float t) {
 
1964
    curveInitCheck();
 
1965
 
 
1966
    float tt = t * t;
 
1967
    float ttt = t * tt;
 
1968
    PMatrix3D cb = curveBasisMatrix;
 
1969
 
 
1970
    // not optimized (and probably need not be)
 
1971
    return (a * (ttt*cb.m00 + tt*cb.m10 + t*cb.m20 + cb.m30) +
 
1972
            b * (ttt*cb.m01 + tt*cb.m11 + t*cb.m21 + cb.m31) +
 
1973
            c * (ttt*cb.m02 + tt*cb.m12 + t*cb.m22 + cb.m32) +
 
1974
            d * (ttt*cb.m03 + tt*cb.m13 + t*cb.m23 + cb.m33));
 
1975
  }
 
1976
 
 
1977
 
 
1978
  /**
 
1979
   * Calculate the tangent at a t value (0..1) on a Catmull-Rom curve.
 
1980
   * Code thanks to Dave Bollinger (Bug #715)
 
1981
   */
 
1982
  public float curveTangent(float a, float b, float c, float d, float t) {
 
1983
    curveInitCheck();
 
1984
 
 
1985
    float tt3 = t * t * 3;
 
1986
    float t2 = t * 2;
 
1987
    PMatrix3D cb = curveBasisMatrix;
 
1988
 
 
1989
    // not optimized (and probably need not be)
 
1990
    return (a * (tt3*cb.m00 + t2*cb.m10 + cb.m20) +
 
1991
            b * (tt3*cb.m01 + t2*cb.m11 + cb.m21) +
 
1992
            c * (tt3*cb.m02 + t2*cb.m12 + cb.m22) +
 
1993
            d * (tt3*cb.m03 + t2*cb.m13 + cb.m23) );
 
1994
  }
 
1995
 
 
1996
 
 
1997
  public void curveDetail(int detail) {
 
1998
    curveDetail = detail;
 
1999
    curveInit();
 
2000
  }
 
2001
 
 
2002
 
 
2003
  public void curveTightness(float tightness) {
 
2004
    curveTightness = tightness;
 
2005
    curveInit();
 
2006
  }
 
2007
 
 
2008
 
 
2009
  protected void curveInitCheck() {
 
2010
    if (!curveInited) {
 
2011
      curveInit();
 
2012
    }
 
2013
  }
 
2014
 
 
2015
 
 
2016
  /**
 
2017
   * Set the number of segments to use when drawing a Catmull-Rom
 
2018
   * curve, and setting the s parameter, which defines how tightly
 
2019
   * the curve fits to each vertex. Catmull-Rom curves are actually
 
2020
   * a subset of this curve type where the s is set to zero.
 
2021
   * <P>
 
2022
   * (This function is not optimized, since it's not expected to
 
2023
   * be called all that often. there are many juicy and obvious
 
2024
   * opimizations in here, but it's probably better to keep the
 
2025
   * code more readable)
 
2026
   */
 
2027
  protected void curveInit() {
 
2028
    // allocate only if/when used to save startup time
 
2029
    if (curveDrawMatrix == null) {
 
2030
      curveBasisMatrix = new PMatrix3D();
 
2031
      curveDrawMatrix = new PMatrix3D();
 
2032
      curveInited = true;
 
2033
    }
 
2034
 
 
2035
    float s = curveTightness;
 
2036
    curveBasisMatrix.set((s-1)/2f, (s+3)/2f,  (-3-s)/2f, (1-s)/2f,
 
2037
                         (1-s),    (-5-s)/2f, (s+2),     (s-1)/2f,
 
2038
                         (s-1)/2f, 0,         (1-s)/2f,  0,
 
2039
                         0,        1,         0,         0);
 
2040
 
 
2041
    //setup_spline_forward(segments, curveForwardMatrix);
 
2042
    splineForward(curveDetail, curveDrawMatrix);
 
2043
 
 
2044
    if (bezierBasisInverse == null) {
 
2045
      bezierBasisInverse = bezierBasisMatrix.get();
 
2046
      bezierBasisInverse.invert();
 
2047
      curveToBezierMatrix = new PMatrix3D();
 
2048
    }
 
2049
 
 
2050
    // TODO only needed for PGraphicsJava2D? if so, move it there
 
2051
    // actually, it's generally useful for other renderers, so keep it
 
2052
    // or hide the implementation elsewhere.
 
2053
    curveToBezierMatrix.set(curveBasisMatrix);
 
2054
    curveToBezierMatrix.preApply(bezierBasisInverse);
 
2055
 
 
2056
    // multiply the basis and forward diff matrices together
 
2057
    // saves much time since this needn't be done for each curve
 
2058
    curveDrawMatrix.apply(curveBasisMatrix);
 
2059
  }
 
2060
 
 
2061
 
 
2062
  /**
 
2063
   * Draws a segment of Catmull-Rom curve.
 
2064
   * <P>
 
2065
   * As of 0070, this function no longer doubles the first and
 
2066
   * last points. The curves are a bit more boring, but it's more
 
2067
   * mathematically correct, and properly mirrored in curvePoint().
 
2068
   * <P>
 
2069
   * Identical to typing out:<PRE>
 
2070
   * beginShape();
 
2071
   * curveVertex(x1, y1);
 
2072
   * curveVertex(x2, y2);
 
2073
   * curveVertex(x3, y3);
 
2074
   * curveVertex(x4, y4);
 
2075
   * endShape();
 
2076
   * </PRE>
 
2077
   */
 
2078
  public void curve(float x1, float y1,
 
2079
                    float x2, float y2,
 
2080
                    float x3, float y3,
 
2081
                    float x4, float y4) {
 
2082
    beginShape();
 
2083
    curveVertex(x1, y1);
 
2084
    curveVertex(x2, y2);
 
2085
    curveVertex(x3, y3);
 
2086
    curveVertex(x4, y4);
 
2087
    endShape();
 
2088
  }
 
2089
 
 
2090
 
 
2091
  public void curve(float x1, float y1, float z1,
 
2092
                    float x2, float y2, float z2,
 
2093
                    float x3, float y3, float z3,
 
2094
                    float x4, float y4, float z4) {
 
2095
    beginShape();
 
2096
    curveVertex(x1, y1, z1);
 
2097
    curveVertex(x2, y2, z2);
 
2098
    curveVertex(x3, y3, z3);
 
2099
    curveVertex(x4, y4, z4);
 
2100
    endShape();
 
2101
  }
 
2102
 
 
2103
 
 
2104
 
 
2105
  //////////////////////////////////////////////////////////////
 
2106
 
 
2107
  // SPLINE UTILITY FUNCTIONS (used by both Bezier and Catmull-Rom)
 
2108
 
 
2109
 
 
2110
  /**
 
2111
   * Setup forward-differencing matrix to be used for speedy
 
2112
   * curve rendering. It's based on using a specific number
 
2113
   * of curve segments and just doing incremental adds for each
 
2114
   * vertex of the segment, rather than running the mathematically
 
2115
   * expensive cubic equation.
 
2116
   * @param segments number of curve segments to use when drawing
 
2117
   * @param matrix target object for the new matrix
 
2118
   */
 
2119
  protected void splineForward(int segments, PMatrix3D matrix) {
 
2120
    float f  = 1.0f / segments;
 
2121
    float ff = f * f;
 
2122
    float fff = ff * f;
 
2123
 
 
2124
    matrix.set(0,     0,    0, 1,
 
2125
               fff,   ff,   f, 0,
 
2126
               6*fff, 2*ff, 0, 0,
 
2127
               6*fff, 0,    0, 0);
 
2128
  }
 
2129
 
 
2130
 
 
2131
 
 
2132
  //////////////////////////////////////////////////////////////
 
2133
 
 
2134
  // SMOOTHING
 
2135
 
 
2136
 
 
2137
  /**
 
2138
   * If true in PImage, use bilinear interpolation for copy()
 
2139
   * operations. When inherited by PGraphics, also controls shapes.
 
2140
   */
 
2141
  public void smooth() {
 
2142
    smooth = true;
 
2143
  }
 
2144
 
 
2145
 
 
2146
  /**
 
2147
   * Disable smoothing. See smooth().
 
2148
   */
 
2149
  public void noSmooth() {
 
2150
    smooth = false;
 
2151
  }
 
2152
 
 
2153
 
 
2154
 
 
2155
  //////////////////////////////////////////////////////////////
 
2156
 
 
2157
  // IMAGE
 
2158
 
 
2159
 
 
2160
  /**
 
2161
   * The mode can only be set to CORNERS, CORNER, and CENTER.
 
2162
   * <p/>
 
2163
   * Support for CENTER was added in release 0146.
 
2164
   */
 
2165
  public void imageMode(int mode) {
 
2166
    if ((mode == CORNER) || (mode == CORNERS) || (mode == CENTER)) {
 
2167
      imageMode = mode;
 
2168
    } else {
 
2169
      String msg =
 
2170
        "imageMode() only works with CORNER, CORNERS, or CENTER";
 
2171
      throw new RuntimeException(msg);
 
2172
    }
 
2173
  }
 
2174
 
 
2175
 
 
2176
  public void image(PImage image, float x, float y) {
 
2177
    // Starting in release 0144, image errors are simply ignored.
 
2178
    // loadImageAsync() sets width and height to -1 when loading fails.
 
2179
    if (image.width == -1 || image.height == -1) return;
 
2180
 
 
2181
    if (imageMode == CORNER || imageMode == CORNERS) {
 
2182
      imageImpl(image,
 
2183
                x, y, x+image.width, y+image.height,
 
2184
                0, 0, image.width, image.height);
 
2185
 
 
2186
    } else if (imageMode == CENTER) {
 
2187
      float x1 = x - image.width/2;
 
2188
      float y1 = y - image.height/2;
 
2189
      imageImpl(image,
 
2190
                x1, y1, x1+image.width, y1+image.height,
 
2191
                0, 0, image.width, image.height);
 
2192
    }
 
2193
  }
 
2194
 
 
2195
 
 
2196
  public void image(PImage image, float x, float y, float c, float d) {
 
2197
    image(image, x, y, c, d, 0, 0, image.width, image.height);
 
2198
  }
 
2199
 
 
2200
 
 
2201
  /**
 
2202
   * Draw an image(), also specifying u/v coordinates.
 
2203
   * In this method, the  u, v coordinates are always based on image space 
 
2204
   * location, regardless of the current textureMode().
 
2205
   */
 
2206
  public void image(PImage image,
 
2207
                    float a, float b, float c, float d,
 
2208
                    int u1, int v1, int u2, int v2) {
 
2209
    // Starting in release 0144, image errors are simply ignored.
 
2210
    // loadImageAsync() sets width and height to -1 when loading fails.
 
2211
    if (image.width == -1 || image.height == -1) return;
 
2212
 
 
2213
    if (imageMode == CORNER) {
 
2214
      if (c < 0) {  // reset a negative width
 
2215
        a += c; c = -c;
 
2216
      }
 
2217
      if (d < 0) {  // reset a negative height
 
2218
        b += d; d = -d;
 
2219
      }
 
2220
 
 
2221
      imageImpl(image,
 
2222
                a, b, a + c, b + d,
 
2223
                u1, v1, u2, v2);
 
2224
 
 
2225
    } else if (imageMode == CORNERS) {
 
2226
      if (c < a) {  // reverse because x2 < x1
 
2227
        float temp = a; a = c; c = temp;
 
2228
      }
 
2229
      if (d < b) {  // reverse because y2 < y1
 
2230
        float temp = b; b = d; d = temp;
 
2231
      }
 
2232
 
 
2233
      imageImpl(image,
 
2234
                a, b, c, d,
 
2235
                u1, v1, u2, v2);
 
2236
 
 
2237
    } else if (imageMode == CENTER) {
 
2238
      // c and d are width/height
 
2239
      if (c < 0) c = -c;
 
2240
      if (d < 0) d = -d;
 
2241
      float x1 = a - c/2;
 
2242
      float y1 = b - d/2;
 
2243
 
 
2244
      imageImpl(image,
 
2245
                x1, y1, x1 + c, y1 + d,
 
2246
                u1, v1, u2, v2);
 
2247
    }
 
2248
  }
 
2249
 
 
2250
 
 
2251
  /**
 
2252
   * Expects x1, y1, x2, y2 coordinates where (x2 >= x1) and (y2 >= y1).
 
2253
   * If tint() has been called, the image will be colored.
 
2254
   * <p/>
 
2255
   * The default implementation draws an image as a textured quad.
 
2256
   * The (u, v) coordinates are in image space (they're ints, after all..)
 
2257
   */
 
2258
  protected void imageImpl(PImage image,
 
2259
                           float x1, float y1, float x2, float y2,
 
2260
                           int u1, int v1, int u2, int v2) {
 
2261
    boolean savedStroke = stroke;
 
2262
//    boolean savedFill = fill;
 
2263
    int savedTextureMode = textureMode;
 
2264
 
 
2265
    stroke = false;
 
2266
//    fill = true;
 
2267
    textureMode = IMAGE;
 
2268
 
 
2269
//    float savedFillR = fillR;
 
2270
//    float savedFillG = fillG;
 
2271
//    float savedFillB = fillB;
 
2272
//    float savedFillA = fillA;
 
2273
//
 
2274
//    if (tint) {
 
2275
//      fillR = tintR;
 
2276
//      fillG = tintG;
 
2277
//      fillB = tintB;
 
2278
//      fillA = tintA;
 
2279
//
 
2280
//    } else {
 
2281
//      fillR = 1;
 
2282
//      fillG = 1;
 
2283
//      fillB = 1;
 
2284
//      fillA = 1;
 
2285
//    }
 
2286
 
 
2287
    beginShape(QUADS);
 
2288
    texture(image);
 
2289
    vertex(x1, y1, u1, v1);
 
2290
    vertex(x1, y2, u1, v2);
 
2291
    vertex(x2, y2, u2, v2);
 
2292
    vertex(x2, y1, u2, v1);
 
2293
    endShape();
 
2294
 
 
2295
    stroke = savedStroke;
 
2296
//    fill = savedFill;
 
2297
    textureMode = savedTextureMode;
 
2298
 
 
2299
//    fillR = savedFillR;
 
2300
//    fillG = savedFillG;
 
2301
//    fillB = savedFillB;
 
2302
//    fillA = savedFillA;
 
2303
  }
 
2304
 
 
2305
 
 
2306
 
 
2307
  //////////////////////////////////////////////////////////////
 
2308
 
 
2309
  // SHAPE
 
2310
 
 
2311
 
 
2312
  /**
 
2313
   * Set the orientation for the shape() command (like imageMode() or rectMode()).
 
2314
   * @param mode Either CORNER, CORNERS, or CENTER.
 
2315
   */
 
2316
  public void shapeMode(int mode) {
 
2317
    this.shapeMode = mode;
 
2318
  }
 
2319
 
 
2320
 
 
2321
  public void shape(PShape shape) {
 
2322
    if (shape.isVisible()) {  // don't do expensive matrix ops if invisible
 
2323
      if (shapeMode == CENTER) {
 
2324
        pushMatrix();
 
2325
        translate(-shape.getWidth()/2, -shape.getHeight()/2);
 
2326
      }
 
2327
 
 
2328
      shape.draw(this); // needs to handle recorder too
 
2329
 
 
2330
      if (shapeMode == CENTER) {
 
2331
        popMatrix();
 
2332
      }
 
2333
    }
 
2334
  }
 
2335
 
 
2336
 
 
2337
  /**
 
2338
   * Convenience method to draw at a particular location.
 
2339
   */
 
2340
  public void shape(PShape shape, float x, float y) {
 
2341
    if (shape.isVisible()) {  // don't do expensive matrix ops if invisible
 
2342
      pushMatrix();
 
2343
 
 
2344
      if (shapeMode == CENTER) {
 
2345
        translate(x - shape.getWidth()/2, y - shape.getHeight()/2);
 
2346
 
 
2347
      } else if ((shapeMode == CORNER) || (shapeMode == CORNERS)) {
 
2348
        translate(x, y);
 
2349
      }
 
2350
      shape.draw(this);
 
2351
 
 
2352
      popMatrix();
 
2353
    }
 
2354
  }
 
2355
 
 
2356
 
 
2357
  public void shape(PShape shape, float x, float y, float c, float d) {
 
2358
    if (shape.isVisible()) {  // don't do expensive matrix ops if invisible
 
2359
      pushMatrix();
 
2360
 
 
2361
      if (shapeMode == CENTER) {
 
2362
        // x and y are center, c and d refer to a diameter
 
2363
        translate(x - c/2f, y - d/2f);
 
2364
        scale(c / shape.getWidth(), d / shape.getHeight());
 
2365
 
 
2366
      } else if (shapeMode == CORNER) {
 
2367
        translate(x, y);
 
2368
        scale(c / shape.getWidth(), d / shape.getHeight());
 
2369
 
 
2370
      } else if (shapeMode == CORNERS) {
 
2371
        // c and d are x2/y2, make them into width/height
 
2372
        c -= x;
 
2373
        d -= y;
 
2374
        // then same as above
 
2375
        translate(x, y);
 
2376
        scale(c / shape.getWidth(), d / shape.getHeight());
 
2377
      }
 
2378
      shape.draw(this);
 
2379
 
 
2380
      popMatrix();
 
2381
    }
 
2382
  }
 
2383
 
 
2384
 
 
2385
 
 
2386
  //////////////////////////////////////////////////////////////
 
2387
 
 
2388
  // TEXT/FONTS
 
2389
 
 
2390
 
 
2391
  /**
 
2392
   * Sets the alignment of the text to one of LEFT, CENTER, or RIGHT.
 
2393
   * This will also reset the vertical text alignment to BASELINE.
 
2394
   */
 
2395
  public void textAlign(int align) {
 
2396
    textAlign(align, BASELINE);
 
2397
  }
 
2398
 
 
2399
 
 
2400
  /**
 
2401
   * Sets the horizontal and vertical alignment of the text. The horizontal
 
2402
   * alignment can be one of LEFT, CENTER, or RIGHT. The vertical alignment
 
2403
   * can be TOP, BOTTOM, CENTER, or the BASELINE (the default).
 
2404
   */
 
2405
  public void textAlign(int alignX, int alignY) {
 
2406
    textAlign = alignX;
 
2407
    textAlignY = alignY;
 
2408
  }
 
2409
 
 
2410
 
 
2411
  /**
 
2412
   * Returns the ascent of the current font at the current size.
 
2413
   * This is a method, rather than a variable inside the PGraphics object
 
2414
   * because it requires calculation.
 
2415
   */
 
2416
  public float textAscent() {
 
2417
    if (textFont == null) {
 
2418
      showTextFontException("textAscent");
 
2419
    }
 
2420
    return textFont.ascent() * ((textMode == SCREEN) ? textFont.size : textSize);
 
2421
  }
 
2422
 
 
2423
 
 
2424
  /**
 
2425
   * Returns the descent of the current font at the current size.
 
2426
   * This is a method, rather than a variable inside the PGraphics object
 
2427
   * because it requires calculation.
 
2428
   */
 
2429
  public float textDescent() {
 
2430
    if (textFont == null) {
 
2431
      showTextFontException("textDescent");
 
2432
    }
 
2433
    return textFont.descent() * ((textMode == SCREEN) ? textFont.size : textSize);
 
2434
  }
 
2435
 
 
2436
 
 
2437
  /**
 
2438
   * Sets the current font. The font's size will be the "natural"
 
2439
   * size of this font (the size that was set when using "Create Font").
 
2440
   * The leading will also be reset.
 
2441
   */
 
2442
  public void textFont(PFont which) {
 
2443
    if (which != null) {
 
2444
      textFont = which;
 
2445
      if (hints[ENABLE_NATIVE_FONTS]) {
 
2446
        //if (which.font == null) {
 
2447
        which.findFont();
 
2448
        //}
 
2449
      }
 
2450
      /*
 
2451
      textFontNative = which.font;
 
2452
 
 
2453
      //textFontNativeMetrics = null;
 
2454
      // changed for rev 0104 for textMode(SHAPE) in opengl
 
2455
      if (textFontNative != null) {
 
2456
        // TODO need a better way to handle this. could use reflection to get
 
2457
        // rid of the warning, but that'd be a little silly. supporting this is
 
2458
        // an artifact of supporting java 1.1, otherwise we'd use getLineMetrics,
 
2459
        // as recommended by the @deprecated flag.
 
2460
        textFontNativeMetrics =
 
2461
          Toolkit.getDefaultToolkit().getFontMetrics(textFontNative);
 
2462
        // The following is what needs to be done, however we need to be able
 
2463
        // to get the actual graphics context where the drawing is happening.
 
2464
        // For instance, parent.getGraphics() doesn't work for OpenGL since
 
2465
        // an OpenGL drawing surface is an embedded component.
 
2466
//        if (parent != null) {
 
2467
//          textFontNativeMetrics = parent.getGraphics().getFontMetrics(textFontNative);
 
2468
//        }
 
2469
 
 
2470
        // float w = font.getStringBounds(text, g2.getFontRenderContext()).getWidth();
 
2471
      }
 
2472
      */
 
2473
      textSize(which.size);
 
2474
 
 
2475
    } else {
 
2476
      throw new RuntimeException(ERROR_TEXTFONT_NULL_PFONT);
 
2477
    }
 
2478
  }
 
2479
 
 
2480
 
 
2481
  /**
 
2482
   * Useful function to set the font and size at the same time.
 
2483
   */
 
2484
  public void textFont(PFont which, float size) {
 
2485
    textFont(which);
 
2486
    textSize(size);
 
2487
  }
 
2488
 
 
2489
 
 
2490
  /**
 
2491
   * Set the text leading to a specific value. If using a custom
 
2492
   * value for the text leading, you'll have to call textLeading()
 
2493
   * again after any calls to textSize().
 
2494
   */
 
2495
  public void textLeading(float leading) {
 
2496
    textLeading = leading;
 
2497
  }
 
2498
 
 
2499
 
 
2500
  /**
 
2501
   * Sets the text rendering/placement to be either SCREEN (direct
 
2502
   * to the screen, exact coordinates, only use the font's original size)
 
2503
   * or MODEL (the default, where text is manipulated by translate() and
 
2504
   * can have a textSize). The text size cannot be set when using
 
2505
   * textMode(SCREEN), because it uses the pixels directly from the font.
 
2506
   */
 
2507
  public void textMode(int mode) {
 
2508
    // CENTER and MODEL overlap (they're both 3)
 
2509
    if ((mode == LEFT) || (mode == RIGHT)) {
 
2510
      showWarning("Since Processing beta, textMode() is now textAlign().");
 
2511
      return;
 
2512
    }
 
2513
//    if ((mode != SCREEN) && (mode != MODEL)) {
 
2514
//      showError("Only textMode(SCREEN) and textMode(MODEL) " +
 
2515
//      "are available with this renderer.");
 
2516
//    }
 
2517
 
 
2518
    if (textModeCheck(mode)) {
 
2519
      textMode = mode;
 
2520
    } else {
 
2521
      String modeStr = String.valueOf(mode);
 
2522
      switch (mode) {
 
2523
        case SCREEN: modeStr = "SCREEN"; break;
 
2524
        case MODEL: modeStr = "MODEL"; break;
 
2525
        case SHAPE: modeStr = "SHAPE"; break;
 
2526
      }
 
2527
      showWarning("textMode(" + modeStr + ") is not supported by this renderer.");
 
2528
    }
 
2529
 
 
2530
    // reset the font to its natural size
 
2531
    // (helps with width calculations and all that)
 
2532
    //if (textMode == SCREEN) {
 
2533
    //textSize(textFont.size);
 
2534
    //}
 
2535
 
 
2536
    //} else {
 
2537
    //throw new RuntimeException("use textFont() before textMode()");
 
2538
    //}
 
2539
  }
 
2540
 
 
2541
 
 
2542
  protected boolean textModeCheck(int mode) {
 
2543
    return true;
 
2544
  }
 
2545
 
 
2546
 
 
2547
  /**
 
2548
   * Sets the text size, also resets the value for the leading.
 
2549
   */
 
2550
  public void textSize(float size) {
 
2551
    if (textFont != null) {
 
2552
//      if ((textMode == SCREEN) && (size != textFont.size)) {
 
2553
//        throw new RuntimeException("textSize() is ignored with " +
 
2554
//                                   "textMode(SCREEN)");
 
2555
//      }
 
2556
      textSize = size;
 
2557
      textLeading = (textAscent() + textDescent()) * 1.275f;
 
2558
 
 
2559
    } else {
 
2560
      showTextFontException("textSize");
 
2561
    }
 
2562
  }
 
2563
 
 
2564
 
 
2565
  // ........................................................
 
2566
 
 
2567
 
 
2568
  public float textWidth(char c) {
 
2569
    textWidthBuffer[0] = c;
 
2570
    return textWidthImpl(textWidthBuffer, 0, 1);
 
2571
  }
 
2572
 
 
2573
 
 
2574
  /**
 
2575
   * Return the width of a line of text. If the text has multiple
 
2576
   * lines, this returns the length of the longest line.
 
2577
   */
 
2578
  public float textWidth(String str) {
 
2579
    if (textFont == null) {
 
2580
      showTextFontException("textWidth");
 
2581
    }
 
2582
 
 
2583
    int length = str.length();
 
2584
    if (length > textWidthBuffer.length) {
 
2585
      textWidthBuffer = new char[length + 10];
 
2586
    }
 
2587
    str.getChars(0, length, textWidthBuffer, 0);
 
2588
 
 
2589
    float wide = 0;
 
2590
    int index = 0;
 
2591
    int start = 0;
 
2592
 
 
2593
    while (index < length) {
 
2594
      if (textWidthBuffer[index] == '\n') {
 
2595
        wide = Math.max(wide, textWidthImpl(textWidthBuffer, start, index));
 
2596
        start = index+1;
 
2597
      }
 
2598
      index++;
 
2599
    }
 
2600
    if (start < length) {
 
2601
      wide = Math.max(wide, textWidthImpl(textWidthBuffer, start, index));
 
2602
    }
 
2603
    return wide;
 
2604
  }
 
2605
 
 
2606
 
 
2607
  /** 
 
2608
   * TODO not sure if this stays...
 
2609
   */
 
2610
  public float textWidth(char[] chars, int start, int length) {
 
2611
    return textWidthImpl(chars, start, start + length);
 
2612
  }
 
2613
  
 
2614
  
 
2615
  /**
 
2616
   * Implementation of returning the text width of
 
2617
   * the chars [start, stop) in the buffer.
 
2618
   * Unlike the previous version that was inside PFont, this will
 
2619
   * return the size not of a 1 pixel font, but the actual current size.
 
2620
   */
 
2621
  protected float textWidthImpl(char buffer[], int start, int stop) {
 
2622
    float wide = 0;
 
2623
    for (int i = start; i < stop; i++) {
 
2624
      // could add kerning here, but it just ain't implemented
 
2625
      wide += textFont.width(buffer[i]) * textSize;
 
2626
    }
 
2627
    return wide;
 
2628
  }
 
2629
 
 
2630
 
 
2631
  // ........................................................
 
2632
 
 
2633
 
 
2634
  /**
 
2635
   * Write text where we just left off.
 
2636
   */
 
2637
  public void text(char c) {
 
2638
    text(c, textX, textY, textZ);
 
2639
  }
 
2640
 
 
2641
 
 
2642
  /**
 
2643
   * Draw a single character on screen.
 
2644
   * Extremely slow when used with textMode(SCREEN) and Java 2D,
 
2645
   * because loadPixels has to be called first and updatePixels last.
 
2646
   */
 
2647
  public void text(char c, float x, float y) {
 
2648
    if (textFont == null) {
 
2649
      showTextFontException("text");
 
2650
    }
 
2651
 
 
2652
    if (textMode == SCREEN) loadPixels();
 
2653
 
 
2654
    if (textAlignY == CENTER) {
 
2655
      y += textAscent() / 2;
 
2656
    } else if (textAlignY == TOP) {
 
2657
      y += textAscent();
 
2658
    } else if (textAlignY == BOTTOM) {
 
2659
      y -= textDescent();
 
2660
    //} else if (textAlignY == BASELINE) {
 
2661
      // do nothing
 
2662
    }
 
2663
 
 
2664
    textBuffer[0] = c;
 
2665
    textLineAlignImpl(textBuffer, 0, 1, x, y);
 
2666
 
 
2667
    if (textMode == SCREEN) updatePixels();
 
2668
  }
 
2669
 
 
2670
 
 
2671
  /**
 
2672
   * Draw a single character on screen (with a z coordinate)
 
2673
   */
 
2674
  public void text(char c, float x, float y, float z) {
 
2675
//    if ((z != 0) && (textMode == SCREEN)) {
 
2676
//      String msg = "textMode(SCREEN) cannot have a z coordinate";
 
2677
//      throw new RuntimeException(msg);
 
2678
//    }
 
2679
 
 
2680
    if (z != 0) translate(0, 0, z);  // slowness, badness
 
2681
 
 
2682
    text(c, x, y);
 
2683
    textZ = z;
 
2684
 
 
2685
    if (z != 0) translate(0, 0, -z);
 
2686
  }
 
2687
 
 
2688
 
 
2689
  /**
 
2690
   * Write text where we just left off.
 
2691
   */
 
2692
  public void text(String str) {
 
2693
    text(str, textX, textY, textZ);
 
2694
  }
 
2695
 
 
2696
 
 
2697
  /**
 
2698
   * Draw a chunk of text.
 
2699
   * Newlines that are \n (Unix newline or linefeed char, ascii 10)
 
2700
   * are honored, but \r (carriage return, Windows and Mac OS) are
 
2701
   * ignored.
 
2702
   */
 
2703
  public void text(String str, float x, float y) {
 
2704
    if (textFont == null) {
 
2705
      showTextFontException("text");
 
2706
    }
 
2707
 
 
2708
    if (textMode == SCREEN) loadPixels();
 
2709
 
 
2710
    int length = str.length();
 
2711
    if (length > textBuffer.length) {
 
2712
      textBuffer = new char[length + 10];
 
2713
    }
 
2714
    str.getChars(0, length, textBuffer, 0);
 
2715
    text(textBuffer, 0, length, x, y);
 
2716
  }
 
2717
 
 
2718
 
 
2719
  /**
 
2720
   * Method to draw text from an array of chars. This method will usually be 
 
2721
   * more efficient than drawing from a String object, because the String will 
 
2722
   * not be converted to a char array before drawing. 
 
2723
   */
 
2724
  public void text(char[] chars, int start, int stop, float x, float y) {
 
2725
    // If multiple lines, sum the height of the additional lines
 
2726
    float high = 0; //-textAscent();
 
2727
    for (int i = start; i < stop; i++) {
 
2728
      if (chars[i] == '\n') {
 
2729
        high += textLeading;
 
2730
      }
 
2731
    }
 
2732
    if (textAlignY == CENTER) {
 
2733
      // for a single line, this adds half the textAscent to y
 
2734
      // for multiple lines, subtract half the additional height
 
2735
      //y += (textAscent() - textDescent() - high)/2;
 
2736
      y += (textAscent() - high)/2;
 
2737
    } else if (textAlignY == TOP) {
 
2738
      // for a single line, need to add textAscent to y
 
2739
      // for multiple lines, no different
 
2740
      y += textAscent();
 
2741
    } else if (textAlignY == BOTTOM) {
 
2742
      // for a single line, this is just offset by the descent
 
2743
      // for multiple lines, subtract leading for each line
 
2744
      y -= textDescent() + high;
 
2745
    //} else if (textAlignY == BASELINE) {
 
2746
      // do nothing
 
2747
    }
 
2748
 
 
2749
//    int start = 0;
 
2750
    int index = 0;
 
2751
    while (index < stop) { //length) {
 
2752
      if (chars[index] == '\n') {
 
2753
        textLineAlignImpl(chars, start, index, x, y);
 
2754
        start = index + 1;
 
2755
        y += textLeading;
 
2756
      }
 
2757
      index++;
 
2758
    }
 
2759
    if (start < stop) {  //length) {
 
2760
      textLineAlignImpl(chars, start, index, x, y);
 
2761
    }
 
2762
    if (textMode == SCREEN) updatePixels();
 
2763
  }
 
2764
 
 
2765
 
 
2766
  /**
 
2767
   * Same as above but with a z coordinate.
 
2768
   */
 
2769
  public void text(String str, float x, float y, float z) {
 
2770
    if (z != 0) translate(0, 0, z);  // slow!
 
2771
 
 
2772
    text(str, x, y);
 
2773
    textZ = z;
 
2774
 
 
2775
    if (z != 0) translate(0, 0, -z);  // inaccurate!
 
2776
  }
 
2777
 
 
2778
 
 
2779
  public void text(char[] chars, int start, int stop, 
 
2780
                   float x, float y, float z) {
 
2781
    if (z != 0) translate(0, 0, z);  // slow!
 
2782
 
 
2783
    text(chars, start, stop, x, y);
 
2784
    textZ = z;
 
2785
 
 
2786
    if (z != 0) translate(0, 0, -z);  // inaccurate!
 
2787
  }
 
2788
  
 
2789
  
 
2790
  /**
 
2791
   * Draw text in a box that is constrained to a particular size.
 
2792
   * The current rectMode() determines what the coordinates mean
 
2793
   * (whether x1/y1/x2/y2 or x/y/w/h).
 
2794
   * <P/>
 
2795
   * Note that the x,y coords of the start of the box
 
2796
   * will align with the *ascent* of the text, not the baseline,
 
2797
   * as is the case for the other text() functions.
 
2798
   * <P/>
 
2799
   * Newlines that are \n (Unix newline or linefeed char, ascii 10)
 
2800
   * are honored, and \r (carriage return, Windows and Mac OS) are
 
2801
   * ignored.
 
2802
   */
 
2803
  public void text(String str, float x1, float y1, float x2, float y2) {
 
2804
    if (textFont == null) {
 
2805
      showTextFontException("text");
 
2806
    }
 
2807
 
 
2808
    if (textMode == SCREEN) loadPixels();
 
2809
 
 
2810
    float hradius, vradius;
 
2811
    switch (rectMode) {
 
2812
    case CORNER:
 
2813
      x2 += x1; y2 += y1;
 
2814
      break;
 
2815
    case RADIUS:
 
2816
      hradius = x2;
 
2817
      vradius = y2;
 
2818
      x2 = x1 + hradius;
 
2819
      y2 = y1 + vradius;
 
2820
      x1 -= hradius;
 
2821
      y1 -= vradius;
 
2822
      break;
 
2823
    case CENTER:
 
2824
      hradius = x2 / 2.0f;
 
2825
      vradius = y2 / 2.0f;
 
2826
      x2 = x1 + hradius;
 
2827
      y2 = y1 + vradius;
 
2828
      x1 -= hradius;
 
2829
      y1 -= vradius;
 
2830
    }
 
2831
    if (x2 < x1) {
 
2832
      float temp = x1; x1 = x2; x2 = temp;
 
2833
    }
 
2834
    if (y2 < y1) {
 
2835
      float temp = y1; y1 = y2; y2 = temp;
 
2836
    }
 
2837
 
 
2838
//    float currentY = y1;
 
2839
    float boxWidth = x2 - x1;
 
2840
 
 
2841
//    // ala illustrator, the text itself must fit inside the box
 
2842
//    currentY += textAscent(); //ascent() * textSize;
 
2843
//    // if the box is already too small, tell em to f off
 
2844
//    if (currentY > y2) return;
 
2845
 
 
2846
    float spaceWidth = textWidth(' ');
 
2847
 
 
2848
    if (textBreakStart == null) {
 
2849
      textBreakStart = new int[20];
 
2850
      textBreakStop = new int[20];
 
2851
    }
 
2852
    textBreakCount = 0;
 
2853
 
 
2854
    int length = str.length();
 
2855
    if (length + 1 > textBuffer.length) {
 
2856
      textBuffer = new char[length + 1];
 
2857
    }
 
2858
    str.getChars(0, length, textBuffer, 0);
 
2859
    // add a fake newline to simplify calculations
 
2860
    textBuffer[length++] = '\n';
 
2861
 
 
2862
    int sentenceStart = 0;
 
2863
    for (int i = 0; i < length; i++) {
 
2864
      if (textBuffer[i] == '\n') {
 
2865
//        currentY = textSentence(textBuffer, sentenceStart, i,
 
2866
//                                lineX, boxWidth, currentY, y2, spaceWidth);
 
2867
        boolean legit =
 
2868
          textSentence(textBuffer, sentenceStart, i, boxWidth, spaceWidth);
 
2869
        if (!legit) break;
 
2870
//      if (Float.isNaN(currentY)) break;  // word too big (or error)
 
2871
//      if (currentY > y2) break;  // past the box
 
2872
        sentenceStart = i + 1;
 
2873
      }
 
2874
    }
 
2875
 
 
2876
    // lineX is the position where the text starts, which is adjusted
 
2877
    // to left/center/right based on the current textAlign
 
2878
    float lineX = x1; //boxX1;
 
2879
    if (textAlign == CENTER) {
 
2880
      lineX = lineX + boxWidth/2f;
 
2881
    } else if (textAlign == RIGHT) {
 
2882
      lineX = x2; //boxX2;
 
2883
    }
 
2884
 
 
2885
    float boxHeight = y2 - y1;
 
2886
    //int lineFitCount = 1 + PApplet.floor((boxHeight - textAscent()) / textLeading);
 
2887
    // incorporate textAscent() for the top (baseline will be y1 + ascent)
 
2888
    // and textDescent() for the bottom, so that lower parts of letters aren't
 
2889
    // outside the box. [0151]
 
2890
    float topAndBottom = textAscent() + textDescent();
 
2891
    int lineFitCount = 1 + PApplet.floor((boxHeight - topAndBottom) / textLeading);
 
2892
    int lineCount = Math.min(textBreakCount, lineFitCount);
 
2893
 
 
2894
    if (textAlignY == CENTER) {
 
2895
      float lineHigh = textAscent() + textLeading * (lineCount - 1);
 
2896
      float y = y1 + textAscent() + (boxHeight - lineHigh) / 2;
 
2897
      for (int i = 0; i < lineCount; i++) {
 
2898
        textLineAlignImpl(textBuffer, textBreakStart[i], textBreakStop[i], lineX, y);
 
2899
        y += textLeading;
 
2900
      }
 
2901
 
 
2902
    } else if (textAlignY == BOTTOM) {
 
2903
      float y = y2 - textDescent() - textLeading * (lineCount - 1);
 
2904
      for (int i = 0; i < lineCount; i++) {
 
2905
        textLineAlignImpl(textBuffer, textBreakStart[i], textBreakStop[i], lineX, y);
 
2906
        y += textLeading;
 
2907
      }
 
2908
 
 
2909
    } else {  // TOP or BASELINE just go to the default
 
2910
      float y = y1 + textAscent();
 
2911
      for (int i = 0; i < lineCount; i++) {
 
2912
        textLineAlignImpl(textBuffer, textBreakStart[i], textBreakStop[i], lineX, y);
 
2913
        y += textLeading;
 
2914
      }
 
2915
    }
 
2916
 
 
2917
    if (textMode == SCREEN) updatePixels();
 
2918
  }
 
2919
 
 
2920
 
 
2921
  /**
 
2922
   * Emit a sentence of text, defined as a chunk of text without any newlines.
 
2923
   * @param stop non-inclusive, the end of the text in question
 
2924
   */
 
2925
  protected boolean textSentence(char[] buffer, int start, int stop,
 
2926
                                 float boxWidth, float spaceWidth) {
 
2927
    float runningX = 0;
 
2928
 
 
2929
    // Keep track of this separately from index, since we'll need to back up
 
2930
    // from index when breaking words that are too long to fit.
 
2931
    int lineStart = start;
 
2932
    int wordStart = start;
 
2933
    int index = start;
 
2934
    while (index <= stop) {
 
2935
      // boundary of a word or end of this sentence
 
2936
      if ((buffer[index] == ' ') || (index == stop)) {
 
2937
        float wordWidth = textWidthImpl(buffer, wordStart, index);
 
2938
 
 
2939
        if (runningX + wordWidth > boxWidth) {
 
2940
          if (runningX != 0) {
 
2941
            // Next word is too big, output the current line and advance
 
2942
            index = wordStart;
 
2943
            textSentenceBreak(lineStart, index);
 
2944
            // Eat whitespace because multiple spaces don't count for s*
 
2945
            // when they're at the end of a line.
 
2946
            while ((index < stop) && (buffer[index] == ' ')) {
 
2947
              index++;
 
2948
            }
 
2949
          } else {  // (runningX == 0)
 
2950
            // If this is the first word on the line, and its width is greater
 
2951
            // than the width of the text box, then break the word where at the
 
2952
            // max width, and send the rest of the word to the next line.
 
2953
            do {
 
2954
              index--;
 
2955
              if (index == wordStart) {
 
2956
                // Not a single char will fit on this line. screw 'em.
 
2957
                //System.out.println("screw you");
 
2958
                return false; //Float.NaN;
 
2959
              }
 
2960
              wordWidth = textWidthImpl(buffer, wordStart, index);
 
2961
            } while (wordWidth > boxWidth);
 
2962
 
 
2963
            //textLineImpl(buffer, lineStart, index, x, y);
 
2964
            textSentenceBreak(lineStart, index);
 
2965
          }
 
2966
          lineStart = index;
 
2967
          wordStart = index;
 
2968
          runningX = 0;
 
2969
 
 
2970
        } else if (index == stop) {
 
2971
          // last line in the block, time to unload
 
2972
          //textLineImpl(buffer, lineStart, index, x, y);
 
2973
          textSentenceBreak(lineStart, index);
 
2974
//          y += textLeading;
 
2975
          index++;
 
2976
 
 
2977
        } else {  // this word will fit, just add it to the line
 
2978
          runningX += wordWidth + spaceWidth;
 
2979
          wordStart = index + 1;  // move on to the next word
 
2980
          index++;
 
2981
        }
 
2982
      } else {  // not a space or the last character
 
2983
        index++;  // this is just another letter
 
2984
      }
 
2985
    }
 
2986
//    return y;
 
2987
    return true;
 
2988
  }
 
2989
 
 
2990
 
 
2991
  protected void textSentenceBreak(int start, int stop) {
 
2992
    if (textBreakCount == textBreakStart.length) {
 
2993
      textBreakStart = PApplet.expand(textBreakStart);
 
2994
      textBreakStop = PApplet.expand(textBreakStop);
 
2995
    }
 
2996
    textBreakStart[textBreakCount] = start;
 
2997
    textBreakStop[textBreakCount] = stop;
 
2998
    textBreakCount++;
 
2999
  }
 
3000
 
 
3001
 
 
3002
  public void text(String s, float x1, float y1, float x2, float y2, float z) {
 
3003
    if (z != 0) translate(0, 0, z);  // slowness, badness
 
3004
 
 
3005
    text(s, x1, y1, x2, y2);
 
3006
    textZ = z;
 
3007
 
 
3008
    if (z != 0) translate(0, 0, -z);  // TEMPORARY HACK! SLOW!
 
3009
  }
 
3010
 
 
3011
 
 
3012
  public void text(int num, float x, float y) {
 
3013
    text(String.valueOf(num), x, y);
 
3014
  }
 
3015
 
 
3016
 
 
3017
  public void text(int num, float x, float y, float z) {
 
3018
    text(String.valueOf(num), x, y, z);
 
3019
  }
 
3020
 
 
3021
 
 
3022
  /**
 
3023
   * This does a basic number formatting, to avoid the
 
3024
   * generally ugly appearance of printing floats.
 
3025
   * Users who want more control should use their own nf() cmmand,
 
3026
   * or if they want the long, ugly version of float,
 
3027
   * use String.valueOf() to convert the float to a String first.
 
3028
   */
 
3029
  public void text(float num, float x, float y) {
 
3030
    text(PApplet.nfs(num, 0, 3), x, y);
 
3031
  }
 
3032
 
 
3033
 
 
3034
  public void text(float num, float x, float y, float z) {
 
3035
    text(PApplet.nfs(num, 0, 3), x, y, z);
 
3036
  }
 
3037
 
 
3038
 
 
3039
 
 
3040
  //////////////////////////////////////////////////////////////
 
3041
 
 
3042
  // TEXT IMPL
 
3043
 
 
3044
  // These are most likely to be overridden by subclasses, since the other
 
3045
  // (public) functions handle generic features like setting alignment.
 
3046
 
 
3047
 
 
3048
  /**
 
3049
   * Handles placement of a text line, then calls textLineImpl
 
3050
   * to actually render at the specific point.
 
3051
   */
 
3052
  protected void textLineAlignImpl(char buffer[], int start, int stop,
 
3053
                                   float x, float y) {
 
3054
    if (textAlign == CENTER) {
 
3055
      x -= textWidthImpl(buffer, start, stop) / 2f;
 
3056
 
 
3057
    } else if (textAlign == RIGHT) {
 
3058
      x -= textWidthImpl(buffer, start, stop);
 
3059
    }
 
3060
 
 
3061
    textLineImpl(buffer, start, stop, x, y);
 
3062
  }
 
3063
 
 
3064
 
 
3065
  /**
 
3066
   * Implementation of actual drawing for a line of text.
 
3067
   */
 
3068
  protected void textLineImpl(char buffer[], int start, int stop,
 
3069
                              float x, float y) {
 
3070
    for (int index = start; index < stop; index++) {
 
3071
      textCharImpl(buffer[index], x, y);
 
3072
 
 
3073
      // this doesn't account for kerning
 
3074
      x += textWidth(buffer[index]);
 
3075
    }
 
3076
    textX = x;
 
3077
    textY = y;
 
3078
    textZ = 0;  // this will get set by the caller if non-zero
 
3079
  }
 
3080
 
 
3081
 
 
3082
  protected void textCharImpl(char ch, float x, float y) { //, float z) {
 
3083
    int index = textFont.index(ch);
 
3084
    if (index == -1) return;
 
3085
 
 
3086
    PImage glyph = textFont.images[index];
 
3087
 
 
3088
    if (textMode == MODEL) {
 
3089
      float high    = (float) textFont.height[index]     / textFont.fheight;
 
3090
      float bwidth  = (float) textFont.width[index]      / textFont.fwidth;
 
3091
      float lextent = (float) textFont.leftExtent[index] / textFont.fwidth;
 
3092
      float textent = (float) textFont.topExtent[index]  / textFont.fheight;
 
3093
 
 
3094
      float x1 = x + lextent * textSize;
 
3095
      float y1 = y - textent * textSize;
 
3096
      float x2 = x1 + bwidth * textSize;
 
3097
      float y2 = y1 + high * textSize;
 
3098
 
 
3099
      textCharModelImpl(glyph,
 
3100
                        x1, y1, x2, y2,
 
3101
                        //x1, y1, z, x2, y2, z,
 
3102
                        textFont.width[index], textFont.height[index]);
 
3103
 
 
3104
    } else if (textMode == SCREEN) {
 
3105
      int xx = (int) x + textFont.leftExtent[index];;
 
3106
      int yy = (int) y - textFont.topExtent[index];
 
3107
 
 
3108
      int w0 = textFont.width[index];
 
3109
      int h0 = textFont.height[index];
 
3110
 
 
3111
      textCharScreenImpl(glyph, xx, yy, w0, h0);
 
3112
    }
 
3113
  }
 
3114
 
 
3115
 
 
3116
  protected void textCharModelImpl(PImage glyph,
 
3117
                                   float x1, float y1, //float z1,
 
3118
                                   float x2, float y2, //float z2,
 
3119
                                   int u2, int v2) {
 
3120
    boolean savedTint = tint;
 
3121
    int savedTintColor = tintColor;
 
3122
    float savedTintR = tintR;
 
3123
    float savedTintG = tintG;
 
3124
    float savedTintB = tintB;
 
3125
    float savedTintA = tintA;
 
3126
    boolean savedTintAlpha = tintAlpha;
 
3127
 
 
3128
    tint = true;
 
3129
    tintColor = fillColor;
 
3130
    tintR = fillR;
 
3131
    tintG = fillG;
 
3132
    tintB = fillB;
 
3133
    tintA = fillA;
 
3134
    tintAlpha = fillAlpha;
 
3135
 
 
3136
    imageImpl(glyph, x1, y1, x2, y2, 0, 0, u2, v2);
 
3137
 
 
3138
    tint = savedTint;
 
3139
    tintColor = savedTintColor;
 
3140
    tintR = savedTintR;
 
3141
    tintG = savedTintG;
 
3142
    tintB = savedTintB;
 
3143
    tintA = savedTintA;
 
3144
    tintAlpha = savedTintAlpha;
 
3145
  }
 
3146
 
 
3147
 
 
3148
  protected void textCharScreenImpl(PImage glyph,
 
3149
                                    int xx, int yy,
 
3150
                                    int w0, int h0) {
 
3151
    int x0 = 0;
 
3152
    int y0 = 0;
 
3153
 
 
3154
    if ((xx >= width) || (yy >= height) ||
 
3155
        (xx + w0 < 0) || (yy + h0 < 0)) return;
 
3156
 
 
3157
    if (xx < 0) {
 
3158
      x0 -= xx;
 
3159
      w0 += xx;
 
3160
      xx = 0;
 
3161
    }
 
3162
    if (yy < 0) {
 
3163
      y0 -= yy;
 
3164
      h0 += yy;
 
3165
      yy = 0;
 
3166
    }
 
3167
    if (xx + w0 > width) {
 
3168
      w0 -= ((xx + w0) - width);
 
3169
    }
 
3170
    if (yy + h0 > height) {
 
3171
      h0 -= ((yy + h0) - height);
 
3172
    }
 
3173
 
 
3174
    int fr = fillRi;
 
3175
    int fg = fillGi;
 
3176
    int fb = fillBi;
 
3177
    int fa = fillAi;
 
3178
 
 
3179
    int pixels1[] = glyph.pixels; //images[glyph].pixels;
 
3180
 
 
3181
    // TODO this can be optimized a bit
 
3182
    for (int row = y0; row < y0 + h0; row++) {
 
3183
      for (int col = x0; col < x0 + w0; col++) {
 
3184
        int a1 = (fa * pixels1[row * textFont.twidth + col]) >> 8;
 
3185
        int a2 = a1 ^ 0xff;
 
3186
        //int p1 = pixels1[row * glyph.width + col];
 
3187
        int p2 = pixels[(yy + row-y0)*width + (xx+col-x0)];
 
3188
 
 
3189
        pixels[(yy + row-y0)*width + xx+col-x0] =
 
3190
          (0xff000000 |
 
3191
           (((a1 * fr + a2 * ((p2 >> 16) & 0xff)) & 0xff00) << 8) |
 
3192
           (( a1 * fg + a2 * ((p2 >>  8) & 0xff)) & 0xff00) |
 
3193
           (( a1 * fb + a2 * ( p2        & 0xff)) >> 8));
 
3194
      }
 
3195
    }
 
3196
  }
 
3197
 
 
3198
 
 
3199
 
 
3200
  //////////////////////////////////////////////////////////////
 
3201
 
 
3202
  // MATRIX STACK
 
3203
 
 
3204
 
 
3205
  /**
 
3206
   * Push a copy of the current transformation matrix onto the stack.
 
3207
   */
 
3208
  public void pushMatrix() {
 
3209
    showMethodWarning("pushMatrix");
 
3210
  }
 
3211
 
 
3212
 
 
3213
  /**
 
3214
   * Replace the current transformation matrix with the top of the stack.
 
3215
   */
 
3216
  public void popMatrix() {
 
3217
    showMethodWarning("popMatrix");
 
3218
  }
 
3219
 
 
3220
 
 
3221
 
 
3222
  //////////////////////////////////////////////////////////////
 
3223
 
 
3224
  // MATRIX TRANSFORMATIONS
 
3225
 
 
3226
 
 
3227
  /**
 
3228
   * Translate in X and Y.
 
3229
   */
 
3230
  public void translate(float tx, float ty) {
 
3231
    showMissingWarning("translate");
 
3232
  }
 
3233
 
 
3234
 
 
3235
  /**
 
3236
   * Translate in X, Y, and Z.
 
3237
   */
 
3238
  public void translate(float tx, float ty, float tz) {
 
3239
    showMissingWarning("translate");
 
3240
  }
 
3241
 
 
3242
 
 
3243
  /**
 
3244
   * Two dimensional rotation.
 
3245
   *
 
3246
   * Same as rotateZ (this is identical to a 3D rotation along the z-axis)
 
3247
   * but included for clarity. It'd be weird for people drawing 2D graphics
 
3248
   * to be using rotateZ. And they might kick our a-- for the confusion.
 
3249
   *
 
3250
   * <A HREF="http://www.xkcd.com/c184.html">Additional background</A>.
 
3251
   */
 
3252
  public void rotate(float angle) {
 
3253
    showMissingWarning("rotate");
 
3254
  }
 
3255
 
 
3256
 
 
3257
  /**
 
3258
   * Rotate around the X axis.
 
3259
   */
 
3260
  public void rotateX(float angle) {
 
3261
    showMethodWarning("rotateX");
 
3262
  }
 
3263
 
 
3264
 
 
3265
  /**
 
3266
   * Rotate around the Y axis.
 
3267
   */
 
3268
  public void rotateY(float angle) {
 
3269
    showMethodWarning("rotateY");
 
3270
  }
 
3271
 
 
3272
 
 
3273
  /**
 
3274
   * Rotate around the Z axis.
 
3275
   *
 
3276
   * The functions rotate() and rotateZ() are identical, it's just that it make
 
3277
   * sense to have rotate() and then rotateX() and rotateY() when using 3D;
 
3278
   * nor does it make sense to use a function called rotateZ() if you're only
 
3279
   * doing things in 2D. so we just decided to have them both be the same.
 
3280
   */
 
3281
  public void rotateZ(float angle) {
 
3282
    showMethodWarning("rotateZ");
 
3283
  }
 
3284
 
 
3285
 
 
3286
  /**
 
3287
   * Rotate about a vector in space. Same as the glRotatef() function.
 
3288
   */
 
3289
  public void rotate(float angle, float vx, float vy, float vz) {
 
3290
    showMissingWarning("rotate");
 
3291
  }
 
3292
 
 
3293
 
 
3294
  /**
 
3295
   * Scale in all dimensions.
 
3296
   */
 
3297
  public void scale(float s) {
 
3298
    showMissingWarning("scale");
 
3299
  }
 
3300
 
 
3301
 
 
3302
  /**
 
3303
   * Scale in X and Y. Equivalent to scale(sx, sy, 1).
 
3304
   *
 
3305
   * Not recommended for use in 3D, because the z-dimension is just
 
3306
   * scaled by 1, since there's no way to know what else to scale it by.
 
3307
   */
 
3308
  public void scale(float sx, float sy) {
 
3309
    showMissingWarning("scale");
 
3310
  }
 
3311
 
 
3312
 
 
3313
  /**
 
3314
   * Scale in X, Y, and Z.
 
3315
   */
 
3316
  public void scale(float x, float y, float z) {
 
3317
    showMissingWarning("scale");
 
3318
  }
 
3319
 
 
3320
 
 
3321
  //////////////////////////////////////////////////////////////
 
3322
 
 
3323
  // MATRIX FULL MONTY
 
3324
 
 
3325
 
 
3326
  /**
 
3327
   * Set the current transformation matrix to identity.
 
3328
   */
 
3329
  public void resetMatrix() {
 
3330
    showMethodWarning("resetMatrix");
 
3331
  }
 
3332
 
 
3333
 
 
3334
  public void applyMatrix(PMatrix source) {
 
3335
    if (source instanceof PMatrix2D) {
 
3336
      applyMatrix((PMatrix2D) source);
 
3337
    } else if (source instanceof PMatrix3D) {
 
3338
      applyMatrix((PMatrix3D) source);
 
3339
    }
 
3340
  }
 
3341
 
 
3342
 
 
3343
  public void applyMatrix(PMatrix2D source) {
 
3344
    applyMatrix(source.m00, source.m01, source.m02,
 
3345
                source.m10, source.m11, source.m12);
 
3346
  }
 
3347
 
 
3348
 
 
3349
  /**
 
3350
   * Apply a 3x2 affine transformation matrix.
 
3351
   */
 
3352
  public void applyMatrix(float n00, float n01, float n02,
 
3353
                          float n10, float n11, float n12) {
 
3354
    showMissingWarning("applyMatrix");
 
3355
  }
 
3356
 
 
3357
 
 
3358
  public void applyMatrix(PMatrix3D source) {
 
3359
    applyMatrix(source.m00, source.m01, source.m02, source.m03,
 
3360
                source.m10, source.m11, source.m12, source.m13,
 
3361
                source.m20, source.m21, source.m22, source.m23,
 
3362
                source.m30, source.m31, source.m32, source.m33);
 
3363
  }
 
3364
 
 
3365
 
 
3366
  /**
 
3367
   * Apply a 4x4 transformation matrix.
 
3368
   */
 
3369
  public void applyMatrix(float n00, float n01, float n02, float n03,
 
3370
                          float n10, float n11, float n12, float n13,
 
3371
                          float n20, float n21, float n22, float n23,
 
3372
                          float n30, float n31, float n32, float n33) {
 
3373
    showMissingWarning("applyMatrix");
 
3374
  }
 
3375
 
 
3376
 
 
3377
 
 
3378
  //////////////////////////////////////////////////////////////
 
3379
 
 
3380
  // MATRIX GET/SET/PRINT
 
3381
 
 
3382
 
 
3383
  public PMatrix getMatrix() {
 
3384
    showMissingWarning("getMatrix");
 
3385
    return null;
 
3386
  }
 
3387
 
 
3388
 
 
3389
  /**
 
3390
   * Copy the current transformation matrix into the specified target.
 
3391
   * Pass in null to create a new matrix.
 
3392
   */
 
3393
  public PMatrix2D getMatrix(PMatrix2D target) {
 
3394
    showMissingWarning("getMatrix");
 
3395
    return null;
 
3396
  }
 
3397
 
 
3398
 
 
3399
  /**
 
3400
   * Copy the current transformation matrix into the specified target.
 
3401
   * Pass in null to create a new matrix.
 
3402
   */
 
3403
  public PMatrix3D getMatrix(PMatrix3D target) {
 
3404
    showMissingWarning("getMatrix");
 
3405
    return null;
 
3406
  }
 
3407
 
 
3408
 
 
3409
  /**
 
3410
   * Set the current transformation matrix to the contents of another.
 
3411
   */
 
3412
  public void setMatrix(PMatrix source) {
 
3413
    if (source instanceof PMatrix2D) {
 
3414
      setMatrix((PMatrix2D) source);
 
3415
    } else if (source instanceof PMatrix3D) {
 
3416
      setMatrix((PMatrix3D) source);
 
3417
    }
 
3418
  }
 
3419
 
 
3420
 
 
3421
  /**
 
3422
   * Set the current transformation to the contents of the specified source.
 
3423
   */
 
3424
  public void setMatrix(PMatrix2D source) {
 
3425
    showMissingWarning("setMatrix");
 
3426
  }
 
3427
 
 
3428
 
 
3429
  /**
 
3430
   * Set the current transformation to the contents of the specified source.
 
3431
   */
 
3432
  public void setMatrix(PMatrix3D source) {
 
3433
    showMissingWarning("setMatrix");
 
3434
  }
 
3435
 
 
3436
 
 
3437
  /**
 
3438
   * Print the current model (or "transformation") matrix.
 
3439
   */
 
3440
  public void printMatrix() {
 
3441
    showMethodWarning("printMatrix");
 
3442
  }
 
3443
 
 
3444
 
 
3445
 
 
3446
  //////////////////////////////////////////////////////////////
 
3447
 
 
3448
  // CAMERA
 
3449
 
 
3450
 
 
3451
  public void beginCamera() {
 
3452
    showMethodWarning("beginCamera");
 
3453
  }
 
3454
 
 
3455
 
 
3456
  public void endCamera() {
 
3457
    showMethodWarning("endCamera");
 
3458
  }
 
3459
 
 
3460
 
 
3461
  public void camera() {
 
3462
    showMissingWarning("camera");
 
3463
  }
 
3464
 
 
3465
 
 
3466
  public void camera(float eyeX, float eyeY, float eyeZ,
 
3467
                     float centerX, float centerY, float centerZ,
 
3468
                     float upX, float upY, float upZ) {
 
3469
    showMissingWarning("camera");
 
3470
  }
 
3471
 
 
3472
 
 
3473
  public void printCamera() {
 
3474
    showMethodWarning("printCamera");
 
3475
  }
 
3476
 
 
3477
 
 
3478
 
 
3479
  //////////////////////////////////////////////////////////////
 
3480
 
 
3481
  // PROJECTION
 
3482
 
 
3483
 
 
3484
  public void ortho() {
 
3485
    showMissingWarning("ortho");
 
3486
  }
 
3487
 
 
3488
 
 
3489
  public void ortho(float left, float right,
 
3490
                    float bottom, float top,
 
3491
                    float near, float far) {
 
3492
    showMissingWarning("ortho");
 
3493
  }
 
3494
 
 
3495
 
 
3496
  public void perspective() {
 
3497
    showMissingWarning("perspective");
 
3498
  }
 
3499
 
 
3500
 
 
3501
  public void perspective(float fovy, float aspect, float zNear, float zFar) {
 
3502
    showMissingWarning("perspective");
 
3503
  }
 
3504
 
 
3505
 
 
3506
  public void frustum(float left, float right,
 
3507
                      float bottom, float top,
 
3508
                      float near, float far) {
 
3509
    showMethodWarning("frustum");
 
3510
  }
 
3511
 
 
3512
 
 
3513
  public void printProjection() {
 
3514
    showMethodWarning("printCamera");
 
3515
  }
 
3516
 
 
3517
 
 
3518
 
 
3519
  //////////////////////////////////////////////////////////////
 
3520
 
 
3521
  // SCREEN TRANSFORMS
 
3522
 
 
3523
 
 
3524
  /**
 
3525
   * Given an x and y coordinate, returns the x position of where
 
3526
   * that point would be placed on screen, once affected by translate(),
 
3527
   * scale(), or any other transformations.
 
3528
   */
 
3529
  public float screenX(float x, float y) {
 
3530
    showMissingWarning("screenX");
 
3531
    return 0;
 
3532
  }
 
3533
 
 
3534
 
 
3535
  /**
 
3536
   * Given an x and y coordinate, returns the y position of where
 
3537
   * that point would be placed on screen, once affected by translate(),
 
3538
   * scale(), or any other transformations.
 
3539
   */
 
3540
  public float screenY(float x, float y) {
 
3541
    showMissingWarning("screenY");
 
3542
    return 0;
 
3543
  }
 
3544
 
 
3545
 
 
3546
  /**
 
3547
   * Maps a three dimensional point to its placement on-screen.
 
3548
   * <P>
 
3549
   * Given an (x, y, z) coordinate, returns the x position of where
 
3550
   * that point would be placed on screen, once affected by translate(),
 
3551
   * scale(), or any other transformations.
 
3552
   */
 
3553
  public float screenX(float x, float y, float z) {
 
3554
    showMissingWarning("screenX");
 
3555
    return 0;
 
3556
  }
 
3557
 
 
3558
 
 
3559
  /**
 
3560
   * Maps a three dimensional point to its placement on-screen.
 
3561
   * <P>
 
3562
   * Given an (x, y, z) coordinate, returns the y position of where
 
3563
   * that point would be placed on screen, once affected by translate(),
 
3564
   * scale(), or any other transformations.
 
3565
   */
 
3566
  public float screenY(float x, float y, float z) {
 
3567
    showMissingWarning("screenY");
 
3568
    return 0;
 
3569
  }
 
3570
 
 
3571
 
 
3572
  /**
 
3573
   * Maps a three dimensional point to its placement on-screen.
 
3574
   * <P>
 
3575
   * Given an (x, y, z) coordinate, returns its z value.
 
3576
   * This value can be used to determine if an (x, y, z) coordinate
 
3577
   * is in front or in back of another (x, y, z) coordinate.
 
3578
   * The units are based on how the zbuffer is set up, and don't
 
3579
   * relate to anything "real". They're only useful for in
 
3580
   * comparison to another value obtained from screenZ(),
 
3581
   * or directly out of the zbuffer[].
 
3582
   */
 
3583
  public float screenZ(float x, float y, float z) {
 
3584
    showMissingWarning("screenZ");
 
3585
    return 0;
 
3586
  }
 
3587
 
 
3588
 
 
3589
  /**
 
3590
   * Returns the model space x value for an x, y, z coordinate.
 
3591
   * <P>
 
3592
   * This will give you a coordinate after it has been transformed
 
3593
   * by translate(), rotate(), and camera(), but not yet transformed
 
3594
   * by the projection matrix. For instance, his can be useful for
 
3595
   * figuring out how points in 3D space relate to the edge
 
3596
   * coordinates of a shape.
 
3597
   */
 
3598
  public float modelX(float x, float y, float z) {
 
3599
    showMissingWarning("modelX");
 
3600
    return 0;
 
3601
  }
 
3602
 
 
3603
 
 
3604
  /**
 
3605
   * Returns the model space y value for an x, y, z coordinate.
 
3606
   */
 
3607
  public float modelY(float x, float y, float z) {
 
3608
    showMissingWarning("modelY");
 
3609
    return 0;
 
3610
  }
 
3611
 
 
3612
 
 
3613
  /**
 
3614
   * Returns the model space z value for an x, y, z coordinate.
 
3615
   */
 
3616
  public float modelZ(float x, float y, float z) {
 
3617
    showMissingWarning("modelZ");
 
3618
    return 0;
 
3619
  }
 
3620
 
 
3621
 
 
3622
 
 
3623
  //////////////////////////////////////////////////////////////
 
3624
 
 
3625
  // STYLE
 
3626
 
 
3627
 
 
3628
  public void pushStyle() {
 
3629
    if (styleStackDepth == styleStack.length) {
 
3630
      styleStack = (PStyle[]) PApplet.expand(styleStack);
 
3631
    }
 
3632
    if (styleStack[styleStackDepth] == null) {
 
3633
      styleStack[styleStackDepth] = new PStyle();
 
3634
    }
 
3635
    PStyle s = styleStack[styleStackDepth++];
 
3636
    getStyle(s);
 
3637
  }
 
3638
 
 
3639
 
 
3640
  public void popStyle() {
 
3641
    if (styleStackDepth == 0) {
 
3642
      throw new RuntimeException("Too many popStyle() without enough pushStyle()");
 
3643
    }
 
3644
    styleStackDepth--;
 
3645
    style(styleStack[styleStackDepth]);
 
3646
  }
 
3647
 
 
3648
 
 
3649
  public void style(PStyle s) {
 
3650
    //  if (s.smooth) {
 
3651
    //    smooth();
 
3652
    //  } else {
 
3653
    //    noSmooth();
 
3654
    //  }
 
3655
 
 
3656
    imageMode(s.imageMode);
 
3657
    rectMode(s.rectMode);
 
3658
    ellipseMode(s.ellipseMode);
 
3659
    shapeMode(s.shapeMode);
 
3660
 
 
3661
    if (s.tint) {
 
3662
      tint(s.tintColor);
 
3663
    } else {
 
3664
      noTint();
 
3665
    }
 
3666
    if (s.fill) {
 
3667
      fill(s.fillColor);
 
3668
    } else {
 
3669
      noFill();
 
3670
    }
 
3671
    if (s.stroke) {
 
3672
      stroke(s.strokeColor);
 
3673
    } else {
 
3674
      noStroke();
 
3675
    }
 
3676
    strokeWeight(s.strokeWeight);
 
3677
    strokeCap(s.strokeCap);
 
3678
    strokeJoin(s.strokeJoin);
 
3679
 
 
3680
    // Set the colorMode() for the material properties.
 
3681
    // TODO this is really inefficient, need to just have a material() method,
 
3682
    // but this has the least impact to the API.
 
3683
    colorMode(RGB, 1);
 
3684
    ambient(s.ambientR, s.ambientG, s.ambientB);
 
3685
    emissive(s.emissiveR, s.emissiveG, s.emissiveB);
 
3686
    specular(s.specularR, s.specularG, s.specularB);
 
3687
    shininess(s.shininess);
 
3688
 
 
3689
    /*
 
3690
  s.ambientR = ambientR;
 
3691
  s.ambientG = ambientG;
 
3692
  s.ambientB = ambientB;
 
3693
  s.specularR = specularR;
 
3694
  s.specularG = specularG;
 
3695
  s.specularB = specularB;
 
3696
  s.emissiveR = emissiveR;
 
3697
  s.emissiveG = emissiveG;
 
3698
  s.emissiveB = emissiveB;
 
3699
  s.shininess = shininess;
 
3700
     */
 
3701
    //  material(s.ambientR, s.ambientG, s.ambientB,
 
3702
    //           s.emissiveR, s.emissiveG, s.emissiveB,
 
3703
    //           s.specularR, s.specularG, s.specularB,
 
3704
    //           s.shininess);
 
3705
 
 
3706
    // Set this after the material properties.
 
3707
    colorMode(s.colorMode,
 
3708
              s.colorModeX, s.colorModeY, s.colorModeZ, s.colorModeA);
 
3709
 
 
3710
    // This is a bit asymmetric, since there's no way to do "noFont()",
 
3711
    // and a null textFont will produce an error (since usually that means that
 
3712
    // the font couldn't load properly). So in some cases, the font won't be
 
3713
    // 'cleared' to null, even though that's technically correct.
 
3714
    if (s.textFont != null) {
 
3715
      textFont(s.textFont, s.textSize);
 
3716
      textLeading(s.textLeading);
 
3717
    }
 
3718
    // These don't require a font to be set.
 
3719
    textAlign(s.textAlign, s.textAlignY);
 
3720
    textMode(s.textMode);
 
3721
  }
 
3722
 
 
3723
 
 
3724
  public PStyle getStyle() {  // ignore
 
3725
    return getStyle(null);
 
3726
  }
 
3727
 
 
3728
 
 
3729
  public PStyle getStyle(PStyle s) {  // ignore
 
3730
    if (s == null) {
 
3731
      s = new PStyle();
 
3732
    }
 
3733
 
 
3734
    s.imageMode = imageMode;
 
3735
    s.rectMode = rectMode;
 
3736
    s.ellipseMode = ellipseMode;
 
3737
    s.shapeMode = shapeMode;
 
3738
 
 
3739
    s.colorMode = colorMode;
 
3740
    s.colorModeX = colorModeX;
 
3741
    s.colorModeY = colorModeY;
 
3742
    s.colorModeZ = colorModeZ;
 
3743
    s.colorModeA = colorModeA;
 
3744
 
 
3745
    s.tint = tint;
 
3746
    s.tintColor = tintColor;
 
3747
    s.fill = fill;
 
3748
    s.fillColor = fillColor;
 
3749
    s.stroke = stroke;
 
3750
    s.strokeColor = strokeColor;
 
3751
    s.strokeWeight = strokeWeight;
 
3752
    s.strokeCap = strokeCap;
 
3753
    s.strokeJoin = strokeJoin;
 
3754
 
 
3755
    s.ambientR = ambientR;
 
3756
    s.ambientG = ambientG;
 
3757
    s.ambientB = ambientB;
 
3758
    s.specularR = specularR;
 
3759
    s.specularG = specularG;
 
3760
    s.specularB = specularB;
 
3761
    s.emissiveR = emissiveR;
 
3762
    s.emissiveG = emissiveG;
 
3763
    s.emissiveB = emissiveB;
 
3764
    s.shininess = shininess;
 
3765
 
 
3766
    s.textFont = textFont;
 
3767
    s.textAlign = textAlign;
 
3768
    s.textAlignY = textAlignY;
 
3769
    s.textMode = textMode;
 
3770
    s.textSize = textSize;
 
3771
    s.textLeading = textLeading;
 
3772
 
 
3773
    return s;
 
3774
  }
 
3775
 
 
3776
 
 
3777
 
 
3778
  //////////////////////////////////////////////////////////////
 
3779
 
 
3780
  // STROKE CAP/JOIN/WEIGHT
 
3781
 
 
3782
 
 
3783
  public void strokeWeight(float weight) {
 
3784
    strokeWeight = weight;
 
3785
  }
 
3786
 
 
3787
 
 
3788
  public void strokeJoin(int join) {
 
3789
    strokeJoin = join;
 
3790
  }
 
3791
 
 
3792
 
 
3793
  public void strokeCap(int cap) {
 
3794
    strokeCap = cap;
 
3795
  }
 
3796
 
 
3797
 
 
3798
 
 
3799
  //////////////////////////////////////////////////////////////
 
3800
 
 
3801
  // STROKE COLOR
 
3802
 
 
3803
 
 
3804
  public void noStroke() {
 
3805
    stroke = false;
 
3806
  }
 
3807
 
 
3808
 
 
3809
  /**
 
3810
   * Set the tint to either a grayscale or ARGB value.
 
3811
   * See notes attached to the fill() function.
 
3812
   */
 
3813
  public void stroke(int rgb) {
 
3814
//    if (((rgb & 0xff000000) == 0) && (rgb <= colorModeX)) {  // see above
 
3815
//      stroke((float) rgb);
 
3816
//
 
3817
//    } else {
 
3818
//      colorCalcARGB(rgb, colorModeA);
 
3819
//      strokeFromCalc();
 
3820
//    }
 
3821
    colorCalc(rgb);
 
3822
    strokeFromCalc();
 
3823
  }
 
3824
 
 
3825
 
 
3826
  public void stroke(int rgb, float alpha) {
 
3827
//    if (((rgb & 0xff000000) == 0) && (rgb <= colorModeX)) {
 
3828
//      stroke((float) rgb, alpha);
 
3829
//
 
3830
//    } else {
 
3831
//      colorCalcARGB(rgb, alpha);
 
3832
//      strokeFromCalc();
 
3833
//    }
 
3834
    colorCalc(rgb, alpha);
 
3835
    strokeFromCalc();
 
3836
  }
 
3837
 
 
3838
 
 
3839
  public void stroke(float gray) {
 
3840
    colorCalc(gray);
 
3841
    strokeFromCalc();
 
3842
  }
 
3843
 
 
3844
 
 
3845
  public void stroke(float gray, float alpha) {
 
3846
    colorCalc(gray, alpha);
 
3847
    strokeFromCalc();
 
3848
  }
 
3849
 
 
3850
 
 
3851
  public void stroke(float x, float y, float z) {
 
3852
    colorCalc(x, y, z);
 
3853
    strokeFromCalc();
 
3854
  }
 
3855
 
 
3856
 
 
3857
  public void stroke(float x, float y, float z, float a) {
 
3858
    colorCalc(x, y, z, a);
 
3859
    strokeFromCalc();
 
3860
  }
 
3861
 
 
3862
 
 
3863
  protected void strokeFromCalc() {
 
3864
    stroke = true;
 
3865
    strokeR = calcR;
 
3866
    strokeG = calcG;
 
3867
    strokeB = calcB;
 
3868
    strokeA = calcA;
 
3869
    strokeRi = calcRi;
 
3870
    strokeGi = calcGi;
 
3871
    strokeBi = calcBi;
 
3872
    strokeAi = calcAi;
 
3873
    strokeColor = calcColor;
 
3874
    strokeAlpha = calcAlpha;
 
3875
  }
 
3876
 
 
3877
 
 
3878
 
 
3879
  //////////////////////////////////////////////////////////////
 
3880
 
 
3881
  // TINT COLOR
 
3882
 
 
3883
 
 
3884
  public void noTint() {
 
3885
    tint = false;
 
3886
  }
 
3887
 
 
3888
 
 
3889
  /**
 
3890
   * Set the tint to either a grayscale or ARGB value.
 
3891
   */
 
3892
  public void tint(int rgb) {
 
3893
//    if (((rgb & 0xff000000) == 0) && (rgb <= colorModeX)) {
 
3894
//      tint((float) rgb);
 
3895
//
 
3896
//    } else {
 
3897
//      colorCalcARGB(rgb, colorModeA);
 
3898
//      tintFromCalc();
 
3899
//    }
 
3900
    colorCalc(rgb);
 
3901
    tintFromCalc();
 
3902
  }
 
3903
 
 
3904
  public void tint(int rgb, float alpha) {
 
3905
//    if (((rgb & 0xff000000) == 0) && (rgb <= colorModeX)) {
 
3906
//      tint((float) rgb, alpha);
 
3907
//
 
3908
//    } else {
 
3909
//      colorCalcARGB(rgb, alpha);
 
3910
//      tintFromCalc();
 
3911
//    }
 
3912
    colorCalc(rgb, alpha);
 
3913
    tintFromCalc();
 
3914
  }
 
3915
 
 
3916
  public void tint(float gray) {
 
3917
    colorCalc(gray);
 
3918
    tintFromCalc();
 
3919
  }
 
3920
 
 
3921
 
 
3922
  public void tint(float gray, float alpha) {
 
3923
    colorCalc(gray, alpha);
 
3924
    tintFromCalc();
 
3925
  }
 
3926
 
 
3927
 
 
3928
  public void tint(float x, float y, float z) {
 
3929
    colorCalc(x, y, z);
 
3930
    tintFromCalc();
 
3931
  }
 
3932
 
 
3933
 
 
3934
  public void tint(float x, float y, float z, float a) {
 
3935
    colorCalc(x, y, z, a);
 
3936
    tintFromCalc();
 
3937
  }
 
3938
 
 
3939
 
 
3940
  protected void tintFromCalc() {
 
3941
    tint = true;
 
3942
    tintR = calcR;
 
3943
    tintG = calcG;
 
3944
    tintB = calcB;
 
3945
    tintA = calcA;
 
3946
    tintRi = calcRi;
 
3947
    tintGi = calcGi;
 
3948
    tintBi = calcBi;
 
3949
    tintAi = calcAi;
 
3950
    tintColor = calcColor;
 
3951
    tintAlpha = calcAlpha;
 
3952
  }
 
3953
 
 
3954
 
 
3955
 
 
3956
  //////////////////////////////////////////////////////////////
 
3957
 
 
3958
  // FILL COLOR
 
3959
 
 
3960
 
 
3961
  public void noFill() {
 
3962
    fill = false;
 
3963
  }
 
3964
 
 
3965
 
 
3966
  /**
 
3967
   * Set the fill to either a grayscale value or an ARGB int.
 
3968
   */
 
3969
  public void fill(int rgb) {
 
3970
//    if (((rgb & 0xff000000) == 0) && (rgb <= colorModeX)) {  // see above
 
3971
//      fill((float) rgb);
 
3972
//
 
3973
//    } else {
 
3974
//      colorCalcARGB(rgb, colorModeA);
 
3975
//      fillFromCalc();
 
3976
//    }
 
3977
    colorCalc(rgb);
 
3978
    fillFromCalc();
 
3979
  }
 
3980
 
 
3981
 
 
3982
  public void fill(int rgb, float alpha) {
 
3983
//    if (((rgb & 0xff000000) == 0) && (rgb <= colorModeX)) {  // see above
 
3984
//      fill((float) rgb, alpha);
 
3985
//
 
3986
//    } else {
 
3987
//      colorCalcARGB(rgb, alpha);
 
3988
//      fillFromCalc();
 
3989
//    }
 
3990
    colorCalc(rgb, alpha);
 
3991
    fillFromCalc();
 
3992
  }
 
3993
 
 
3994
 
 
3995
  public void fill(float gray) {
 
3996
    colorCalc(gray);
 
3997
    fillFromCalc();
 
3998
  }
 
3999
 
 
4000
 
 
4001
  public void fill(float gray, float alpha) {
 
4002
    colorCalc(gray, alpha);
 
4003
    fillFromCalc();
 
4004
  }
 
4005
 
 
4006
 
 
4007
  public void fill(float x, float y, float z) {
 
4008
    colorCalc(x, y, z);
 
4009
    fillFromCalc();
 
4010
  }
 
4011
 
 
4012
 
 
4013
  public void fill(float x, float y, float z, float a) {
 
4014
    colorCalc(x, y, z, a);
 
4015
    fillFromCalc();
 
4016
  }
 
4017
 
 
4018
 
 
4019
  protected void fillFromCalc() {
 
4020
    fill = true;
 
4021
    fillR = calcR;
 
4022
    fillG = calcG;
 
4023
    fillB = calcB;
 
4024
    fillA = calcA;
 
4025
    fillRi = calcRi;
 
4026
    fillGi = calcGi;
 
4027
    fillBi = calcBi;
 
4028
    fillAi = calcAi;
 
4029
    fillColor = calcColor;
 
4030
    fillAlpha = calcAlpha;
 
4031
  }
 
4032
 
 
4033
 
 
4034
 
 
4035
  //////////////////////////////////////////////////////////////
 
4036
 
 
4037
  // MATERIAL PROPERTIES
 
4038
 
 
4039
 
 
4040
  public void ambient(int rgb) {
 
4041
//    if (((rgb & 0xff000000) == 0) && (rgb <= colorModeX)) {
 
4042
//      ambient((float) rgb);
 
4043
//
 
4044
//    } else {
 
4045
//      colorCalcARGB(rgb, colorModeA);
 
4046
//      ambientFromCalc();
 
4047
//    }
 
4048
    colorCalc(rgb);
 
4049
    ambientFromCalc();
 
4050
  }
 
4051
 
 
4052
 
 
4053
  public void ambient(float gray) {
 
4054
    colorCalc(gray);
 
4055
    ambientFromCalc();
 
4056
  }
 
4057
 
 
4058
 
 
4059
  public void ambient(float x, float y, float z) {
 
4060
    colorCalc(x, y, z);
 
4061
    ambientFromCalc();
 
4062
  }
 
4063
 
 
4064
 
 
4065
  protected void ambientFromCalc() {
 
4066
    ambientR = calcR;
 
4067
    ambientG = calcG;
 
4068
    ambientB = calcB;
 
4069
  }
 
4070
 
 
4071
 
 
4072
  public void specular(int rgb) {
 
4073
//    if (((rgb & 0xff000000) == 0) && (rgb <= colorModeX)) {
 
4074
//      specular((float) rgb);
 
4075
//
 
4076
//    } else {
 
4077
//      colorCalcARGB(rgb, colorModeA);
 
4078
//      specularFromCalc();
 
4079
//    }
 
4080
    colorCalc(rgb);
 
4081
    specularFromCalc();
 
4082
  }
 
4083
 
 
4084
 
 
4085
  public void specular(float gray) {
 
4086
    colorCalc(gray);
 
4087
    specularFromCalc();
 
4088
  }
 
4089
 
 
4090
 
 
4091
  public void specular(float x, float y, float z) {
 
4092
    colorCalc(x, y, z);
 
4093
    specularFromCalc();
 
4094
  }
 
4095
 
 
4096
 
 
4097
  protected void specularFromCalc() {
 
4098
    specularR = calcR;
 
4099
    specularG = calcG;
 
4100
    specularB = calcB;
 
4101
  }
 
4102
 
 
4103
 
 
4104
  public void shininess(float shine) {
 
4105
    shininess = shine;
 
4106
  }
 
4107
 
 
4108
 
 
4109
  public void emissive(int rgb) {
 
4110
//    if (((rgb & 0xff000000) == 0) && (rgb <= colorModeX)) {
 
4111
//      emissive((float) rgb);
 
4112
//
 
4113
//    } else {
 
4114
//      colorCalcARGB(rgb, colorModeA);
 
4115
//      emissiveFromCalc();
 
4116
//    }
 
4117
    colorCalc(rgb);
 
4118
    emissiveFromCalc();
 
4119
  }
 
4120
 
 
4121
 
 
4122
  public void emissive(float gray) {
 
4123
    colorCalc(gray);
 
4124
    emissiveFromCalc();
 
4125
  }
 
4126
 
 
4127
 
 
4128
  public void emissive(float x, float y, float z) {
 
4129
    colorCalc(x, y, z);
 
4130
    emissiveFromCalc();
 
4131
  }
 
4132
 
 
4133
 
 
4134
  protected void emissiveFromCalc() {
 
4135
    emissiveR = calcR;
 
4136
    emissiveG = calcG;
 
4137
    emissiveB = calcB;
 
4138
  }
 
4139
 
 
4140
 
 
4141
 
 
4142
  //////////////////////////////////////////////////////////////
 
4143
 
 
4144
  // LIGHTS
 
4145
 
 
4146
  // The details of lighting are very implementation-specific, so this base
 
4147
  // class does not handle any details of settings lights. It does however
 
4148
  // display warning messages that the functions are not available.
 
4149
 
 
4150
 
 
4151
  public void lights() {
 
4152
    showMethodWarning("lights");
 
4153
  }
 
4154
 
 
4155
  public void noLights() {
 
4156
    showMethodWarning("noLights");
 
4157
  }
 
4158
 
 
4159
  public void ambientLight(float red, float green, float blue) {
 
4160
    showMethodWarning("ambientLight");
 
4161
  }
 
4162
 
 
4163
  public void ambientLight(float red, float green, float blue,
 
4164
                           float x, float y, float z) {
 
4165
    showMethodWarning("ambientLight");
 
4166
  }
 
4167
 
 
4168
  public void directionalLight(float red, float green, float blue,
 
4169
                               float nx, float ny, float nz) {
 
4170
    showMethodWarning("directionalLight");
 
4171
  }
 
4172
 
 
4173
  public void pointLight(float red, float green, float blue,
 
4174
                         float x, float y, float z) {
 
4175
    showMethodWarning("pointLight");
 
4176
  }
 
4177
 
 
4178
  public void spotLight(float red, float green, float blue,
 
4179
                        float x, float y, float z,
 
4180
                        float nx, float ny, float nz,
 
4181
                        float angle, float concentration) {
 
4182
    showMethodWarning("spotLight");
 
4183
  }
 
4184
 
 
4185
  public void lightFalloff(float constant, float linear, float quadratic) {
 
4186
    showMethodWarning("lightFalloff");
 
4187
  }
 
4188
 
 
4189
  public void lightSpecular(float x, float y, float z) {
 
4190
    showMethodWarning("lightSpecular");
 
4191
  }
 
4192
 
 
4193
 
 
4194
 
 
4195
  //////////////////////////////////////////////////////////////
 
4196
 
 
4197
  // BACKGROUND
 
4198
 
 
4199
  /**
 
4200
   * Set the background to a gray or ARGB color.
 
4201
   * <p>
 
4202
   * For the main drawing surface, the alpha value will be ignored. However,
 
4203
   * alpha can be used on PGraphics objects from createGraphics(). This is
 
4204
   * the only way to set all the pixels partially transparent, for instance.
 
4205
   * <p>
 
4206
   * Note that background() should be called before any transformations occur,
 
4207
   * because some implementations may require the current transformation matrix
 
4208
   * to be identity before drawing.
 
4209
   */
 
4210
  public void background(int rgb) {
 
4211
//    if (((rgb & 0xff000000) == 0) && (rgb <= colorModeX)) {
 
4212
//      background((float) rgb);
 
4213
//
 
4214
//    } else {
 
4215
//      if (format == RGB) {
 
4216
//        rgb |= 0xff000000;  // ignore alpha for main drawing surface
 
4217
//      }
 
4218
//      colorCalcARGB(rgb, colorModeA);
 
4219
//      backgroundFromCalc();
 
4220
//      backgroundImpl();
 
4221
//    }
 
4222
    colorCalc(rgb);
 
4223
    backgroundFromCalc();
 
4224
  }
 
4225
 
 
4226
 
 
4227
  /**
 
4228
   * See notes about alpha in background(x, y, z, a).
 
4229
   */
 
4230
  public void background(int rgb, float alpha) {
 
4231
//    if (format == RGB) {
 
4232
//      background(rgb);  // ignore alpha for main drawing surface
 
4233
//
 
4234
//    } else {
 
4235
//      if (((rgb & 0xff000000) == 0) && (rgb <= colorModeX)) {
 
4236
//        background((float) rgb, alpha);
 
4237
//
 
4238
//      } else {
 
4239
//        colorCalcARGB(rgb, alpha);
 
4240
//        backgroundFromCalc();
 
4241
//        backgroundImpl();
 
4242
//      }
 
4243
//    }
 
4244
    colorCalc(rgb, alpha);
 
4245
    backgroundFromCalc();
 
4246
  }
 
4247
 
 
4248
 
 
4249
  /**
 
4250
   * Set the background to a grayscale value, based on the
 
4251
   * current colorMode.
 
4252
   */
 
4253
  public void background(float gray) {
 
4254
    colorCalc(gray);
 
4255
    backgroundFromCalc();
 
4256
//    backgroundImpl();
 
4257
  }
 
4258
 
 
4259
 
 
4260
  /**
 
4261
   * See notes about alpha in background(x, y, z, a).
 
4262
   */
 
4263
  public void background(float gray, float alpha) {
 
4264
    if (format == RGB) {
 
4265
      background(gray);  // ignore alpha for main drawing surface
 
4266
 
 
4267
    } else {
 
4268
      colorCalc(gray, alpha);
 
4269
      backgroundFromCalc();
 
4270
//      backgroundImpl();
 
4271
    }
 
4272
  }
 
4273
 
 
4274
 
 
4275
  /**
 
4276
   * Set the background to an r, g, b or h, s, b value,
 
4277
   * based on the current colorMode.
 
4278
   */
 
4279
  public void background(float x, float y, float z) {
 
4280
    colorCalc(x, y, z);
 
4281
    backgroundFromCalc();
 
4282
//    backgroundImpl();
 
4283
  }
 
4284
 
 
4285
 
 
4286
  /**
 
4287
   * Clear the background with a color that includes an alpha value. This can
 
4288
   * only be used with objects created by createGraphics(), because the main
 
4289
   * drawing surface cannot be set transparent.
 
4290
   * <p>
 
4291
   * It might be tempting to use this function to partially clear the screen
 
4292
   * on each frame, however that's not how this function works. When calling
 
4293
   * background(), the pixels will be replaced with pixels that have that level
 
4294
   * of transparency. To do a semi-transparent overlay, use fill() with alpha
 
4295
   * and draw a rectangle.
 
4296
   */
 
4297
  public void background(float x, float y, float z, float a) {
 
4298
//    if (format == RGB) {
 
4299
//      background(x, y, z);  // don't allow people to set alpha
 
4300
//
 
4301
//    } else {
 
4302
//      colorCalc(x, y, z, a);
 
4303
//      backgroundFromCalc();
 
4304
//      backgroundImpl();
 
4305
//    }
 
4306
    colorCalc(x, y, z, a);
 
4307
    backgroundFromCalc();
 
4308
  }
 
4309
 
 
4310
 
 
4311
  protected void backgroundFromCalc() {
 
4312
    backgroundR = calcR;
 
4313
    backgroundG = calcG;
 
4314
    backgroundB = calcB;
 
4315
    backgroundA = (format == RGB) ? colorModeA : calcA;
 
4316
    backgroundRi = calcRi;
 
4317
    backgroundGi = calcGi;
 
4318
    backgroundBi = calcBi;
 
4319
    backgroundAi = (format == RGB) ? 255 : calcAi;
 
4320
    backgroundAlpha = (format == RGB) ? false : calcAlpha;
 
4321
    backgroundColor = calcColor;
 
4322
 
 
4323
    backgroundImpl();
 
4324
  }
 
4325
 
 
4326
 
 
4327
  /**
 
4328
   * Takes an RGB or ARGB image and sets it as the background.
 
4329
   * The width and height of the image must be the same size as the sketch.
 
4330
   * Use image.resize(width, height) to make short work of such a task.
 
4331
   * <P>
 
4332
   * Note that even if the image is set as RGB, the high 8 bits of each pixel
 
4333
   * should be set opaque (0xFF000000), because the image data will be copied
 
4334
   * directly to the screen, and non-opaque background images may have strange
 
4335
   * behavior. Using image.filter(OPAQUE) will handle this easily.
 
4336
   * <P>
 
4337
   * When using 3D, this will also clear the zbuffer (if it exists).
 
4338
   */
 
4339
  public void background(PImage image) {
 
4340
    if ((image.width != width) || (image.height != height)) {
 
4341
      throw new RuntimeException(ERROR_BACKGROUND_IMAGE_SIZE);
 
4342
    }
 
4343
    if ((image.format != RGB) && (image.format != ARGB)) {
 
4344
      throw new RuntimeException(ERROR_BACKGROUND_IMAGE_FORMAT);
 
4345
    }
 
4346
    backgroundColor = 0;  // just zero it out for images
 
4347
    backgroundImpl(image);
 
4348
  }
 
4349
 
 
4350
 
 
4351
  /**
 
4352
   * Actually set the background image. This is separated from the error
 
4353
   * handling and other semantic goofiness that is shared across renderers.
 
4354
   */
 
4355
  protected void backgroundImpl(PImage image) {
 
4356
    // blit image to the screen
 
4357
    set(0, 0, image);
 
4358
  }
 
4359
 
 
4360
 
 
4361
  /**
 
4362
   * Actual implementation of clearing the background, now that the
 
4363
   * internal variables for background color have been set. Called by the
 
4364
   * backgroundFromCalc() method, which is what all the other background()
 
4365
   * methods call once the work is done.
 
4366
   */
 
4367
  protected void backgroundImpl() {
 
4368
    pushStyle();
 
4369
    pushMatrix();
 
4370
    resetMatrix();
 
4371
    fill(backgroundColor);
 
4372
    rect(0, 0, width, height);
 
4373
    popMatrix();
 
4374
    popStyle();
 
4375
  }
 
4376
 
 
4377
 
 
4378
  /**
 
4379
   * Callback to handle clearing the background when begin/endRaw is in use.
 
4380
   * Handled as separate function for OpenGL (or other) subclasses that
 
4381
   * override backgroundImpl() but still needs this to work properly.
 
4382
   */
 
4383
//  protected void backgroundRawImpl() {
 
4384
//    if (raw != null) {
 
4385
//      raw.colorMode(RGB, 1);
 
4386
//      raw.noStroke();
 
4387
//      raw.fill(backgroundR, backgroundG, backgroundB);
 
4388
//      raw.beginShape(TRIANGLES);
 
4389
//
 
4390
//      raw.vertex(0, 0);
 
4391
//      raw.vertex(width, 0);
 
4392
//      raw.vertex(0, height);
 
4393
//
 
4394
//      raw.vertex(width, 0);
 
4395
//      raw.vertex(width, height);
 
4396
//      raw.vertex(0, height);
 
4397
//
 
4398
//      raw.endShape();
 
4399
//    }
 
4400
//  }
 
4401
 
 
4402
 
 
4403
 
 
4404
  //////////////////////////////////////////////////////////////
 
4405
 
 
4406
  // COLOR MODE
 
4407
 
 
4408
 
 
4409
  public void colorMode(int mode) {
 
4410
    colorMode(mode, colorModeX, colorModeY, colorModeZ, colorModeA);
 
4411
  }
 
4412
 
 
4413
 
 
4414
  public void colorMode(int mode, float max) {
 
4415
    colorMode(mode, max, max, max, max);
 
4416
  }
 
4417
 
 
4418
 
 
4419
  /**
 
4420
   * Set the colorMode and the maximum values for (r, g, b)
 
4421
   * or (h, s, b).
 
4422
   * <P>
 
4423
   * Note that this doesn't set the maximum for the alpha value,
 
4424
   * which might be confusing if for instance you switched to
 
4425
   * <PRE>colorMode(HSB, 360, 100, 100);</PRE>
 
4426
   * because the alpha values were still between 0 and 255.
 
4427
   */
 
4428
  public void colorMode(int mode, float maxX, float maxY, float maxZ) {
 
4429
    colorMode(mode, maxX, maxY, maxZ, colorModeA);
 
4430
  }
 
4431
 
 
4432
 
 
4433
  public void colorMode(int mode,
 
4434
                        float maxX, float maxY, float maxZ, float maxA) {
 
4435
    colorMode = mode;
 
4436
 
 
4437
    colorModeX = maxX;  // still needs to be set for hsb
 
4438
    colorModeY = maxY;
 
4439
    colorModeZ = maxZ;
 
4440
    colorModeA = maxA;
 
4441
 
 
4442
    // if color max values are all 1, then no need to scale
 
4443
    colorModeScale =
 
4444
      ((maxA != 1) || (maxX != maxY) || (maxY != maxZ) || (maxZ != maxA));
 
4445
 
 
4446
    // if color is rgb/0..255 this will make it easier for the
 
4447
    // red() green() etc functions
 
4448
    colorModeDefault = (colorMode == RGB) &&
 
4449
      (colorModeA == 255) && (colorModeX == 255) &&
 
4450
      (colorModeY == 255) && (colorModeZ == 255);
 
4451
  }
 
4452
 
 
4453
 
 
4454
 
 
4455
  //////////////////////////////////////////////////////////////
 
4456
 
 
4457
  // COLOR CALCULATIONS
 
4458
 
 
4459
  // Given input values for coloring, these functions will fill the calcXxxx
 
4460
  // variables with values that have been properly filtered through the
 
4461
  // current colorMode settings.
 
4462
 
 
4463
  // Renderers that need to subclass any drawing properties such as fill or
 
4464
  // stroke will usally want to override methods like fillFromCalc (or the
 
4465
  // same for stroke, ambient, etc.) That way the color calcuations are
 
4466
  // covered by this based PGraphics class, leaving only a single function
 
4467
  // to override/implement in the subclass.
 
4468
 
 
4469
 
 
4470
  /**
 
4471
   * Set the fill to either a grayscale value or an ARGB int.
 
4472
   * <P>
 
4473
   * The problem with this code is that it has to detect between these two
 
4474
   * situations automatically. This is done by checking to see if the high bits
 
4475
   * (the alpha for 0xAA000000) is set, and if not, whether the color value
 
4476
   * that follows is less than colorModeX (first param passed to colorMode).
 
4477
   * <P>
 
4478
   * This auto-detect would break in the following situation:
 
4479
   * <PRE>size(256, 256);
 
4480
   * for (int i = 0; i < 256; i++) {
 
4481
   *   color c = color(0, 0, 0, i);
 
4482
   *   stroke(c);
 
4483
   *   line(i, 0, i, 256);
 
4484
   * }</PRE>
 
4485
   * ...on the first time through the loop, where (i == 0), since the color
 
4486
   * itself is zero (black) then it would appear indistinguishable from code
 
4487
   * that reads "fill(0)". The solution is to use the four parameter versions
 
4488
   * of stroke or fill to more directly specify the desired result.
 
4489
   */
 
4490
  protected void colorCalc(int rgb) {
 
4491
    if (((rgb & 0xff000000) == 0) && (rgb <= colorModeX)) {
 
4492
      colorCalc((float) rgb);
 
4493
 
 
4494
    } else {
 
4495
      colorCalcARGB(rgb, colorModeA);
 
4496
    }
 
4497
  }
 
4498
 
 
4499
 
 
4500
  protected void colorCalc(int rgb, float alpha) {
 
4501
    if (((rgb & 0xff000000) == 0) && (rgb <= colorModeX)) {  // see above
 
4502
      colorCalc((float) rgb, alpha);
 
4503
 
 
4504
    } else {
 
4505
      colorCalcARGB(rgb, alpha);
 
4506
    }
 
4507
  }
 
4508
 
 
4509
 
 
4510
  protected void colorCalc(float gray) {
 
4511
    colorCalc(gray, colorModeA);
 
4512
  }
 
4513
 
 
4514
 
 
4515
  protected void colorCalc(float gray, float alpha) {
 
4516
    if (gray > colorModeX) gray = colorModeX;
 
4517
    if (alpha > colorModeA) alpha = colorModeA;
 
4518
 
 
4519
    if (gray < 0) gray = 0;
 
4520
    if (alpha < 0) alpha = 0;
 
4521
 
 
4522
    calcR = colorModeScale ? (gray / colorModeX) : gray;
 
4523
    calcG = calcR;
 
4524
    calcB = calcR;
 
4525
    calcA = colorModeScale ? (alpha / colorModeA) : alpha;
 
4526
 
 
4527
    calcRi = (int)(calcR*255); calcGi = (int)(calcG*255);
 
4528
    calcBi = (int)(calcB*255); calcAi = (int)(calcA*255);
 
4529
    calcColor = (calcAi << 24) | (calcRi << 16) | (calcGi << 8) | calcBi;
 
4530
    calcAlpha = (calcAi != 255);
 
4531
  }
 
4532
 
 
4533
 
 
4534
  protected void colorCalc(float x, float y, float z) {
 
4535
    colorCalc(x, y, z, colorModeA);
 
4536
  }
 
4537
 
 
4538
 
 
4539
  protected void colorCalc(float x, float y, float z, float a) {
 
4540
    if (x > colorModeX) x = colorModeX;
 
4541
    if (y > colorModeY) y = colorModeY;
 
4542
    if (z > colorModeZ) z = colorModeZ;
 
4543
    if (a > colorModeA) a = colorModeA;
 
4544
 
 
4545
    if (x < 0) x = 0;
 
4546
    if (y < 0) y = 0;
 
4547
    if (z < 0) z = 0;
 
4548
    if (a < 0) a = 0;
 
4549
 
 
4550
    switch (colorMode) {
 
4551
    case RGB:
 
4552
      if (colorModeScale) {
 
4553
        calcR = x / colorModeX;
 
4554
        calcG = y / colorModeY;
 
4555
        calcB = z / colorModeZ;
 
4556
        calcA = a / colorModeA;
 
4557
      } else {
 
4558
        calcR = x; calcG = y; calcB = z; calcA = a;
 
4559
      }
 
4560
      break;
 
4561
 
 
4562
    case HSB:
 
4563
      x /= colorModeX; // h
 
4564
      y /= colorModeY; // s
 
4565
      z /= colorModeZ; // b
 
4566
 
 
4567
      calcA = colorModeScale ? (a/colorModeA) : a;
 
4568
 
 
4569
      if (y == 0) {  // saturation == 0
 
4570
        calcR = calcG = calcB = z;
 
4571
 
 
4572
      } else {
 
4573
        float which = (x - (int)x) * 6.0f;
 
4574
        float f = which - (int)which;
 
4575
        float p = z * (1.0f - y);
 
4576
        float q = z * (1.0f - y * f);
 
4577
        float t = z * (1.0f - (y * (1.0f - f)));
 
4578
 
 
4579
        switch ((int)which) {
 
4580
        case 0: calcR = z; calcG = t; calcB = p; break;
 
4581
        case 1: calcR = q; calcG = z; calcB = p; break;
 
4582
        case 2: calcR = p; calcG = z; calcB = t; break;
 
4583
        case 3: calcR = p; calcG = q; calcB = z; break;
 
4584
        case 4: calcR = t; calcG = p; calcB = z; break;
 
4585
        case 5: calcR = z; calcG = p; calcB = q; break;
 
4586
        }
 
4587
      }
 
4588
      break;
 
4589
    }
 
4590
    calcRi = (int)(255*calcR); calcGi = (int)(255*calcG);
 
4591
    calcBi = (int)(255*calcB); calcAi = (int)(255*calcA);
 
4592
    calcColor = (calcAi << 24) | (calcRi << 16) | (calcGi << 8) | calcBi;
 
4593
    calcAlpha = (calcAi != 255);
 
4594
  }
 
4595
 
 
4596
 
 
4597
  /**
 
4598
   * Unpacks AARRGGBB color for direct use with colorCalc.
 
4599
   * <P>
 
4600
   * Handled here with its own function since this is indepenent
 
4601
   * of the color mode.
 
4602
   * <P>
 
4603
   * Strangely the old version of this code ignored the alpha
 
4604
   * value. not sure if that was a bug or what.
 
4605
   * <P>
 
4606
   * Note, no need for a bounds check since it's a 32 bit number.
 
4607
   */
 
4608
  protected void colorCalcARGB(int argb, float alpha) {
 
4609
    if (alpha == colorModeA) {
 
4610
      calcAi = (argb >> 24) & 0xff;
 
4611
      calcColor = argb;
 
4612
    } else {
 
4613
      calcAi = (int) (((argb >> 24) & 0xff) * (alpha / colorModeA));
 
4614
      calcColor = (calcAi << 24) | (argb & 0xFFFFFF);
 
4615
    }
 
4616
    calcRi = (argb >> 16) & 0xff;
 
4617
    calcGi = (argb >> 8) & 0xff;
 
4618
    calcBi = argb & 0xff;
 
4619
    calcA = (float)calcAi / 255.0f;
 
4620
    calcR = (float)calcRi / 255.0f;
 
4621
    calcG = (float)calcGi / 255.0f;
 
4622
    calcB = (float)calcBi / 255.0f;
 
4623
    calcAlpha = (calcAi != 255);
 
4624
  }
 
4625
 
 
4626
 
 
4627
 
 
4628
  //////////////////////////////////////////////////////////////
 
4629
 
 
4630
  // COLOR DATATYPE STUFFING
 
4631
 
 
4632
  // The 'color' primitive type in Processing syntax is in fact a 32-bit int.
 
4633
  // These functions handle stuffing color values into a 32-bit cage based
 
4634
  // on the current colorMode settings.
 
4635
 
 
4636
  // These functions are really slow (because they take the current colorMode
 
4637
  // into account), but they're easy to use. Advanced users can write their
 
4638
  // own bit shifting operations to setup 'color' data types.
 
4639
 
 
4640
 
 
4641
  public final int color(int gray) {  // ignore
 
4642
    if (((gray & 0xff000000) == 0) && (gray <= colorModeX)) {
 
4643
      if (colorModeDefault) {
 
4644
        // bounds checking to make sure the numbers aren't to high or low
 
4645
        if (gray > 255) gray = 255; else if (gray < 0) gray = 0;
 
4646
        return 0xff000000 | (gray << 16) | (gray << 8) | gray;
 
4647
      } else {
 
4648
        colorCalc(gray);
 
4649
      }
 
4650
    } else {
 
4651
      colorCalcARGB(gray, colorModeA);
 
4652
    }
 
4653
    return calcColor;
 
4654
  }
 
4655
 
 
4656
 
 
4657
  public final int color(float gray) {  // ignore
 
4658
    colorCalc(gray);
 
4659
    return calcColor;
 
4660
  }
 
4661
 
 
4662
 
 
4663
  /**
 
4664
   * @param gray can be packed ARGB or a gray in this case
 
4665
   */
 
4666
  public final int color(int gray, int alpha) {  // ignore
 
4667
    if (colorModeDefault) {
 
4668
      // bounds checking to make sure the numbers aren't to high or low
 
4669
      if (gray > 255) gray = 255; else if (gray < 0) gray = 0;
 
4670
      if (alpha > 255) alpha = 255; else if (alpha < 0) alpha = 0;
 
4671
 
 
4672
      return ((alpha & 0xff) << 24) | (gray << 16) | (gray << 8) | gray;
 
4673
    }
 
4674
    colorCalc(gray, alpha);
 
4675
    return calcColor;
 
4676
  }
 
4677
 
 
4678
 
 
4679
  /**
 
4680
   * @param rgb can be packed ARGB or a gray in this case
 
4681
   */
 
4682
  public final int color(int rgb, float alpha) {  // ignore
 
4683
    if (((rgb & 0xff000000) == 0) && (rgb <= colorModeX)) {
 
4684
      colorCalc(rgb, alpha);
 
4685
    } else {
 
4686
      colorCalcARGB(rgb, alpha);
 
4687
    }
 
4688
    return calcColor;
 
4689
  }
 
4690
 
 
4691
 
 
4692
  public final int color(float gray, float alpha) {  // ignore
 
4693
    colorCalc(gray, alpha);
 
4694
    return calcColor;
 
4695
  }
 
4696
 
 
4697
 
 
4698
  public final int color(int x, int y, int z) {  // ignore
 
4699
    if (colorModeDefault) {
 
4700
      // bounds checking to make sure the numbers aren't to high or low
 
4701
      if (x > 255) x = 255; else if (x < 0) x = 0;
 
4702
      if (y > 255) y = 255; else if (y < 0) y = 0;
 
4703
      if (z > 255) z = 255; else if (z < 0) z = 0;
 
4704
 
 
4705
      return 0xff000000 | (x << 16) | (y << 8) | z;
 
4706
    }
 
4707
    colorCalc(x, y, z);
 
4708
    return calcColor;
 
4709
  }
 
4710
 
 
4711
 
 
4712
  public final int color(float x, float y, float z) {  // ignore
 
4713
    colorCalc(x, y, z);
 
4714
    return calcColor;
 
4715
  }
 
4716
 
 
4717
 
 
4718
  public final int color(int x, int y, int z, int a) {  // ignore
 
4719
    if (colorModeDefault) {
 
4720
      // bounds checking to make sure the numbers aren't to high or low
 
4721
      if (a > 255) a = 255; else if (a < 0) a = 0;
 
4722
      if (x > 255) x = 255; else if (x < 0) x = 0;
 
4723
      if (y > 255) y = 255; else if (y < 0) y = 0;
 
4724
      if (z > 255) z = 255; else if (z < 0) z = 0;
 
4725
 
 
4726
      return (a << 24) | (x << 16) | (y << 8) | z;
 
4727
    }
 
4728
    colorCalc(x, y, z, a);
 
4729
    return calcColor;
 
4730
  }
 
4731
 
 
4732
 
 
4733
  public final int color(float x, float y, float z, float a) {  // ignore
 
4734
    colorCalc(x, y, z, a);
 
4735
    return calcColor;
 
4736
  }
 
4737
 
 
4738
 
 
4739
 
 
4740
  //////////////////////////////////////////////////////////////
 
4741
 
 
4742
  // COLOR DATATYPE EXTRACTION
 
4743
 
 
4744
  // Vee have veys of making the colors talk.
 
4745
 
 
4746
 
 
4747
  public final float alpha(int what) {
 
4748
    float c = (what >> 24) & 0xff;
 
4749
    if (colorModeA == 255) return c;
 
4750
    return (c / 255.0f) * colorModeA;
 
4751
  }
 
4752
 
 
4753
 
 
4754
  public final float red(int what) {
 
4755
    float c = (what >> 16) & 0xff;
 
4756
    if (colorModeDefault) return c;
 
4757
    return (c / 255.0f) * colorModeX;
 
4758
  }
 
4759
 
 
4760
 
 
4761
  public final float green(int what) {
 
4762
    float c = (what >> 8) & 0xff;
 
4763
    if (colorModeDefault) return c;
 
4764
    return (c / 255.0f) * colorModeY;
 
4765
  }
 
4766
 
 
4767
 
 
4768
  public final float blue(int what) {
 
4769
    float c = (what) & 0xff;
 
4770
    if (colorModeDefault) return c;
 
4771
    return (c / 255.0f) * colorModeZ;
 
4772
  }
 
4773
 
 
4774
 
 
4775
  public final float hue(int what) {
 
4776
    if (what != cacheHsbKey) {
 
4777
      Color.RGBtoHSB((what >> 16) & 0xff, (what >> 8) & 0xff,
 
4778
                     what & 0xff, cacheHsbValue);
 
4779
      cacheHsbKey = what;
 
4780
    }
 
4781
    return cacheHsbValue[0] * colorModeX;
 
4782
  }
 
4783
 
 
4784
 
 
4785
  public final float saturation(int what) {
 
4786
    if (what != cacheHsbKey) {
 
4787
      Color.RGBtoHSB((what >> 16) & 0xff, (what >> 8) & 0xff,
 
4788
                     what & 0xff, cacheHsbValue);
 
4789
      cacheHsbKey = what;
 
4790
    }
 
4791
    return cacheHsbValue[1] * colorModeY;
 
4792
  }
 
4793
 
 
4794
 
 
4795
  public final float brightness(int what) {
 
4796
    if (what != cacheHsbKey) {
 
4797
      Color.RGBtoHSB((what >> 16) & 0xff, (what >> 8) & 0xff,
 
4798
                     what & 0xff, cacheHsbValue);
 
4799
      cacheHsbKey = what;
 
4800
    }
 
4801
    return cacheHsbValue[2] * colorModeZ;
 
4802
  }
 
4803
 
 
4804
 
 
4805
 
 
4806
  //////////////////////////////////////////////////////////////
 
4807
 
 
4808
  // COLOR DATATYPE INTERPOLATION
 
4809
 
 
4810
  // Against our better judgement.
 
4811
 
 
4812
 
 
4813
  /**
 
4814
   * Interpolate between two colors, using the current color mode.
 
4815
   */
 
4816
  public int lerpColor(int c1, int c2, float amt) {
 
4817
    return lerpColor(c1, c2, amt, colorMode);
 
4818
  }
 
4819
 
 
4820
  static float[] lerpColorHSB1;
 
4821
  static float[] lerpColorHSB2;
 
4822
 
 
4823
  /**
 
4824
   * Interpolate between two colors. Like lerp(), but for the
 
4825
   * individual color components of a color supplied as an int value.
 
4826
   */
 
4827
  static public int lerpColor(int c1, int c2, float amt, int mode) {
 
4828
    if (mode == RGB) {
 
4829
      float a1 = ((c1 >> 24) & 0xff);
 
4830
      float r1 = (c1 >> 16) & 0xff;
 
4831
      float g1 = (c1 >> 8) & 0xff;
 
4832
      float b1 = c1 & 0xff;
 
4833
      float a2 = (c2 >> 24) & 0xff;
 
4834
      float r2 = (c2 >> 16) & 0xff;
 
4835
      float g2 = (c2 >> 8) & 0xff;
 
4836
      float b2 = c2 & 0xff;
 
4837
 
 
4838
      return (((int) (a1 + (a2-a1)*amt) << 24) |
 
4839
              ((int) (r1 + (r2-r1)*amt) << 16) |
 
4840
              ((int) (g1 + (g2-g1)*amt) << 8) |
 
4841
              ((int) (b1 + (b2-b1)*amt)));
 
4842
 
 
4843
    } else if (mode == HSB) {
 
4844
      if (lerpColorHSB1 == null) {
 
4845
        lerpColorHSB1 = new float[3];
 
4846
        lerpColorHSB2 = new float[3];
 
4847
      }
 
4848
 
 
4849
      float a1 = (c1 >> 24) & 0xff;
 
4850
      float a2 = (c2 >> 24) & 0xff;
 
4851
      int alfa = ((int) (a1 + (a2-a1)*amt)) << 24;
 
4852
 
 
4853
      Color.RGBtoHSB((c1 >> 16) & 0xff, (c1 >> 8) & 0xff, c1 & 0xff,
 
4854
                     lerpColorHSB1);
 
4855
      Color.RGBtoHSB((c2 >> 16) & 0xff, (c2 >> 8) & 0xff, c2 & 0xff,
 
4856
                     lerpColorHSB2);
 
4857
 
 
4858
      /* If mode is HSB, this will take the shortest path around the
 
4859
       * color wheel to find the new color. For instance, red to blue
 
4860
       * will go red violet blue (backwards in hue space) rather than
 
4861
       * cycling through ROYGBIV.
 
4862
       */
 
4863
      // Disabling rollover (wasn't working anyway) for 0126.
 
4864
      // Otherwise it makes full spectrum scale impossible for
 
4865
      // those who might want it...in spite of how despicable
 
4866
      // a full spectrum scale might be.
 
4867
      // roll around when 0.9 to 0.1
 
4868
      // more than 0.5 away means that it should roll in the other direction
 
4869
      /*
 
4870
      float h1 = lerpColorHSB1[0];
 
4871
      float h2 = lerpColorHSB2[0];
 
4872
      if (Math.abs(h1 - h2) > 0.5f) {
 
4873
        if (h1 > h2) {
 
4874
          // i.e. h1 is 0.7, h2 is 0.1
 
4875
          h2 += 1;
 
4876
        } else {
 
4877
          // i.e. h1 is 0.1, h2 is 0.7
 
4878
          h1 += 1;
 
4879
        }
 
4880
      }
 
4881
      float ho = (PApplet.lerp(lerpColorHSB1[0], lerpColorHSB2[0], amt)) % 1.0f;
 
4882
      */
 
4883
      float ho = PApplet.lerp(lerpColorHSB1[0], lerpColorHSB2[0], amt);
 
4884
      float so = PApplet.lerp(lerpColorHSB1[1], lerpColorHSB2[1], amt);
 
4885
      float bo = PApplet.lerp(lerpColorHSB1[2], lerpColorHSB2[2], amt);
 
4886
 
 
4887
      return alfa | (Color.HSBtoRGB(ho, so, bo) & 0xFFFFFF);
 
4888
    }
 
4889
    return 0;
 
4890
  }
 
4891
 
 
4892
 
 
4893
 
 
4894
  //////////////////////////////////////////////////////////////
 
4895
 
 
4896
  // BEGINRAW/ENDRAW
 
4897
 
 
4898
 
 
4899
  /**
 
4900
   * Record individual lines and triangles by echoing them to another renderer.
 
4901
   */
 
4902
  public void beginRaw(PGraphics rawGraphics) {  // ignore
 
4903
    this.raw = rawGraphics;
 
4904
    rawGraphics.beginDraw();
 
4905
  }
 
4906
 
 
4907
 
 
4908
  public void endRaw() {  // ignore
 
4909
    if (raw != null) {
 
4910
      // for 3D, need to flush any geometry that's been stored for sorting
 
4911
      // (particularly if the ENABLE_DEPTH_SORT hint is set)
 
4912
      flush();
 
4913
 
 
4914
      // just like beginDraw, this will have to be called because
 
4915
      // endDraw() will be happening outside of draw()
 
4916
      raw.endDraw();
 
4917
      raw.dispose();
 
4918
      raw = null;
 
4919
    }
 
4920
  }
 
4921
 
 
4922
 
 
4923
 
 
4924
  //////////////////////////////////////////////////////////////
 
4925
 
 
4926
  // WARNINGS and EXCEPTIONS
 
4927
 
 
4928
 
 
4929
  static protected HashMap<String, Object> warnings;
 
4930
 
 
4931
 
 
4932
  /**
 
4933
   * Show a renderer error, and keep track of it so that it's only shown once.
 
4934
   * @param msg the error message (which will be stored for later comparison)
 
4935
   */
 
4936
  static public void showWarning(String msg) {  // ignore
 
4937
    if (warnings == null) {
 
4938
      warnings = new HashMap<String, Object>();
 
4939
    }
 
4940
    if (!warnings.containsKey(msg)) {
 
4941
      System.err.println(msg);
 
4942
      warnings.put(msg, new Object());
 
4943
    }
 
4944
  }
 
4945
 
 
4946
 
 
4947
  /**
 
4948
   * Display a warning that the specified method is only available with 3D.
 
4949
   * @param method The method name (no parentheses)
 
4950
   */
 
4951
  static protected void showDepthWarning(String method) {
 
4952
    showWarning(method + "() can only be used with a renderer that " +
 
4953
                "supports 3D, such as P3D or OPENGL.");
 
4954
  }
 
4955
 
 
4956
 
 
4957
  /**
 
4958
   * Display a warning that the specified method that takes x, y, z parameters
 
4959
   * can only be used with x and y parameters in this renderer.
 
4960
   * @param method The method name (no parentheses)
 
4961
   */
 
4962
  static protected void showDepthWarningXYZ(String method) {
 
4963
    showWarning(method + "() with x, y, and z coordinates " +
 
4964
                "can only be used with a renderer that " +
 
4965
                "supports 3D, such as P3D or OPENGL. " +
 
4966
                "Use a version without a z-coordinate instead.");
 
4967
  }
 
4968
 
 
4969
 
 
4970
  /**
 
4971
   * Display a warning that the specified method is simply unavailable.
 
4972
   */
 
4973
  static protected void showMethodWarning(String method) {
 
4974
    showWarning(method + "() is not available with this renderer.");
 
4975
  }
 
4976
 
 
4977
 
 
4978
  /**
 
4979
   * Error that a particular variation of a method is unavailable (even though
 
4980
   * other variations are). For instance, if vertex(x, y, u, v) is not
 
4981
   * available, but vertex(x, y) is just fine.
 
4982
   */
 
4983
  static protected void showVariationWarning(String str) {
 
4984
    showWarning(str + " is not available with this renderer.");
 
4985
  }
 
4986
 
 
4987
 
 
4988
  /**
 
4989
   * Display a warning that the specified method is not implemented, meaning
 
4990
   * that it could be either a completely missing function, although other
 
4991
   * variations of it may still work properly.
 
4992
   */
 
4993
  static protected void showMissingWarning(String method) {
 
4994
    showWarning(method + "(), or this particular variation of it, " +
 
4995
                "is not available with this renderer.");
 
4996
  }
 
4997
 
 
4998
 
 
4999
  /**
 
5000
   * Show an renderer-related exception that halts the program. Currently just
 
5001
   * wraps the message as a RuntimeException and throws it, but might do
 
5002
   * something more specific might be used in the future.
 
5003
   */
 
5004
  static public void showException(String msg) {  // ignore
 
5005
    throw new RuntimeException(msg);
 
5006
  }
 
5007
 
 
5008
 
 
5009
  /**
 
5010
   * Throw an exeption that halts the program because textFont() has not been
 
5011
   * used prior to the specified method.
 
5012
   */
 
5013
  static protected void showTextFontException(String method) {
 
5014
    throw new RuntimeException("Use textFont() before " + method + "()");
 
5015
  }
 
5016
 
 
5017
 
 
5018
 
 
5019
  //////////////////////////////////////////////////////////////
 
5020
 
 
5021
  // RENDERER SUPPORT QUERIES
 
5022
 
 
5023
 
 
5024
  /**
 
5025
   * Return true if this renderer should be drawn to the screen. Defaults to
 
5026
   * returning true, since nearly all renderers are on-screen beasts. But can
 
5027
   * be overridden for subclasses like PDF so that a window doesn't open up.
 
5028
   * <br/> <br/>
 
5029
   * A better name? showFrame, displayable, isVisible, visible, shouldDisplay,
 
5030
   * what to call this?
 
5031
   */
 
5032
  public boolean displayable() {
 
5033
    return true;
 
5034
  }
 
5035
 
 
5036
 
 
5037
  /**
 
5038
   * Return true if this renderer supports 2D drawing. Defaults to true.
 
5039
   */
 
5040
  public boolean is2D() {
 
5041
    return true;
 
5042
  }
 
5043
 
 
5044
 
 
5045
  /**
 
5046
   * Return true if this renderer supports 2D drawing. Defaults to true.
 
5047
   */
 
5048
  public boolean is3D() {
 
5049
    return false;
 
5050
  }
 
5051
}