1
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
4
Part of the Processing project - http://processing.org
6
Copyright (c) 2004-09 Ben Fry and Casey Reas
7
Copyright (c) 2001-04 Massachusetts Institute of Technology
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.
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.
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
25
package processing.core;
28
import java.util.HashMap;
32
* Main graphics and rendering context, as well as the base API implementation.
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.
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.
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.
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.
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.
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.
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.
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.
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—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.
110
public class PGraphics extends PImage implements PConstants {
112
// ........................................................
114
// width and height are already inherited from PImage
117
/// width minus one (useful for many calculations)
118
protected int width1;
120
/// height minus one (useful for many calculations)
121
protected int height1;
123
/// width * height (useful for many calculations)
124
public int pixelCount;
126
/// true if smoothing is enabled (read-only)
127
public boolean smooth = false;
129
// ........................................................
131
/// true if defaults() has been called a first time
132
protected boolean settingsInited;
134
/// set to a PGraphics object being used inside a beginRaw/endRaw() block
135
protected PGraphics raw;
137
// ........................................................
139
/** path to the file being saved for this renderer (if any) */
140
protected String path;
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.
148
protected boolean primarySurface;
150
// ........................................................
153
* Array of hint[] items. These are hacks to get around various
154
* temporary workarounds inside the environment.
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.
161
* The hints[] array is allocated early on because it might
162
* be used inside beginDraw(), allocate(), etc.
164
protected boolean[] hints = new boolean[HINT_COUNT];
167
////////////////////////////////////////////////////////////
171
// Also inherits imageMode() and smooth() (among others) from PImage.
173
/** The current colorMode */
174
public int colorMode; // = RGB;
176
/** Max value for red (or hue) set by colorMode */
177
public float colorModeX; // = 255;
179
/** Max value for green (or saturation) set by colorMode */
180
public float colorModeY; // = 255;
182
/** Max value for blue (or value) set by colorMode */
183
public float colorModeZ; // = 255;
185
/** Max value for alpha set by colorMode */
186
public float colorModeA; // = 255;
188
/** True if colors are not in the range 0..1 */
189
boolean colorModeScale; // = true;
191
/** True if colorMode(RGB, 255) */
192
boolean colorModeDefault; // = true;
194
// ........................................................
196
// Tint color for images
199
* True if tint() is enabled (read-only).
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.
209
/** tint that was last set (read-only) */
210
public int tintColor;
212
protected boolean tintAlpha;
213
protected float tintR, tintG, tintB, tintA;
214
protected int tintRi, tintGi, tintBi, tintAi;
216
// ........................................................
220
/** true if fill() is enabled, (read-only) */
223
/** fill that was last set (read-only) */
224
public int fillColor = 0xffFFFFFF;
226
protected boolean fillAlpha;
227
protected float fillR, fillG, fillB, fillA;
228
protected int fillRi, fillGi, fillBi, fillAi;
230
// ........................................................
234
/** true if stroke() is enabled, (read-only) */
235
public boolean stroke;
237
/** stroke that was last set (read-only) */
238
public int strokeColor = 0xff000000;
240
protected boolean strokeAlpha;
241
protected float strokeR, strokeG, strokeB, strokeA;
242
protected int strokeRi, strokeGi, strokeBi, strokeAi;
244
// ........................................................
246
// Additional stroke properties
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;
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.
257
public float strokeWeight = DEFAULT_STROKE_WEIGHT;
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)
264
public int strokeJoin = DEFAULT_STROKE_JOIN;
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)
271
public int strokeCap = DEFAULT_STROKE_CAP;
273
// ........................................................
275
// Shape placement properties
277
// imageMode() is inherited from PImage
279
/** The current rect mode (read-only) */
282
/** The current ellipse mode (read-only) */
283
public int ellipseMode;
285
/** The current shape alignment mode (read-only) */
286
public int shapeMode;
288
/** The current image alignment (read-only) */
289
public int imageMode = CORNER;
291
// ........................................................
293
// Text and font properties
295
/** The current text font (read-only) */
296
public PFont textFont;
298
/** The current text align (read-only) */
299
public int textAlign = LEFT;
301
/** The current vertical text alignment (read-only) */
302
public int textAlignY = BASELINE;
304
/** The current text mode (read-only) */
305
public int textMode = MODEL;
307
/** The current text size (read-only) */
308
public float textSize;
310
/** The current text leading (read-only) */
311
public float textLeading;
313
// ........................................................
315
// Material properties
317
// PMaterial material;
318
// PMaterial[] materialStack;
319
// int materialStackPointer;
321
public float ambientR, ambientG, ambientB;
322
public float specularR, specularG, specularB;
323
public float emissiveR, emissiveG, emissiveB;
324
public float shininess;
329
static final int STYLE_STACK_DEPTH = 64;
330
PStyle[] styleStack = new PStyle[STYLE_STACK_DEPTH];
334
////////////////////////////////////////////////////////////
337
/** Last background color that was set, zero if an image */
338
public int backgroundColor = 0xffCCCCCC;
340
protected boolean backgroundAlpha;
341
protected float backgroundR, backgroundG, backgroundB, backgroundA;
342
protected int backgroundRi, backgroundGi, backgroundBi, backgroundAi;
344
// ........................................................
347
* Current model-view matrix transformation of the form m[row][column],
348
* which is a "column vector" (as opposed to "row vector") 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;
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;
361
static final int MATRIX_STACK_DEPTH = 32;
363
// ........................................................
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.
372
// ........................................................
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;
380
/** The last RGB value converted to HSB */
382
/** Result of the last conversion to HSB */
383
float[] cacheHsbValue = new float[3];
385
// ........................................................
388
* Type of shape passed to beginShape(),
389
* zero if no shape is currently being drawn.
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
399
// ........................................................
401
protected boolean bezierInited = false;
402
public int bezierDetail = 20;
404
// used by both curve and bezier, so just init here
405
protected PMatrix3D bezierBasisMatrix =
406
new PMatrix3D(-1, 3, -3, 1,
411
//protected PMatrix3D bezierForwardMatrix;
412
protected PMatrix3D bezierDrawMatrix;
414
// ........................................................
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;
423
protected PMatrix3D bezierBasisInverse;
424
protected PMatrix3D curveToBezierMatrix;
426
// ........................................................
430
protected float curveVertices[][];
431
protected int curveVertexCount;
433
// ........................................................
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
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);
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);
456
// ........................................................
458
/** The current font if a Java version of it is installed */
459
//protected Font textFontNative;
461
/** Metrics for the current native Java font */
462
//protected FontMetrics textFontNativeMetrics;
464
/** Last text position, because text often mixed on lines together */
465
protected float textX, textY, textZ;
468
* Internal buffer used by the text() functions
469
* because the String object is slow
471
protected char[] textBuffer = new char[8 * 1024];
472
protected char[] textWidthBuffer = new char[8 * 1024];
474
protected int textBreakCount;
475
protected int[] textBreakStart;
476
protected int[] textBreakStop;
478
// ........................................................
480
public boolean edge = true;
482
// ........................................................
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;
491
/// Current mode for normals, one of AUTO, SHAPE, or VERTEX
492
protected int normalMode;
494
/// Keep track of how many calls to normal, to determine the mode.
495
//protected int normalCount;
497
/** Current normal vector. */
498
public float normalX, normalY, normalZ;
500
// ........................................................
503
* Sets whether texture coordinates passed to
504
* vertex() calls will be based on coordinates that are
505
* based on the IMAGE or NORMALIZED.
507
public int textureMode;
510
* Current horizontal coordinate for texture, will always
511
* be between 0 and 1, even if using textureMode(IMAGE).
513
public float textureU;
515
/** Current vertical coordinate for texture, see above. */
516
public float textureV;
518
/** Current image being used as a texture */
519
public PImage textureImage;
521
// ........................................................
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[];
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;
533
//////////////////////////////////////////////////////////////
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.
548
public void setParent(PApplet parent) { // ignore
549
this.parent = parent;
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.
558
public void setPrimary(boolean primary) { // ignore
559
this.primarySurface = primary;
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) {
570
public void setPath(String path) { // ignore
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.
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
586
public void setSize(int w, int h) { // ignore
590
height1 = height - 1;
598
* Allocate memory for this renderer. Generally will need to be implemented
601
protected void allocate() { }
605
* Handle any takedown for this graphics context.
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.
611
public void dispose() { // ignore
616
//////////////////////////////////////////////////////////////
622
* Some renderers have requirements re: when they are ready to draw.
624
public boolean canDraw() { // ignore
630
* Prepares the PGraphics for drawing.
632
* When creating your own PGraphics, you should call this before
635
public void beginDraw() { // ignore
640
* This will finalize rendering so that it can be shown on-screen.
642
* When creating your own PGraphics, you should call this when
643
* you're finished drawing.
645
public void endDraw() { // ignore
649
public void flush() {
650
// no-op, mostly for P3D to write sorted stuff
654
protected void checkSettings() {
655
if (!settingsInited) defaultSettings();
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.
666
* This is currently called by checkSettings(), during beginDraw().
668
protected void defaultSettings() { // ignore
669
// System.out.println("PGraphics.defaultSettings() " + width + " " + height);
676
// other stroke attributes are set in the initializers
677
// inside the class (see above, strokeWeight = 1 et al)
682
// init matrices (must do before lights)
683
//matrixStackDepth = 0;
686
ellipseMode(DIAMETER);
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);
706
settingsInited = true;
707
// defaultSettings() overlaps reapplySettings(), don't do both
708
//reapplySettings = false;
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).
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.
722
protected void reapplySettings() {
723
// System.out.println("attempting reapplySettings()");
724
if (!settingsInited) return; // if this is the initial setup, no need to reapply
726
// System.out.println(" doing reapplySettings");
727
// new Exception().printStackTrace(System.out);
729
colorMode(colorMode, colorModeX, colorModeY, colorModeZ);
731
// PApplet.println(" fill " + PApplet.hex(fillColor));
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);
744
// if (strokeCap != DEFAULT_STROKE_CAP) {
745
strokeCap(strokeCap);
747
// if (strokeJoin != DEFAULT_STROKE_JOIN) {
748
strokeJoin(strokeJoin);
761
// Don't bother setting this, cuz it'll anger P3D.
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);
772
textAlign(textAlign, textAlignY);
773
background(backgroundColor);
775
//reapplySettings = false;
779
//////////////////////////////////////////////////////////////
784
* Enable a hint option.
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.
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.
795
* Current hint options:
797
* <LI><TT>DISABLE_DEPTH_TEST</TT> -
798
* turns off the z-buffer in the P3D or OPENGL renderers.
801
public void hint(int which) {
805
hints[-which] = false;
811
//////////////////////////////////////////////////////////////
816
* Start a new shape of type POLYGON
818
public void beginShape() {
826
* <B>Differences between beginShape() and line() and point() methods.</B>
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
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.
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.
845
public void beginShape(int kind) {
851
* Sets whether the upcoming vertex is part of an edge.
852
* Equivalent to glEdgeFlag(), for people familiar with OpenGL.
854
public void edge(boolean edge) {
860
* Sets the current normal vector. Only applies with 3D rendering
861
* and inside a beginShape/endShape block.
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.
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.
871
* For people familiar with OpenGL, this function is basically
872
* identical to glNormal3f().
874
public void normal(float nx, float ny, float nz) {
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
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;
889
// One normal per begin/end shape
890
normalMode = NORMAL_MODE_SHAPE;
892
} else if (normalMode == NORMAL_MODE_SHAPE) {
893
// a separate normal for each vertex
894
normalMode = NORMAL_MODE_VERTEX;
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)
904
public void textureMode(int mode) {
905
this.textureMode = mode;
910
* Set texture image for current shape.
911
* Needs to be called between @see beginShape and @see endShape
913
* @param image reference to a PImage object
915
public void texture(PImage image) {
916
textureImage = image;
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);
929
public void vertex(float x, float y) {
931
float[] vertex = vertices[vertexCount];
933
curveVertexCount = 0;
938
vertex[EDGE] = edge ? 1 : 0;
941
// vertex[R] = fillR;
942
// vertex[G] = fillG;
943
// vertex[B] = fillB;
944
// vertex[A] = fillA;
946
if (fill || textureImage != null) {
947
if (textureImage == null) {
968
vertex[SR] = strokeR;
969
vertex[SG] = strokeG;
970
vertex[SB] = strokeB;
971
vertex[SA] = strokeA;
972
vertex[SW] = strokeWeight;
975
if (textureImage != null) {
976
vertex[U] = textureU;
977
vertex[V] = textureV;
984
public void vertex(float x, float y, float z) {
986
float[] vertex = vertices[vertexCount];
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
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;
1014
vertex[EDGE] = edge ? 1 : 0;
1016
if (fill || textureImage != null) {
1017
if (textureImage == null) {
1036
vertex[AR] = ambientR;
1037
vertex[AG] = ambientG;
1038
vertex[AB] = ambientB;
1040
vertex[SPR] = specularR;
1041
vertex[SPG] = specularG;
1042
vertex[SPB] = specularB;
1043
//vertex[SPA] = specularA;
1045
vertex[SHINE] = shininess;
1047
vertex[ER] = emissiveR;
1048
vertex[EG] = emissiveG;
1049
vertex[EB] = emissiveB;
1053
vertex[SR] = strokeR;
1054
vertex[SG] = strokeG;
1055
vertex[SB] = strokeB;
1056
vertex[SA] = strokeA;
1057
vertex[SW] = strokeWeight;
1060
if (textureImage != null) {
1061
vertex[U] = textureU;
1062
vertex[V] = textureV;
1065
vertex[NX] = normalX;
1066
vertex[NY] = normalY;
1067
vertex[NZ] = normalZ;
1069
vertex[BEEN_LIT] = 0;
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
1080
public void vertex(float[] v) {
1082
curveVertexCount = 0;
1083
float[] vertex = vertices[vertexCount];
1084
System.arraycopy(v, 0, vertex, 0, VERTEX_FIELD_COUNT);
1089
public void vertex(float x, float y, float u, float v) {
1090
vertexTexture(u, v);
1095
public void vertex(float x, float y, float z, float u, float v) {
1096
vertexTexture(u, v);
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)
1106
// protected void vertexStyle() {
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().
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.
1122
* Used by both PGraphics2D (for images) and PGraphics3D.
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()");
1129
if (textureMode == IMAGE) {
1130
u /= (float) textureImage.width;
1131
v /= (float) textureImage.height;
1137
if (textureU < 0) textureU = 0;
1138
else if (textureU > 1) textureU = 1;
1140
if (textureV < 0) textureV = 0;
1141
else if (textureV > 1) textureV = 1;
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.");
1152
public void endShape() {
1157
public void endShape(int mode) {
1162
//////////////////////////////////////////////////////////////
1164
// CURVE/BEZIER VERTEX HANDLING
1167
protected void bezierVertexCheck() {
1168
if (shape == 0 || shape != POLYGON) {
1169
throw new RuntimeException("beginShape() or beginShape(POLYGON) " +
1170
"must be used before bezierVertex()");
1172
if (vertexCount == 0) {
1173
throw new RuntimeException("vertex() must be used at least once" +
1174
"before bezierVertex()");
1179
public void bezierVertex(float x2, float y2,
1181
float x4, float y4) {
1183
bezierVertexCheck();
1184
PMatrix3D draw = bezierDrawMatrix;
1186
float[] prev = vertices[vertexCount-1];
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;
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;
1198
for (int j = 0; j < bezierDetail; j++) {
1199
x1 += xplot1; xplot1 += xplot2; xplot2 += xplot3;
1200
y1 += yplot1; yplot1 += yplot2; yplot2 += yplot3;
1206
public void bezierVertex(float x2, float y2, float z2,
1207
float x3, float y3, float z3,
1208
float x4, float y4, float z4) {
1210
bezierVertexCheck();
1211
PMatrix3D draw = bezierDrawMatrix;
1213
float[] prev = vertices[vertexCount-1];
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;
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;
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;
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;
1240
* Perform initialization specific to curveVertex(), and handle standard
1241
* error modes. Can be overridden by subclasses that need the flexibility.
1243
protected void curveVertexCheck() {
1244
if (shape != POLYGON) {
1245
throw new RuntimeException("You must use beginShape() or " +
1246
"beginShape(POLYGON) before curveVertex()");
1248
// to improve code init time, allocate on first use.
1249
if (curveVertices == null) {
1250
curveVertices = new float[128][3];
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;
1263
public void curveVertex(float x, float y) {
1265
float[] vertex = curveVertices[curveVertexCount];
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]);
1284
public void curveVertex(float x, float y, float z) {
1286
float[] vertex = curveVertices[curveVertexCount];
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]);
1311
* Handle emitting a specific segment of Catmull-Rom curve. This can be
1312
* overridden by subclasses that need more efficient rendering options.
1314
protected void curveVertexSegment(float x1, float y1,
1317
float x4, float y4) {
1321
PMatrix3D draw = curveDrawMatrix;
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;
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;
1331
// vertex() will reset splineVertexCount, so save it
1332
int savedCount = curveVertexCount;
1335
for (int j = 0; j < curveDetail; j++) {
1336
x0 += xplot1; xplot1 += xplot2; xplot2 += xplot3;
1337
y0 += yplot1; yplot1 += yplot2; yplot2 += yplot3;
1340
curveVertexCount = savedCount;
1345
* Handle emitting a specific segment of Catmull-Rom curve. This can be
1346
* overridden by subclasses that need more efficient rendering options.
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) {
1356
PMatrix3D draw = curveDrawMatrix;
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;
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;
1366
// vertex() will reset splineVertexCount, so save it
1367
int savedCount = curveVertexCount;
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;
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;
1380
curveVertexCount = savedCount;
1385
//////////////////////////////////////////////////////////////
1387
// SIMPLE SHAPES WITH ANALOGUES IN beginShape()
1390
public void point(float x, float y) {
1397
public void point(float x, float y, float z) {
1404
public void line(float x1, float y1, float x2, float y2) {
1412
public void line(float x1, float y1, float z1,
1413
float x2, float y2, float z2) {
1421
public void triangle(float x1, float y1, float x2, float y2,
1422
float x3, float y3) {
1423
beginShape(TRIANGLES);
1431
public void quad(float x1, float y1, float x2, float y2,
1432
float x3, float y3, float x4, float y4) {
1443
//////////////////////////////////////////////////////////////
1448
public void rectMode(int mode) {
1453
public void rect(float a, float b, float c, float d) {
1454
float hradius, vradius;
1479
float temp = a; a = c; c = temp;
1483
float temp = b; b = d; d = temp;
1486
rectImpl(a, b, c, d);
1490
protected void rectImpl(float x1, float y1, float x2, float y2) {
1491
quad(x1, y1, x2, y1, x2, y2, x1, y2);
1496
//////////////////////////////////////////////////////////////
1501
public void ellipseMode(int mode) {
1506
public void ellipse(float a, float b, float c, float d) {
1512
if (ellipseMode == CORNERS) {
1516
} else if (ellipseMode == RADIUS) {
1522
} else if (ellipseMode == DIAMETER) {
1527
if (w < 0) { // undo negative width
1532
if (h < 0) { // undo negative height
1537
ellipseImpl(x, y, w, h);
1541
protected void ellipseImpl(float x, float y, float w, float h) {
1546
* Identical parameters and placement to ellipse,
1547
* but draws only an arc of that ellipse.
1549
* start and stop are always radians because angleMode() was goofy.
1550
* ellipseMode() sets the placement.
1552
* also tries to be smart about start < stop.
1554
public void arc(float a, float b, float c, float d,
1555
float start, float stop) {
1561
if (ellipseMode == CORNERS) {
1565
} else if (ellipseMode == RADIUS) {
1571
} else if (ellipseMode == CENTER) {
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
1581
// make sure that we're starting at a useful point
1587
if (stop - start > TWO_PI) {
1592
arcImpl(x, y, w, h, start, stop);
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.
1602
protected void arcImpl(float x, float y, float w, float h,
1603
float start, float stop) {
1608
//////////////////////////////////////////////////////////////
1613
public void box(float size) {
1614
box(size, size, size);
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;
1674
//////////////////////////////////////////////////////////////
1679
public void sphereDetail(int res) {
1680
sphereDetail(res, res);
1685
* Set the detail level for approximating a sphere. The ures and vres params
1686
* control the horizontal and vertical resolution.
1688
* Code for sphereDetail() submitted by toxi [031031].
1689
* Code for enhanced u/v version from davbol [080801].
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;
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];
1704
// computing vertexlist
1705
// vertexlist starts at south pole
1706
int vertCount = ures * (vres-1) + 2;
1709
// re-init arrays to store vertices
1710
sphereX = new float[vertCount];
1711
sphereY = new float[vertCount];
1712
sphereZ = new float[vertCount];
1714
float angle_step = (SINCOS_LENGTH*0.5f)/vres;
1715
float angle = angle_step;
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;
1726
angle += angle_step;
1728
sphereDetailU = ures;
1729
sphereDetailV = vres;
1734
* Draw a sphere with radius r centered at coordinate 0, 0, 0.
1736
* Implementation notes:
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
1742
* sphere is a series of concentric circles who radii vary
1743
* along the shape, based on, er.. cos or something
1745
* [toxi 031031] new sphere code. removed all multiplies with
1746
* radius, as scale() will take care of that anyway
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
1752
* [davbol 080801] now using separate sphereDetailU/V
1755
public void sphere(float r) {
1756
if ((sphereDetailU < 3) || (sphereDetailV < 2)) {
1764
// 1st ring from south pole
1765
beginShape(TRIANGLE_STRIP);
1766
for (int i = 0; i < sphereDetailU; i++) {
1769
normal(sphereX[i], sphereY[i], sphereZ[i]);
1770
vertex(sphereX[i], sphereY[i], sphereZ[i]);
1774
normal(sphereX[0], sphereY[0], sphereZ[0]);
1775
vertex(sphereX[0], sphereY[0], sphereZ[0]);
1782
for (int i = 2; i < sphereDetailV; i++) {
1784
voff += sphereDetailU;
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++]);
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]);
1803
// add the northern cap
1804
beginShape(TRIANGLE_STRIP);
1805
for (int i = 0; i < sphereDetailU; i++) {
1807
normal(sphereX[v2], sphereY[v2], sphereZ[v2]);
1808
vertex(sphereX[v2], sphereY[v2], sphereZ[v2]);
1812
normal(sphereX[voff], sphereY[voff], sphereZ[voff]);
1813
vertex(sphereX[voff], sphereY[voff], sphereZ[voff]);
1824
//////////////////////////////////////////////////////////////
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.
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);
1841
* bezier(85, 20, 10, 10, 90, 90, 15, 80);
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
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);
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;
1863
* Provide the tangent at the given point on the bezier curve.
1864
* Fix from davbol for 0136.
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) +
1873
protected void bezierInitCheck() {
1874
if (!bezierInited) {
1880
protected void bezierInit() {
1881
// overkill to be broken out, but better parity with the curve stuff below
1882
bezierDetail(bezierDetail);
1883
bezierInited = true;
1887
public void bezierDetail(int detail) {
1888
bezierDetail = detail;
1890
if (bezierDrawMatrix == null) {
1891
bezierDrawMatrix = new PMatrix3D();
1894
// setup matrix for forward differencing to speed up drawing
1895
splineForward(detail, bezierDrawMatrix);
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);
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.
1910
* Identical to typing:
1911
* <PRE>beginShape();
1913
* bezierVertex(x2, y2, x3, y3, x4, y4);
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)
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>
1928
public void bezier(float x1, float y1,
1931
float x4, float y4) {
1934
bezierVertex(x2, y2, x3, y3, x4, y4);
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) {
1945
bezierVertex(x2, y2, z2,
1953
//////////////////////////////////////////////////////////////
1955
// CATMULL-ROM CURVE
1959
* Get a location along a catmull-rom curve segment.
1961
* @param t Value between zero and one for how far along the segment
1963
public float curvePoint(float a, float b, float c, float d, float t) {
1968
PMatrix3D cb = curveBasisMatrix;
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));
1979
* Calculate the tangent at a t value (0..1) on a Catmull-Rom curve.
1980
* Code thanks to Dave Bollinger (Bug #715)
1982
public float curveTangent(float a, float b, float c, float d, float t) {
1985
float tt3 = t * t * 3;
1987
PMatrix3D cb = curveBasisMatrix;
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) );
1997
public void curveDetail(int detail) {
1998
curveDetail = detail;
2003
public void curveTightness(float tightness) {
2004
curveTightness = tightness;
2009
protected void curveInitCheck() {
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.
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)
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();
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,
2041
//setup_spline_forward(segments, curveForwardMatrix);
2042
splineForward(curveDetail, curveDrawMatrix);
2044
if (bezierBasisInverse == null) {
2045
bezierBasisInverse = bezierBasisMatrix.get();
2046
bezierBasisInverse.invert();
2047
curveToBezierMatrix = new PMatrix3D();
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);
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);
2063
* Draws a segment of Catmull-Rom curve.
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().
2069
* Identical to typing out:<PRE>
2071
* curveVertex(x1, y1);
2072
* curveVertex(x2, y2);
2073
* curveVertex(x3, y3);
2074
* curveVertex(x4, y4);
2078
public void curve(float x1, float y1,
2081
float x4, float y4) {
2083
curveVertex(x1, y1);
2084
curveVertex(x2, y2);
2085
curveVertex(x3, y3);
2086
curveVertex(x4, y4);
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) {
2096
curveVertex(x1, y1, z1);
2097
curveVertex(x2, y2, z2);
2098
curveVertex(x3, y3, z3);
2099
curveVertex(x4, y4, z4);
2105
//////////////////////////////////////////////////////////////
2107
// SPLINE UTILITY FUNCTIONS (used by both Bezier and Catmull-Rom)
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
2119
protected void splineForward(int segments, PMatrix3D matrix) {
2120
float f = 1.0f / segments;
2124
matrix.set(0, 0, 0, 1,
2132
//////////////////////////////////////////////////////////////
2138
* If true in PImage, use bilinear interpolation for copy()
2139
* operations. When inherited by PGraphics, also controls shapes.
2141
public void smooth() {
2147
* Disable smoothing. See smooth().
2149
public void noSmooth() {
2155
//////////////////////////////////////////////////////////////
2161
* The mode can only be set to CORNERS, CORNER, and CENTER.
2163
* Support for CENTER was added in release 0146.
2165
public void imageMode(int mode) {
2166
if ((mode == CORNER) || (mode == CORNERS) || (mode == CENTER)) {
2170
"imageMode() only works with CORNER, CORNERS, or CENTER";
2171
throw new RuntimeException(msg);
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;
2181
if (imageMode == CORNER || imageMode == CORNERS) {
2183
x, y, x+image.width, y+image.height,
2184
0, 0, image.width, image.height);
2186
} else if (imageMode == CENTER) {
2187
float x1 = x - image.width/2;
2188
float y1 = y - image.height/2;
2190
x1, y1, x1+image.width, y1+image.height,
2191
0, 0, image.width, image.height);
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);
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().
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;
2213
if (imageMode == CORNER) {
2214
if (c < 0) { // reset a negative width
2217
if (d < 0) { // reset a negative height
2225
} else if (imageMode == CORNERS) {
2226
if (c < a) { // reverse because x2 < x1
2227
float temp = a; a = c; c = temp;
2229
if (d < b) { // reverse because y2 < y1
2230
float temp = b; b = d; d = temp;
2237
} else if (imageMode == CENTER) {
2238
// c and d are width/height
2245
x1, y1, x1 + c, y1 + d,
2252
* Expects x1, y1, x2, y2 coordinates where (x2 >= x1) and (y2 >= y1).
2253
* If tint() has been called, the image will be colored.
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..)
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;
2267
textureMode = IMAGE;
2269
// float savedFillR = fillR;
2270
// float savedFillG = fillG;
2271
// float savedFillB = fillB;
2272
// float savedFillA = fillA;
2289
vertex(x1, y1, u1, v1);
2290
vertex(x1, y2, u1, v2);
2291
vertex(x2, y2, u2, v2);
2292
vertex(x2, y1, u2, v1);
2295
stroke = savedStroke;
2296
// fill = savedFill;
2297
textureMode = savedTextureMode;
2299
// fillR = savedFillR;
2300
// fillG = savedFillG;
2301
// fillB = savedFillB;
2302
// fillA = savedFillA;
2307
//////////////////////////////////////////////////////////////
2313
* Set the orientation for the shape() command (like imageMode() or rectMode()).
2314
* @param mode Either CORNER, CORNERS, or CENTER.
2316
public void shapeMode(int mode) {
2317
this.shapeMode = mode;
2321
public void shape(PShape shape) {
2322
if (shape.isVisible()) { // don't do expensive matrix ops if invisible
2323
if (shapeMode == CENTER) {
2325
translate(-shape.getWidth()/2, -shape.getHeight()/2);
2328
shape.draw(this); // needs to handle recorder too
2330
if (shapeMode == CENTER) {
2338
* Convenience method to draw at a particular location.
2340
public void shape(PShape shape, float x, float y) {
2341
if (shape.isVisible()) { // don't do expensive matrix ops if invisible
2344
if (shapeMode == CENTER) {
2345
translate(x - shape.getWidth()/2, y - shape.getHeight()/2);
2347
} else if ((shapeMode == CORNER) || (shapeMode == CORNERS)) {
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
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());
2366
} else if (shapeMode == CORNER) {
2368
scale(c / shape.getWidth(), d / shape.getHeight());
2370
} else if (shapeMode == CORNERS) {
2371
// c and d are x2/y2, make them into width/height
2374
// then same as above
2376
scale(c / shape.getWidth(), d / shape.getHeight());
2386
//////////////////////////////////////////////////////////////
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.
2395
public void textAlign(int align) {
2396
textAlign(align, BASELINE);
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).
2405
public void textAlign(int alignX, int alignY) {
2407
textAlignY = alignY;
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.
2416
public float textAscent() {
2417
if (textFont == null) {
2418
showTextFontException("textAscent");
2420
return textFont.ascent() * ((textMode == SCREEN) ? textFont.size : textSize);
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.
2429
public float textDescent() {
2430
if (textFont == null) {
2431
showTextFontException("textDescent");
2433
return textFont.descent() * ((textMode == SCREEN) ? textFont.size : textSize);
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.
2442
public void textFont(PFont which) {
2443
if (which != null) {
2445
if (hints[ENABLE_NATIVE_FONTS]) {
2446
//if (which.font == null) {
2451
textFontNative = which.font;
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);
2470
// float w = font.getStringBounds(text, g2.getFontRenderContext()).getWidth();
2473
textSize(which.size);
2476
throw new RuntimeException(ERROR_TEXTFONT_NULL_PFONT);
2482
* Useful function to set the font and size at the same time.
2484
public void textFont(PFont which, float size) {
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().
2495
public void textLeading(float leading) {
2496
textLeading = leading;
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.
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().");
2513
// if ((mode != SCREEN) && (mode != MODEL)) {
2514
// showError("Only textMode(SCREEN) and textMode(MODEL) " +
2515
// "are available with this renderer.");
2518
if (textModeCheck(mode)) {
2521
String modeStr = String.valueOf(mode);
2523
case SCREEN: modeStr = "SCREEN"; break;
2524
case MODEL: modeStr = "MODEL"; break;
2525
case SHAPE: modeStr = "SHAPE"; break;
2527
showWarning("textMode(" + modeStr + ") is not supported by this renderer.");
2530
// reset the font to its natural size
2531
// (helps with width calculations and all that)
2532
//if (textMode == SCREEN) {
2533
//textSize(textFont.size);
2537
//throw new RuntimeException("use textFont() before textMode()");
2542
protected boolean textModeCheck(int mode) {
2548
* Sets the text size, also resets the value for the leading.
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)");
2557
textLeading = (textAscent() + textDescent()) * 1.275f;
2560
showTextFontException("textSize");
2565
// ........................................................
2568
public float textWidth(char c) {
2569
textWidthBuffer[0] = c;
2570
return textWidthImpl(textWidthBuffer, 0, 1);
2575
* Return the width of a line of text. If the text has multiple
2576
* lines, this returns the length of the longest line.
2578
public float textWidth(String str) {
2579
if (textFont == null) {
2580
showTextFontException("textWidth");
2583
int length = str.length();
2584
if (length > textWidthBuffer.length) {
2585
textWidthBuffer = new char[length + 10];
2587
str.getChars(0, length, textWidthBuffer, 0);
2593
while (index < length) {
2594
if (textWidthBuffer[index] == '\n') {
2595
wide = Math.max(wide, textWidthImpl(textWidthBuffer, start, index));
2600
if (start < length) {
2601
wide = Math.max(wide, textWidthImpl(textWidthBuffer, start, index));
2608
* TODO not sure if this stays...
2610
public float textWidth(char[] chars, int start, int length) {
2611
return textWidthImpl(chars, start, start + length);
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.
2621
protected float textWidthImpl(char buffer[], int start, int stop) {
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;
2631
// ........................................................
2635
* Write text where we just left off.
2637
public void text(char c) {
2638
text(c, textX, textY, textZ);
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.
2647
public void text(char c, float x, float y) {
2648
if (textFont == null) {
2649
showTextFontException("text");
2652
if (textMode == SCREEN) loadPixels();
2654
if (textAlignY == CENTER) {
2655
y += textAscent() / 2;
2656
} else if (textAlignY == TOP) {
2658
} else if (textAlignY == BOTTOM) {
2660
//} else if (textAlignY == BASELINE) {
2665
textLineAlignImpl(textBuffer, 0, 1, x, y);
2667
if (textMode == SCREEN) updatePixels();
2672
* Draw a single character on screen (with a z coordinate)
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);
2680
if (z != 0) translate(0, 0, z); // slowness, badness
2685
if (z != 0) translate(0, 0, -z);
2690
* Write text where we just left off.
2692
public void text(String str) {
2693
text(str, textX, textY, textZ);
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
2703
public void text(String str, float x, float y) {
2704
if (textFont == null) {
2705
showTextFontException("text");
2708
if (textMode == SCREEN) loadPixels();
2710
int length = str.length();
2711
if (length > textBuffer.length) {
2712
textBuffer = new char[length + 10];
2714
str.getChars(0, length, textBuffer, 0);
2715
text(textBuffer, 0, length, x, y);
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.
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;
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
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) {
2751
while (index < stop) { //length) {
2752
if (chars[index] == '\n') {
2753
textLineAlignImpl(chars, start, index, x, y);
2759
if (start < stop) { //length) {
2760
textLineAlignImpl(chars, start, index, x, y);
2762
if (textMode == SCREEN) updatePixels();
2767
* Same as above but with a z coordinate.
2769
public void text(String str, float x, float y, float z) {
2770
if (z != 0) translate(0, 0, z); // slow!
2775
if (z != 0) translate(0, 0, -z); // inaccurate!
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!
2783
text(chars, start, stop, x, y);
2786
if (z != 0) translate(0, 0, -z); // inaccurate!
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).
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.
2799
* Newlines that are \n (Unix newline or linefeed char, ascii 10)
2800
* are honored, and \r (carriage return, Windows and Mac OS) are
2803
public void text(String str, float x1, float y1, float x2, float y2) {
2804
if (textFont == null) {
2805
showTextFontException("text");
2808
if (textMode == SCREEN) loadPixels();
2810
float hradius, vradius;
2824
hradius = x2 / 2.0f;
2825
vradius = y2 / 2.0f;
2832
float temp = x1; x1 = x2; x2 = temp;
2835
float temp = y1; y1 = y2; y2 = temp;
2838
// float currentY = y1;
2839
float boxWidth = x2 - x1;
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;
2846
float spaceWidth = textWidth(' ');
2848
if (textBreakStart == null) {
2849
textBreakStart = new int[20];
2850
textBreakStop = new int[20];
2854
int length = str.length();
2855
if (length + 1 > textBuffer.length) {
2856
textBuffer = new char[length + 1];
2858
str.getChars(0, length, textBuffer, 0);
2859
// add a fake newline to simplify calculations
2860
textBuffer[length++] = '\n';
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);
2868
textSentence(textBuffer, sentenceStart, i, boxWidth, spaceWidth);
2870
// if (Float.isNaN(currentY)) break; // word too big (or error)
2871
// if (currentY > y2) break; // past the box
2872
sentenceStart = i + 1;
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;
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);
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);
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);
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);
2917
if (textMode == SCREEN) updatePixels();
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
2925
protected boolean textSentence(char[] buffer, int start, int stop,
2926
float boxWidth, float spaceWidth) {
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;
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);
2939
if (runningX + wordWidth > boxWidth) {
2940
if (runningX != 0) {
2941
// Next word is too big, output the current line and advance
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] == ' ')) {
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.
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;
2960
wordWidth = textWidthImpl(buffer, wordStart, index);
2961
} while (wordWidth > boxWidth);
2963
//textLineImpl(buffer, lineStart, index, x, y);
2964
textSentenceBreak(lineStart, index);
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;
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
2982
} else { // not a space or the last character
2983
index++; // this is just another letter
2991
protected void textSentenceBreak(int start, int stop) {
2992
if (textBreakCount == textBreakStart.length) {
2993
textBreakStart = PApplet.expand(textBreakStart);
2994
textBreakStop = PApplet.expand(textBreakStop);
2996
textBreakStart[textBreakCount] = start;
2997
textBreakStop[textBreakCount] = stop;
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
3005
text(s, x1, y1, x2, y2);
3008
if (z != 0) translate(0, 0, -z); // TEMPORARY HACK! SLOW!
3012
public void text(int num, float x, float y) {
3013
text(String.valueOf(num), x, y);
3017
public void text(int num, float x, float y, float z) {
3018
text(String.valueOf(num), x, y, z);
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.
3029
public void text(float num, float x, float y) {
3030
text(PApplet.nfs(num, 0, 3), x, y);
3034
public void text(float num, float x, float y, float z) {
3035
text(PApplet.nfs(num, 0, 3), x, y, z);
3040
//////////////////////////////////////////////////////////////
3044
// These are most likely to be overridden by subclasses, since the other
3045
// (public) functions handle generic features like setting alignment.
3049
* Handles placement of a text line, then calls textLineImpl
3050
* to actually render at the specific point.
3052
protected void textLineAlignImpl(char buffer[], int start, int stop,
3054
if (textAlign == CENTER) {
3055
x -= textWidthImpl(buffer, start, stop) / 2f;
3057
} else if (textAlign == RIGHT) {
3058
x -= textWidthImpl(buffer, start, stop);
3061
textLineImpl(buffer, start, stop, x, y);
3066
* Implementation of actual drawing for a line of text.
3068
protected void textLineImpl(char buffer[], int start, int stop,
3070
for (int index = start; index < stop; index++) {
3071
textCharImpl(buffer[index], x, y);
3073
// this doesn't account for kerning
3074
x += textWidth(buffer[index]);
3078
textZ = 0; // this will get set by the caller if non-zero
3082
protected void textCharImpl(char ch, float x, float y) { //, float z) {
3083
int index = textFont.index(ch);
3084
if (index == -1) return;
3086
PImage glyph = textFont.images[index];
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;
3094
float x1 = x + lextent * textSize;
3095
float y1 = y - textent * textSize;
3096
float x2 = x1 + bwidth * textSize;
3097
float y2 = y1 + high * textSize;
3099
textCharModelImpl(glyph,
3101
//x1, y1, z, x2, y2, z,
3102
textFont.width[index], textFont.height[index]);
3104
} else if (textMode == SCREEN) {
3105
int xx = (int) x + textFont.leftExtent[index];;
3106
int yy = (int) y - textFont.topExtent[index];
3108
int w0 = textFont.width[index];
3109
int h0 = textFont.height[index];
3111
textCharScreenImpl(glyph, xx, yy, w0, h0);
3116
protected void textCharModelImpl(PImage glyph,
3117
float x1, float y1, //float z1,
3118
float x2, float y2, //float z2,
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;
3129
tintColor = fillColor;
3134
tintAlpha = fillAlpha;
3136
imageImpl(glyph, x1, y1, x2, y2, 0, 0, u2, v2);
3139
tintColor = savedTintColor;
3144
tintAlpha = savedTintAlpha;
3148
protected void textCharScreenImpl(PImage glyph,
3154
if ((xx >= width) || (yy >= height) ||
3155
(xx + w0 < 0) || (yy + h0 < 0)) return;
3167
if (xx + w0 > width) {
3168
w0 -= ((xx + w0) - width);
3170
if (yy + h0 > height) {
3171
h0 -= ((yy + h0) - height);
3179
int pixels1[] = glyph.pixels; //images[glyph].pixels;
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;
3186
//int p1 = pixels1[row * glyph.width + col];
3187
int p2 = pixels[(yy + row-y0)*width + (xx+col-x0)];
3189
pixels[(yy + row-y0)*width + xx+col-x0] =
3191
(((a1 * fr + a2 * ((p2 >> 16) & 0xff)) & 0xff00) << 8) |
3192
(( a1 * fg + a2 * ((p2 >> 8) & 0xff)) & 0xff00) |
3193
(( a1 * fb + a2 * ( p2 & 0xff)) >> 8));
3200
//////////////////////////////////////////////////////////////
3206
* Push a copy of the current transformation matrix onto the stack.
3208
public void pushMatrix() {
3209
showMethodWarning("pushMatrix");
3214
* Replace the current transformation matrix with the top of the stack.
3216
public void popMatrix() {
3217
showMethodWarning("popMatrix");
3222
//////////////////////////////////////////////////////////////
3224
// MATRIX TRANSFORMATIONS
3228
* Translate in X and Y.
3230
public void translate(float tx, float ty) {
3231
showMissingWarning("translate");
3236
* Translate in X, Y, and Z.
3238
public void translate(float tx, float ty, float tz) {
3239
showMissingWarning("translate");
3244
* Two dimensional rotation.
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.
3250
* <A HREF="http://www.xkcd.com/c184.html">Additional background</A>.
3252
public void rotate(float angle) {
3253
showMissingWarning("rotate");
3258
* Rotate around the X axis.
3260
public void rotateX(float angle) {
3261
showMethodWarning("rotateX");
3266
* Rotate around the Y axis.
3268
public void rotateY(float angle) {
3269
showMethodWarning("rotateY");
3274
* Rotate around the Z axis.
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.
3281
public void rotateZ(float angle) {
3282
showMethodWarning("rotateZ");
3287
* Rotate about a vector in space. Same as the glRotatef() function.
3289
public void rotate(float angle, float vx, float vy, float vz) {
3290
showMissingWarning("rotate");
3295
* Scale in all dimensions.
3297
public void scale(float s) {
3298
showMissingWarning("scale");
3303
* Scale in X and Y. Equivalent to scale(sx, sy, 1).
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.
3308
public void scale(float sx, float sy) {
3309
showMissingWarning("scale");
3314
* Scale in X, Y, and Z.
3316
public void scale(float x, float y, float z) {
3317
showMissingWarning("scale");
3321
//////////////////////////////////////////////////////////////
3323
// MATRIX FULL MONTY
3327
* Set the current transformation matrix to identity.
3329
public void resetMatrix() {
3330
showMethodWarning("resetMatrix");
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);
3343
public void applyMatrix(PMatrix2D source) {
3344
applyMatrix(source.m00, source.m01, source.m02,
3345
source.m10, source.m11, source.m12);
3350
* Apply a 3x2 affine transformation matrix.
3352
public void applyMatrix(float n00, float n01, float n02,
3353
float n10, float n11, float n12) {
3354
showMissingWarning("applyMatrix");
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);
3367
* Apply a 4x4 transformation matrix.
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");
3378
//////////////////////////////////////////////////////////////
3380
// MATRIX GET/SET/PRINT
3383
public PMatrix getMatrix() {
3384
showMissingWarning("getMatrix");
3390
* Copy the current transformation matrix into the specified target.
3391
* Pass in null to create a new matrix.
3393
public PMatrix2D getMatrix(PMatrix2D target) {
3394
showMissingWarning("getMatrix");
3400
* Copy the current transformation matrix into the specified target.
3401
* Pass in null to create a new matrix.
3403
public PMatrix3D getMatrix(PMatrix3D target) {
3404
showMissingWarning("getMatrix");
3410
* Set the current transformation matrix to the contents of another.
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);
3422
* Set the current transformation to the contents of the specified source.
3424
public void setMatrix(PMatrix2D source) {
3425
showMissingWarning("setMatrix");
3430
* Set the current transformation to the contents of the specified source.
3432
public void setMatrix(PMatrix3D source) {
3433
showMissingWarning("setMatrix");
3438
* Print the current model (or "transformation") matrix.
3440
public void printMatrix() {
3441
showMethodWarning("printMatrix");
3446
//////////////////////////////////////////////////////////////
3451
public void beginCamera() {
3452
showMethodWarning("beginCamera");
3456
public void endCamera() {
3457
showMethodWarning("endCamera");
3461
public void camera() {
3462
showMissingWarning("camera");
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");
3473
public void printCamera() {
3474
showMethodWarning("printCamera");
3479
//////////////////////////////////////////////////////////////
3484
public void ortho() {
3485
showMissingWarning("ortho");
3489
public void ortho(float left, float right,
3490
float bottom, float top,
3491
float near, float far) {
3492
showMissingWarning("ortho");
3496
public void perspective() {
3497
showMissingWarning("perspective");
3501
public void perspective(float fovy, float aspect, float zNear, float zFar) {
3502
showMissingWarning("perspective");
3506
public void frustum(float left, float right,
3507
float bottom, float top,
3508
float near, float far) {
3509
showMethodWarning("frustum");
3513
public void printProjection() {
3514
showMethodWarning("printCamera");
3519
//////////////////////////////////////////////////////////////
3521
// SCREEN TRANSFORMS
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.
3529
public float screenX(float x, float y) {
3530
showMissingWarning("screenX");
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.
3540
public float screenY(float x, float y) {
3541
showMissingWarning("screenY");
3547
* Maps a three dimensional point to its placement on-screen.
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.
3553
public float screenX(float x, float y, float z) {
3554
showMissingWarning("screenX");
3560
* Maps a three dimensional point to its placement on-screen.
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.
3566
public float screenY(float x, float y, float z) {
3567
showMissingWarning("screenY");
3573
* Maps a three dimensional point to its placement on-screen.
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[].
3583
public float screenZ(float x, float y, float z) {
3584
showMissingWarning("screenZ");
3590
* Returns the model space x value for an x, y, z coordinate.
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.
3598
public float modelX(float x, float y, float z) {
3599
showMissingWarning("modelX");
3605
* Returns the model space y value for an x, y, z coordinate.
3607
public float modelY(float x, float y, float z) {
3608
showMissingWarning("modelY");
3614
* Returns the model space z value for an x, y, z coordinate.
3616
public float modelZ(float x, float y, float z) {
3617
showMissingWarning("modelZ");
3623
//////////////////////////////////////////////////////////////
3628
public void pushStyle() {
3629
if (styleStackDepth == styleStack.length) {
3630
styleStack = (PStyle[]) PApplet.expand(styleStack);
3632
if (styleStack[styleStackDepth] == null) {
3633
styleStack[styleStackDepth] = new PStyle();
3635
PStyle s = styleStack[styleStackDepth++];
3640
public void popStyle() {
3641
if (styleStackDepth == 0) {
3642
throw new RuntimeException("Too many popStyle() without enough pushStyle()");
3645
style(styleStack[styleStackDepth]);
3649
public void style(PStyle s) {
3656
imageMode(s.imageMode);
3657
rectMode(s.rectMode);
3658
ellipseMode(s.ellipseMode);
3659
shapeMode(s.shapeMode);
3672
stroke(s.strokeColor);
3676
strokeWeight(s.strokeWeight);
3677
strokeCap(s.strokeCap);
3678
strokeJoin(s.strokeJoin);
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.
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);
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;
3701
// material(s.ambientR, s.ambientG, s.ambientB,
3702
// s.emissiveR, s.emissiveG, s.emissiveB,
3703
// s.specularR, s.specularG, s.specularB,
3706
// Set this after the material properties.
3707
colorMode(s.colorMode,
3708
s.colorModeX, s.colorModeY, s.colorModeZ, s.colorModeA);
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);
3718
// These don't require a font to be set.
3719
textAlign(s.textAlign, s.textAlignY);
3720
textMode(s.textMode);
3724
public PStyle getStyle() { // ignore
3725
return getStyle(null);
3729
public PStyle getStyle(PStyle s) { // ignore
3734
s.imageMode = imageMode;
3735
s.rectMode = rectMode;
3736
s.ellipseMode = ellipseMode;
3737
s.shapeMode = shapeMode;
3739
s.colorMode = colorMode;
3740
s.colorModeX = colorModeX;
3741
s.colorModeY = colorModeY;
3742
s.colorModeZ = colorModeZ;
3743
s.colorModeA = colorModeA;
3746
s.tintColor = tintColor;
3748
s.fillColor = fillColor;
3750
s.strokeColor = strokeColor;
3751
s.strokeWeight = strokeWeight;
3752
s.strokeCap = strokeCap;
3753
s.strokeJoin = strokeJoin;
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;
3766
s.textFont = textFont;
3767
s.textAlign = textAlign;
3768
s.textAlignY = textAlignY;
3769
s.textMode = textMode;
3770
s.textSize = textSize;
3771
s.textLeading = textLeading;
3778
//////////////////////////////////////////////////////////////
3780
// STROKE CAP/JOIN/WEIGHT
3783
public void strokeWeight(float weight) {
3784
strokeWeight = weight;
3788
public void strokeJoin(int join) {
3793
public void strokeCap(int cap) {
3799
//////////////////////////////////////////////////////////////
3804
public void noStroke() {
3810
* Set the tint to either a grayscale or ARGB value.
3811
* See notes attached to the fill() function.
3813
public void stroke(int rgb) {
3814
// if (((rgb & 0xff000000) == 0) && (rgb <= colorModeX)) { // see above
3815
// stroke((float) rgb);
3818
// colorCalcARGB(rgb, colorModeA);
3819
// strokeFromCalc();
3826
public void stroke(int rgb, float alpha) {
3827
// if (((rgb & 0xff000000) == 0) && (rgb <= colorModeX)) {
3828
// stroke((float) rgb, alpha);
3831
// colorCalcARGB(rgb, alpha);
3832
// strokeFromCalc();
3834
colorCalc(rgb, alpha);
3839
public void stroke(float gray) {
3845
public void stroke(float gray, float alpha) {
3846
colorCalc(gray, alpha);
3851
public void stroke(float x, float y, float z) {
3857
public void stroke(float x, float y, float z, float a) {
3858
colorCalc(x, y, z, a);
3863
protected void strokeFromCalc() {
3873
strokeColor = calcColor;
3874
strokeAlpha = calcAlpha;
3879
//////////////////////////////////////////////////////////////
3884
public void noTint() {
3890
* Set the tint to either a grayscale or ARGB value.
3892
public void tint(int rgb) {
3893
// if (((rgb & 0xff000000) == 0) && (rgb <= colorModeX)) {
3894
// tint((float) rgb);
3897
// colorCalcARGB(rgb, colorModeA);
3904
public void tint(int rgb, float alpha) {
3905
// if (((rgb & 0xff000000) == 0) && (rgb <= colorModeX)) {
3906
// tint((float) rgb, alpha);
3909
// colorCalcARGB(rgb, alpha);
3912
colorCalc(rgb, alpha);
3916
public void tint(float gray) {
3922
public void tint(float gray, float alpha) {
3923
colorCalc(gray, alpha);
3928
public void tint(float x, float y, float z) {
3934
public void tint(float x, float y, float z, float a) {
3935
colorCalc(x, y, z, a);
3940
protected void tintFromCalc() {
3950
tintColor = calcColor;
3951
tintAlpha = calcAlpha;
3956
//////////////////////////////////////////////////////////////
3961
public void noFill() {
3967
* Set the fill to either a grayscale value or an ARGB int.
3969
public void fill(int rgb) {
3970
// if (((rgb & 0xff000000) == 0) && (rgb <= colorModeX)) { // see above
3971
// fill((float) rgb);
3974
// colorCalcARGB(rgb, colorModeA);
3982
public void fill(int rgb, float alpha) {
3983
// if (((rgb & 0xff000000) == 0) && (rgb <= colorModeX)) { // see above
3984
// fill((float) rgb, alpha);
3987
// colorCalcARGB(rgb, alpha);
3990
colorCalc(rgb, alpha);
3995
public void fill(float gray) {
4001
public void fill(float gray, float alpha) {
4002
colorCalc(gray, alpha);
4007
public void fill(float x, float y, float z) {
4013
public void fill(float x, float y, float z, float a) {
4014
colorCalc(x, y, z, a);
4019
protected void fillFromCalc() {
4029
fillColor = calcColor;
4030
fillAlpha = calcAlpha;
4035
//////////////////////////////////////////////////////////////
4037
// MATERIAL PROPERTIES
4040
public void ambient(int rgb) {
4041
// if (((rgb & 0xff000000) == 0) && (rgb <= colorModeX)) {
4042
// ambient((float) rgb);
4045
// colorCalcARGB(rgb, colorModeA);
4046
// ambientFromCalc();
4053
public void ambient(float gray) {
4059
public void ambient(float x, float y, float z) {
4065
protected void ambientFromCalc() {
4072
public void specular(int rgb) {
4073
// if (((rgb & 0xff000000) == 0) && (rgb <= colorModeX)) {
4074
// specular((float) rgb);
4077
// colorCalcARGB(rgb, colorModeA);
4078
// specularFromCalc();
4085
public void specular(float gray) {
4091
public void specular(float x, float y, float z) {
4097
protected void specularFromCalc() {
4104
public void shininess(float shine) {
4109
public void emissive(int rgb) {
4110
// if (((rgb & 0xff000000) == 0) && (rgb <= colorModeX)) {
4111
// emissive((float) rgb);
4114
// colorCalcARGB(rgb, colorModeA);
4115
// emissiveFromCalc();
4122
public void emissive(float gray) {
4128
public void emissive(float x, float y, float z) {
4134
protected void emissiveFromCalc() {
4142
//////////////////////////////////////////////////////////////
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.
4151
public void lights() {
4152
showMethodWarning("lights");
4155
public void noLights() {
4156
showMethodWarning("noLights");
4159
public void ambientLight(float red, float green, float blue) {
4160
showMethodWarning("ambientLight");
4163
public void ambientLight(float red, float green, float blue,
4164
float x, float y, float z) {
4165
showMethodWarning("ambientLight");
4168
public void directionalLight(float red, float green, float blue,
4169
float nx, float ny, float nz) {
4170
showMethodWarning("directionalLight");
4173
public void pointLight(float red, float green, float blue,
4174
float x, float y, float z) {
4175
showMethodWarning("pointLight");
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");
4185
public void lightFalloff(float constant, float linear, float quadratic) {
4186
showMethodWarning("lightFalloff");
4189
public void lightSpecular(float x, float y, float z) {
4190
showMethodWarning("lightSpecular");
4195
//////////////////////////////////////////////////////////////
4200
* Set the background to a gray or ARGB color.
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.
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.
4210
public void background(int rgb) {
4211
// if (((rgb & 0xff000000) == 0) && (rgb <= colorModeX)) {
4212
// background((float) rgb);
4215
// if (format == RGB) {
4216
// rgb |= 0xff000000; // ignore alpha for main drawing surface
4218
// colorCalcARGB(rgb, colorModeA);
4219
// backgroundFromCalc();
4220
// backgroundImpl();
4223
backgroundFromCalc();
4228
* See notes about alpha in background(x, y, z, a).
4230
public void background(int rgb, float alpha) {
4231
// if (format == RGB) {
4232
// background(rgb); // ignore alpha for main drawing surface
4235
// if (((rgb & 0xff000000) == 0) && (rgb <= colorModeX)) {
4236
// background((float) rgb, alpha);
4239
// colorCalcARGB(rgb, alpha);
4240
// backgroundFromCalc();
4241
// backgroundImpl();
4244
colorCalc(rgb, alpha);
4245
backgroundFromCalc();
4250
* Set the background to a grayscale value, based on the
4251
* current colorMode.
4253
public void background(float gray) {
4255
backgroundFromCalc();
4256
// backgroundImpl();
4261
* See notes about alpha in background(x, y, z, a).
4263
public void background(float gray, float alpha) {
4264
if (format == RGB) {
4265
background(gray); // ignore alpha for main drawing surface
4268
colorCalc(gray, alpha);
4269
backgroundFromCalc();
4270
// backgroundImpl();
4276
* Set the background to an r, g, b or h, s, b value,
4277
* based on the current colorMode.
4279
public void background(float x, float y, float z) {
4281
backgroundFromCalc();
4282
// backgroundImpl();
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.
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.
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
4302
// colorCalc(x, y, z, a);
4303
// backgroundFromCalc();
4304
// backgroundImpl();
4306
colorCalc(x, y, z, a);
4307
backgroundFromCalc();
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;
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.
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.
4337
* When using 3D, this will also clear the zbuffer (if it exists).
4339
public void background(PImage image) {
4340
if ((image.width != width) || (image.height != height)) {
4341
throw new RuntimeException(ERROR_BACKGROUND_IMAGE_SIZE);
4343
if ((image.format != RGB) && (image.format != ARGB)) {
4344
throw new RuntimeException(ERROR_BACKGROUND_IMAGE_FORMAT);
4346
backgroundColor = 0; // just zero it out for images
4347
backgroundImpl(image);
4352
* Actually set the background image. This is separated from the error
4353
* handling and other semantic goofiness that is shared across renderers.
4355
protected void backgroundImpl(PImage image) {
4356
// blit image to the screen
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.
4367
protected void backgroundImpl() {
4371
fill(backgroundColor);
4372
rect(0, 0, width, height);
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.
4383
// protected void backgroundRawImpl() {
4384
// if (raw != null) {
4385
// raw.colorMode(RGB, 1);
4387
// raw.fill(backgroundR, backgroundG, backgroundB);
4388
// raw.beginShape(TRIANGLES);
4390
// raw.vertex(0, 0);
4391
// raw.vertex(width, 0);
4392
// raw.vertex(0, height);
4394
// raw.vertex(width, 0);
4395
// raw.vertex(width, height);
4396
// raw.vertex(0, height);
4404
//////////////////////////////////////////////////////////////
4409
public void colorMode(int mode) {
4410
colorMode(mode, colorModeX, colorModeY, colorModeZ, colorModeA);
4414
public void colorMode(int mode, float max) {
4415
colorMode(mode, max, max, max, max);
4420
* Set the colorMode and the maximum values for (r, g, b)
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.
4428
public void colorMode(int mode, float maxX, float maxY, float maxZ) {
4429
colorMode(mode, maxX, maxY, maxZ, colorModeA);
4433
public void colorMode(int mode,
4434
float maxX, float maxY, float maxZ, float maxA) {
4437
colorModeX = maxX; // still needs to be set for hsb
4442
// if color max values are all 1, then no need to scale
4444
((maxA != 1) || (maxX != maxY) || (maxY != maxZ) || (maxZ != maxA));
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);
4455
//////////////////////////////////////////////////////////////
4457
// COLOR CALCULATIONS
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.
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.
4471
* Set the fill to either a grayscale value or an ARGB int.
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).
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);
4483
* line(i, 0, i, 256);
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.
4490
protected void colorCalc(int rgb) {
4491
if (((rgb & 0xff000000) == 0) && (rgb <= colorModeX)) {
4492
colorCalc((float) rgb);
4495
colorCalcARGB(rgb, colorModeA);
4500
protected void colorCalc(int rgb, float alpha) {
4501
if (((rgb & 0xff000000) == 0) && (rgb <= colorModeX)) { // see above
4502
colorCalc((float) rgb, alpha);
4505
colorCalcARGB(rgb, alpha);
4510
protected void colorCalc(float gray) {
4511
colorCalc(gray, colorModeA);
4515
protected void colorCalc(float gray, float alpha) {
4516
if (gray > colorModeX) gray = colorModeX;
4517
if (alpha > colorModeA) alpha = colorModeA;
4519
if (gray < 0) gray = 0;
4520
if (alpha < 0) alpha = 0;
4522
calcR = colorModeScale ? (gray / colorModeX) : gray;
4525
calcA = colorModeScale ? (alpha / colorModeA) : alpha;
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);
4534
protected void colorCalc(float x, float y, float z) {
4535
colorCalc(x, y, z, colorModeA);
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;
4550
switch (colorMode) {
4552
if (colorModeScale) {
4553
calcR = x / colorModeX;
4554
calcG = y / colorModeY;
4555
calcB = z / colorModeZ;
4556
calcA = a / colorModeA;
4558
calcR = x; calcG = y; calcB = z; calcA = a;
4563
x /= colorModeX; // h
4564
y /= colorModeY; // s
4565
z /= colorModeZ; // b
4567
calcA = colorModeScale ? (a/colorModeA) : a;
4569
if (y == 0) { // saturation == 0
4570
calcR = calcG = calcB = z;
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)));
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;
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);
4598
* Unpacks AARRGGBB color for direct use with colorCalc.
4600
* Handled here with its own function since this is indepenent
4601
* of the color mode.
4603
* Strangely the old version of this code ignored the alpha
4604
* value. not sure if that was a bug or what.
4606
* Note, no need for a bounds check since it's a 32 bit number.
4608
protected void colorCalcARGB(int argb, float alpha) {
4609
if (alpha == colorModeA) {
4610
calcAi = (argb >> 24) & 0xff;
4613
calcAi = (int) (((argb >> 24) & 0xff) * (alpha / colorModeA));
4614
calcColor = (calcAi << 24) | (argb & 0xFFFFFF);
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);
4628
//////////////////////////////////////////////////////////////
4630
// COLOR DATATYPE STUFFING
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.
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.
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;
4651
colorCalcARGB(gray, colorModeA);
4657
public final int color(float gray) { // ignore
4664
* @param gray can be packed ARGB or a gray in this case
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;
4672
return ((alpha & 0xff) << 24) | (gray << 16) | (gray << 8) | gray;
4674
colorCalc(gray, alpha);
4680
* @param rgb can be packed ARGB or a gray in this case
4682
public final int color(int rgb, float alpha) { // ignore
4683
if (((rgb & 0xff000000) == 0) && (rgb <= colorModeX)) {
4684
colorCalc(rgb, alpha);
4686
colorCalcARGB(rgb, alpha);
4692
public final int color(float gray, float alpha) { // ignore
4693
colorCalc(gray, alpha);
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;
4705
return 0xff000000 | (x << 16) | (y << 8) | z;
4712
public final int color(float x, float y, float z) { // ignore
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;
4726
return (a << 24) | (x << 16) | (y << 8) | z;
4728
colorCalc(x, y, z, a);
4733
public final int color(float x, float y, float z, float a) { // ignore
4734
colorCalc(x, y, z, a);
4740
//////////////////////////////////////////////////////////////
4742
// COLOR DATATYPE EXTRACTION
4744
// Vee have veys of making the colors talk.
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;
4754
public final float red(int what) {
4755
float c = (what >> 16) & 0xff;
4756
if (colorModeDefault) return c;
4757
return (c / 255.0f) * colorModeX;
4761
public final float green(int what) {
4762
float c = (what >> 8) & 0xff;
4763
if (colorModeDefault) return c;
4764
return (c / 255.0f) * colorModeY;
4768
public final float blue(int what) {
4769
float c = (what) & 0xff;
4770
if (colorModeDefault) return c;
4771
return (c / 255.0f) * colorModeZ;
4775
public final float hue(int what) {
4776
if (what != cacheHsbKey) {
4777
Color.RGBtoHSB((what >> 16) & 0xff, (what >> 8) & 0xff,
4778
what & 0xff, cacheHsbValue);
4781
return cacheHsbValue[0] * colorModeX;
4785
public final float saturation(int what) {
4786
if (what != cacheHsbKey) {
4787
Color.RGBtoHSB((what >> 16) & 0xff, (what >> 8) & 0xff,
4788
what & 0xff, cacheHsbValue);
4791
return cacheHsbValue[1] * colorModeY;
4795
public final float brightness(int what) {
4796
if (what != cacheHsbKey) {
4797
Color.RGBtoHSB((what >> 16) & 0xff, (what >> 8) & 0xff,
4798
what & 0xff, cacheHsbValue);
4801
return cacheHsbValue[2] * colorModeZ;
4806
//////////////////////////////////////////////////////////////
4808
// COLOR DATATYPE INTERPOLATION
4810
// Against our better judgement.
4814
* Interpolate between two colors, using the current color mode.
4816
public int lerpColor(int c1, int c2, float amt) {
4817
return lerpColor(c1, c2, amt, colorMode);
4820
static float[] lerpColorHSB1;
4821
static float[] lerpColorHSB2;
4824
* Interpolate between two colors. Like lerp(), but for the
4825
* individual color components of a color supplied as an int value.
4827
static public int lerpColor(int c1, int c2, float amt, int mode) {
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;
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)));
4843
} else if (mode == HSB) {
4844
if (lerpColorHSB1 == null) {
4845
lerpColorHSB1 = new float[3];
4846
lerpColorHSB2 = new float[3];
4849
float a1 = (c1 >> 24) & 0xff;
4850
float a2 = (c2 >> 24) & 0xff;
4851
int alfa = ((int) (a1 + (a2-a1)*amt)) << 24;
4853
Color.RGBtoHSB((c1 >> 16) & 0xff, (c1 >> 8) & 0xff, c1 & 0xff,
4855
Color.RGBtoHSB((c2 >> 16) & 0xff, (c2 >> 8) & 0xff, c2 & 0xff,
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.
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
4870
float h1 = lerpColorHSB1[0];
4871
float h2 = lerpColorHSB2[0];
4872
if (Math.abs(h1 - h2) > 0.5f) {
4874
// i.e. h1 is 0.7, h2 is 0.1
4877
// i.e. h1 is 0.1, h2 is 0.7
4881
float ho = (PApplet.lerp(lerpColorHSB1[0], lerpColorHSB2[0], amt)) % 1.0f;
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);
4887
return alfa | (Color.HSBtoRGB(ho, so, bo) & 0xFFFFFF);
4894
//////////////////////////////////////////////////////////////
4900
* Record individual lines and triangles by echoing them to another renderer.
4902
public void beginRaw(PGraphics rawGraphics) { // ignore
4903
this.raw = rawGraphics;
4904
rawGraphics.beginDraw();
4908
public void endRaw() { // ignore
4910
// for 3D, need to flush any geometry that's been stored for sorting
4911
// (particularly if the ENABLE_DEPTH_SORT hint is set)
4914
// just like beginDraw, this will have to be called because
4915
// endDraw() will be happening outside of draw()
4924
//////////////////////////////////////////////////////////////
4926
// WARNINGS and EXCEPTIONS
4929
static protected HashMap<String, Object> warnings;
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)
4936
static public void showWarning(String msg) { // ignore
4937
if (warnings == null) {
4938
warnings = new HashMap<String, Object>();
4940
if (!warnings.containsKey(msg)) {
4941
System.err.println(msg);
4942
warnings.put(msg, new Object());
4948
* Display a warning that the specified method is only available with 3D.
4949
* @param method The method name (no parentheses)
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.");
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)
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.");
4971
* Display a warning that the specified method is simply unavailable.
4973
static protected void showMethodWarning(String method) {
4974
showWarning(method + "() is not available with this renderer.");
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.
4983
static protected void showVariationWarning(String str) {
4984
showWarning(str + " is not available with this renderer.");
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.
4993
static protected void showMissingWarning(String method) {
4994
showWarning(method + "(), or this particular variation of it, " +
4995
"is not available with this renderer.");
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.
5004
static public void showException(String msg) { // ignore
5005
throw new RuntimeException(msg);
5010
* Throw an exeption that halts the program because textFont() has not been
5011
* used prior to the specified method.
5013
static protected void showTextFontException(String method) {
5014
throw new RuntimeException("Use textFont() before " + method + "()");
5019
//////////////////////////////////////////////////////////////
5021
// RENDERER SUPPORT QUERIES
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.
5029
* A better name? showFrame, displayable, isVisible, visible, shouldDisplay,
5030
* what to call this?
5032
public boolean displayable() {
5038
* Return true if this renderer supports 2D drawing. Defaults to true.
5040
public boolean is2D() {
5046
* Return true if this renderer supports 2D drawing. Defaults to true.
5048
public boolean is3D() {