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

« back to all changes in this revision

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

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

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
 
2
 
 
3
/*
 
4
  Part of the Processing project - http://processing.org
 
5
 
 
6
  Copyright (c) 2004-08 Ben Fry and Casey Reas
 
7
  Copyright (c) 2001-04 Massachusetts Institute of Technology
 
8
 
 
9
  This library is free software; you can redistribute it and/or
 
10
  modify it under the terms of the GNU Lesser General Public
 
11
  License as published by the Free Software Foundation; either
 
12
  version 2.1 of the License, or (at your option) any later version.
 
13
 
 
14
  This library is distributed in the hope that it will be useful,
 
15
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
17
  Lesser General Public License for more details.
 
18
 
 
19
  You should have received a copy of the GNU Lesser General
 
20
  Public License along with this library; if not, write to the
 
21
  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 
22
  Boston, MA  02111-1307  USA
 
23
*/
 
24
 
 
25
package processing.core;
 
26
 
 
27
import java.awt.Toolkit;
 
28
import java.awt.image.*;
 
29
import java.util.*;
 
30
 
 
31
 
 
32
/**
 
33
 * Subclass of PGraphics that handles 3D rendering.
 
34
 * It can render 3D inside a browser window and requires no plug-ins.
 
35
 * <p/>
 
36
 * The renderer is mostly set up based on the structure of the OpenGL API,
 
37
 * if you have questions about specifics that aren't covered here,
 
38
 * look for reference on the OpenGL implementation of a similar feature.
 
39
 * <p/>
 
40
 * Lighting and camera implementation by Simon Greenwold.
 
41
 */
 
42
public class PGraphics3D extends PGraphics {
 
43
 
 
44
  /** The depth buffer. */
 
45
  public float[] zbuffer;
 
46
 
 
47
  // ........................................................
 
48
 
 
49
  /** The modelview matrix. */
 
50
  public PMatrix3D modelview;
 
51
 
 
52
  /** Inverse modelview matrix, used for lighting. */
 
53
  public PMatrix3D modelviewInv;
 
54
 
 
55
  /**
 
56
   * The camera matrix, the modelview will be set to this on beginDraw.
 
57
   */
 
58
  public PMatrix3D camera;
 
59
 
 
60
  /** Inverse camera matrix */
 
61
  protected PMatrix3D cameraInv;
 
62
 
 
63
  /** Camera field of view. */
 
64
  public float cameraFOV;
 
65
 
 
66
  /** Position of the camera. */
 
67
  public float cameraX, cameraY, cameraZ;
 
68
  public float cameraNear, cameraFar;
 
69
  /** Aspect ratio of camera's view. */
 
70
  public float cameraAspect;
 
71
 
 
72
  /** Current projection matrix. */
 
73
  public PMatrix3D projection;
 
74
 
 
75
 
 
76
  //////////////////////////////////////////////////////////////
 
77
 
 
78
 
 
79
  /**
 
80
   * Maximum lights by default is 8, which is arbitrary for this renderer,
 
81
   * but is the minimum defined by OpenGL
 
82
   */
 
83
  public static final int MAX_LIGHTS = 8;
 
84
 
 
85
  public int lightCount = 0;
 
86
 
 
87
  /** Light types */
 
88
  public int[] lightType;
 
89
 
 
90
  /** Light positions */
 
91
  //public float[][] lightPosition;
 
92
  public PVector[] lightPosition;
 
93
 
 
94
  /** Light direction (normalized vector) */
 
95
  //public float[][] lightNormal;
 
96
  public PVector[] lightNormal;
 
97
 
 
98
  /** Light falloff */
 
99
  public float[] lightFalloffConstant;
 
100
  public float[] lightFalloffLinear;
 
101
  public float[] lightFalloffQuadratic;
 
102
 
 
103
  /** Light spot angle */
 
104
  public float[] lightSpotAngle;
 
105
 
 
106
  /** Cosine of light spot angle */
 
107
  public float[] lightSpotAngleCos;
 
108
 
 
109
  /** Light spot concentration */
 
110
  public float[] lightSpotConcentration;
 
111
 
 
112
  /** Diffuse colors for lights.
 
113
   *  For an ambient light, this will hold the ambient color.
 
114
   *  Internally these are stored as numbers between 0 and 1. */
 
115
  public float[][] lightDiffuse;
 
116
 
 
117
  /** Specular colors for lights.
 
118
      Internally these are stored as numbers between 0 and 1. */
 
119
  public float[][] lightSpecular;
 
120
 
 
121
  /** Current specular color for lighting */
 
122
  public float[] currentLightSpecular;
 
123
 
 
124
  /** Current light falloff */
 
125
  public float currentLightFalloffConstant;
 
126
  public float currentLightFalloffLinear;
 
127
  public float currentLightFalloffQuadratic;
 
128
 
 
129
 
 
130
  //////////////////////////////////////////////////////////////
 
131
 
 
132
 
 
133
  static public final int TRI_DIFFUSE_R = 0;
 
134
  static public final int TRI_DIFFUSE_G = 1;
 
135
  static public final int TRI_DIFFUSE_B = 2;
 
136
  static public final int TRI_DIFFUSE_A = 3;
 
137
  static public final int TRI_SPECULAR_R = 4;
 
138
  static public final int TRI_SPECULAR_G = 5;
 
139
  static public final int TRI_SPECULAR_B = 6;
 
140
  static public final int TRI_COLOR_COUNT = 7;
 
141
 
 
142
  // ........................................................
 
143
 
 
144
  // Whether or not we have to worry about vertex position for lighting calcs
 
145
  private boolean lightingDependsOnVertexPosition;
 
146
 
 
147
  static final int LIGHT_AMBIENT_R = 0;
 
148
  static final int LIGHT_AMBIENT_G = 1;
 
149
  static final int LIGHT_AMBIENT_B = 2;
 
150
  static final int LIGHT_DIFFUSE_R = 3;
 
151
  static final int LIGHT_DIFFUSE_G = 4;
 
152
  static final int LIGHT_DIFFUSE_B = 5;
 
153
  static final int LIGHT_SPECULAR_R = 6;
 
154
  static final int LIGHT_SPECULAR_G = 7;
 
155
  static final int LIGHT_SPECULAR_B = 8;
 
156
  static final int LIGHT_COLOR_COUNT = 9;
 
157
 
 
158
  // Used to shuttle lighting calcs around
 
159
  // (no need to re-allocate all the time)
 
160
  protected float[] tempLightingContribution = new float[LIGHT_COLOR_COUNT];
 
161
//  protected float[] worldNormal = new float[4];
 
162
 
 
163
  /// Used in lightTriangle(). Allocated here once to avoid re-allocating
 
164
  protected PVector lightTriangleNorm = new PVector();
 
165
 
 
166
  // ........................................................
 
167
 
 
168
  /**
 
169
   * This is turned on at beginCamera, and off at endCamera
 
170
   * Currently we don't support nested begin/end cameras.
 
171
   * If we wanted to, this variable would have to become a stack.
 
172
   */
 
173
  protected boolean manipulatingCamera;
 
174
 
 
175
  float[][] matrixStack = new float[MATRIX_STACK_DEPTH][16];
 
176
  float[][] matrixInvStack = new float[MATRIX_STACK_DEPTH][16];
 
177
  int matrixStackDepth;
 
178
 
 
179
  // These two matrices always point to either the modelview
 
180
  // or the modelviewInv, but they are swapped during
 
181
  // when in camera manipulation mode. That way camera transforms
 
182
  // are automatically accumulated in inverse on the modelview matrix.
 
183
  protected PMatrix3D forwardTransform;
 
184
  protected PMatrix3D reverseTransform;
 
185
 
 
186
  // Added by ewjordan for accurate texturing purposes. Screen plane is
 
187
  // not scaled to pixel-size, so these manually keep track of its size
 
188
  // from frustum() calls. Sorry to add public vars, is there a way
 
189
  // to compute these from something publicly available without matrix ops?
 
190
  // (used once per triangle in PTriangle with ENABLE_ACCURATE_TEXTURES)
 
191
  protected float leftScreen;
 
192
  protected float rightScreen;
 
193
  protected float topScreen;
 
194
  protected float bottomScreen;
 
195
  protected float nearPlane; //depth of near clipping plane
 
196
 
 
197
  /** true if frustum has been called to set perspective, false if ortho */
 
198
  private boolean frustumMode = false;
 
199
 
 
200
  /**
 
201
   * Use PSmoothTriangle for rendering instead of PTriangle?
 
202
   * Usually set by calling smooth() or noSmooth()
 
203
   */
 
204
  static protected boolean s_enableAccurateTextures = false; //maybe just use smooth instead?
 
205
 
 
206
  /** Used for anti-aliased and perspective corrected rendering. */
 
207
  public PSmoothTriangle smoothTriangle;
 
208
 
 
209
 
 
210
  // ........................................................
 
211
 
 
212
  // pos of first vertex of current shape in vertices array
 
213
  protected int shapeFirst;
 
214
 
 
215
  // i think vertex_end is actually the last vertex in the current shape
 
216
  // and is separate from vertexCount for occasions where drawing happens
 
217
  // on endDraw() with all the triangles being depth sorted
 
218
  protected int shapeLast;
 
219
 
 
220
  // vertices may be added during clipping against the near plane.
 
221
  protected int shapeLastPlusClipped;
 
222
 
 
223
  // used for sorting points when triangulating a polygon
 
224
  // warning - maximum number of vertices for a polygon is DEFAULT_VERTICES
 
225
  protected int vertexOrder[] = new int[DEFAULT_VERTICES];
 
226
 
 
227
  // ........................................................
 
228
 
 
229
  // This is done to keep track of start/stop information for lines in the
 
230
  // line array, so that lines can be shown as a single path, rather than just
 
231
  // individual segments. Currently only in use inside PGraphicsOpenGL.
 
232
  protected int pathCount;
 
233
  protected int[] pathOffset = new int[64];
 
234
  protected int[] pathLength = new int[64];
 
235
 
 
236
  // ........................................................
 
237
 
 
238
  // line & triangle fields (note that these overlap)
 
239
//  static protected final int INDEX = 0;          // shape index
 
240
  static protected final int VERTEX1 = 0;
 
241
  static protected final int VERTEX2 = 1;
 
242
  static protected final int VERTEX3 = 2;        // (triangles only)
 
243
  /** used to store the strokeColor int for efficient drawing. */
 
244
  static protected final int STROKE_COLOR = 1;   // (points only)
 
245
  static protected final int TEXTURE_INDEX = 3;  // (triangles only)
 
246
  //static protected final int STROKE_MODE = 2;    // (lines only)
 
247
  //static protected final int STROKE_WEIGHT = 3;  // (lines only)
 
248
 
 
249
  static protected final int POINT_FIELD_COUNT = 2;  //4
 
250
  static protected final int LINE_FIELD_COUNT = 2;  //4
 
251
  static protected final int TRIANGLE_FIELD_COUNT = 4;
 
252
 
 
253
  // points
 
254
  static final int DEFAULT_POINTS = 512;
 
255
  protected int[][] points = new int[DEFAULT_POINTS][POINT_FIELD_COUNT];
 
256
  protected int pointCount;
 
257
 
 
258
  // lines
 
259
  static final int DEFAULT_LINES = 512;
 
260
  public PLine line;  // used for drawing
 
261
  protected int[][] lines = new int[DEFAULT_LINES][LINE_FIELD_COUNT];
 
262
  protected int lineCount;
 
263
 
 
264
  // triangles
 
265
  static final int DEFAULT_TRIANGLES = 256;
 
266
  public PTriangle triangle;
 
267
  protected int[][] triangles =
 
268
    new int[DEFAULT_TRIANGLES][TRIANGLE_FIELD_COUNT];
 
269
  protected float triangleColors[][][] =
 
270
    new float[DEFAULT_TRIANGLES][3][TRI_COLOR_COUNT];
 
271
  protected int triangleCount;   // total number of triangles
 
272
 
 
273
  // cheap picking someday
 
274
  //public int shape_index;
 
275
 
 
276
  // ........................................................
 
277
 
 
278
  static final int DEFAULT_TEXTURES = 3;
 
279
  protected PImage[] textures = new PImage[DEFAULT_TEXTURES];
 
280
  int textureIndex;
 
281
 
 
282
  // ........................................................
 
283
 
 
284
  DirectColorModel cm;
 
285
  MemoryImageSource mis;
 
286
 
 
287
 
 
288
  //////////////////////////////////////////////////////////////
 
289
 
 
290
 
 
291
  public PGraphics3D() { }
 
292
 
 
293
 
 
294
  //public void setParent(PApplet parent)
 
295
 
 
296
 
 
297
  //public void setPrimary(boolean primary)
 
298
 
 
299
 
 
300
  //public void setPath(String path)
 
301
 
 
302
 
 
303
  /**
 
304
   * Called in response to a resize event, handles setting the
 
305
   * new width and height internally, as well as re-allocating
 
306
   * the pixel buffer for the new size.
 
307
   *
 
308
   * Note that this will nuke any cameraMode() settings.
 
309
   */
 
310
  public void setSize(int iwidth, int iheight) {  // ignore
 
311
    width = iwidth;
 
312
    height = iheight;
 
313
    width1 = width - 1;
 
314
    height1 = height - 1;
 
315
 
 
316
    allocate();
 
317
    reapplySettings();
 
318
 
 
319
    // init lights (in resize() instead of allocate() b/c needed by opengl)
 
320
    lightType = new int[MAX_LIGHTS];
 
321
    lightPosition = new PVector[MAX_LIGHTS];
 
322
    lightNormal = new PVector[MAX_LIGHTS];
 
323
    for (int i = 0; i < MAX_LIGHTS; i++) {
 
324
      lightPosition[i] = new PVector();
 
325
      lightNormal[i] = new PVector();
 
326
    }
 
327
    lightDiffuse = new float[MAX_LIGHTS][3];
 
328
    lightSpecular = new float[MAX_LIGHTS][3];
 
329
    lightFalloffConstant = new float[MAX_LIGHTS];
 
330
    lightFalloffLinear = new float[MAX_LIGHTS];
 
331
    lightFalloffQuadratic = new float[MAX_LIGHTS];
 
332
    lightSpotAngle = new float[MAX_LIGHTS];
 
333
    lightSpotAngleCos = new float[MAX_LIGHTS];
 
334
    lightSpotConcentration = new float[MAX_LIGHTS];
 
335
    currentLightSpecular = new float[3];
 
336
 
 
337
    projection = new PMatrix3D();
 
338
    modelview = new PMatrix3D();
 
339
    modelviewInv = new PMatrix3D();
 
340
 
 
341
//    modelviewStack = new float[MATRIX_STACK_DEPTH][16];
 
342
//    modelviewInvStack = new float[MATRIX_STACK_DEPTH][16];
 
343
//    modelviewStackPointer = 0;
 
344
 
 
345
    forwardTransform = modelview;
 
346
    reverseTransform = modelviewInv;
 
347
 
 
348
    // init perspective projection based on new dimensions
 
349
    cameraFOV = 60 * DEG_TO_RAD; // at least for now
 
350
    cameraX = width / 2.0f;
 
351
    cameraY = height / 2.0f;
 
352
    cameraZ = cameraY / ((float) Math.tan(cameraFOV / 2.0f));
 
353
    cameraNear = cameraZ / 10.0f;
 
354
    cameraFar = cameraZ * 10.0f;
 
355
    cameraAspect = (float)width / (float)height;
 
356
 
 
357
    camera = new PMatrix3D();
 
358
    cameraInv = new PMatrix3D();
 
359
 
 
360
    // set up the default camera
 
361
//    camera();
 
362
 
 
363
    // defaults to perspective, if the user has setup up their
 
364
    // own projection, they'll need to fix it after resize anyway.
 
365
    // this helps the people who haven't set up their own projection.
 
366
//    perspective();
 
367
  }
 
368
 
 
369
 
 
370
  protected void allocate() {
 
371
    //System.out.println(this + " allocating for " + width + " " + height);
 
372
    //new Exception().printStackTrace();
 
373
 
 
374
    pixelCount = width * height;
 
375
    pixels = new int[pixelCount];
 
376
    zbuffer = new float[pixelCount];
 
377
 
 
378
    if (primarySurface) {
 
379
      cm = new DirectColorModel(32, 0x00ff0000, 0x0000ff00, 0x000000ff);;
 
380
      mis = new MemoryImageSource(width, height, pixels, 0, width);
 
381
      mis.setFullBufferUpdates(true);
 
382
      mis.setAnimated(true);
 
383
      image = Toolkit.getDefaultToolkit().createImage(mis);
 
384
 
 
385
    } else {
 
386
      // when not the main drawing surface, need to set the zbuffer,
 
387
      // because there's a possibility that background() will not be called
 
388
      Arrays.fill(zbuffer, Float.MAX_VALUE);
 
389
    }
 
390
 
 
391
    line = new PLine(this);
 
392
    triangle = new PTriangle(this);
 
393
    smoothTriangle = new PSmoothTriangle(this);
 
394
  }
 
395
 
 
396
 
 
397
  //public void dispose()
 
398
 
 
399
 
 
400
  ////////////////////////////////////////////////////////////
 
401
 
 
402
 
 
403
  //public boolean canDraw()
 
404
 
 
405
 
 
406
  public void beginDraw() {
 
407
    // need to call defaults(), but can only be done when it's ok
 
408
    // to draw (i.e. for opengl, no drawing can be done outside
 
409
    // beginDraw/endDraw).
 
410
    if (!settingsInited) defaultSettings();
 
411
 
 
412
    resetMatrix(); // reset model matrix
 
413
 
 
414
    // reset vertices
 
415
    vertexCount = 0;
 
416
 
 
417
    modelview.set(camera);
 
418
    modelviewInv.set(cameraInv);
 
419
 
 
420
    // clear out the lights, they'll have to be turned on again
 
421
    lightCount = 0;
 
422
    lightingDependsOnVertexPosition = false;
 
423
    lightFalloff(1, 0, 0);
 
424
    lightSpecular(0, 0, 0);
 
425
 
 
426
    /*
 
427
    // reset lines
 
428
    lineCount = 0;
 
429
    if (line != null) line.reset();  // is this necessary?
 
430
    pathCount = 0;
 
431
 
 
432
    // reset triangles
 
433
    triangleCount = 0;
 
434
    if (triangle != null) triangle.reset();  // necessary?
 
435
    */
 
436
 
 
437
    shapeFirst = 0;
 
438
 
 
439
    // reset textures
 
440
    textureIndex = 0;
 
441
 
 
442
    normal(0, 0, 1);
 
443
  }
 
444
 
 
445
 
 
446
  /**
 
447
   * See notes in PGraphics.
 
448
   * If z-sorting has been turned on, then the triangles will
 
449
   * all be quicksorted here (to make alpha work more properly)
 
450
   * and then blit to the screen.
 
451
   */
 
452
  public void endDraw() {
 
453
    // no need to z order and render
 
454
    // shapes were already rendered in endShape();
 
455
    // (but can't return, since needs to update memimgsrc)
 
456
    if (hints[ENABLE_DEPTH_SORT]) {
 
457
      flush();
 
458
    }
 
459
    if (mis != null) {
 
460
      mis.newPixels(pixels, cm, 0, width);
 
461
    }
 
462
    // mark pixels as having been updated, so that they'll work properly
 
463
    // when this PGraphics is drawn using image().
 
464
    updatePixels();
 
465
  }
 
466
 
 
467
 
 
468
  ////////////////////////////////////////////////////////////
 
469
 
 
470
 
 
471
  //protected void checkSettings()
 
472
 
 
473
 
 
474
  protected void defaultSettings() {
 
475
    super.defaultSettings();
 
476
 
 
477
    manipulatingCamera = false;
 
478
    forwardTransform = modelview;
 
479
    reverseTransform = modelviewInv;
 
480
 
 
481
    // set up the default camera
 
482
    camera();
 
483
 
 
484
    // defaults to perspective, if the user has setup up their
 
485
    // own projection, they'll need to fix it after resize anyway.
 
486
    // this helps the people who haven't set up their own projection.
 
487
    perspective();
 
488
 
 
489
    // easiest for beginners
 
490
    textureMode(IMAGE);
 
491
 
 
492
    emissive(0.0f);
 
493
    specular(0.5f);
 
494
    shininess(1.0f);
 
495
  }
 
496
 
 
497
 
 
498
  //protected void reapplySettings()
 
499
 
 
500
 
 
501
  ////////////////////////////////////////////////////////////
 
502
 
 
503
 
 
504
  public void hint(int which) {
 
505
    if (which == DISABLE_DEPTH_SORT) {
 
506
      flush();
 
507
    } else if (which == DISABLE_DEPTH_TEST) {
 
508
      if (zbuffer != null) {  // will be null in OpenGL and others
 
509
        Arrays.fill(zbuffer, Float.MAX_VALUE);
 
510
      }
 
511
    }
 
512
    super.hint(which);
 
513
  }
 
514
 
 
515
 
 
516
  //////////////////////////////////////////////////////////////
 
517
 
 
518
 
 
519
  //public void beginShape()
 
520
 
 
521
 
 
522
  public void beginShape(int kind) {
 
523
    shape = kind;
 
524
 
 
525
//    shape_index = shape_index + 1;
 
526
//    if (shape_index == -1) {
 
527
//      shape_index = 0;
 
528
//    }
 
529
 
 
530
    if (hints[ENABLE_DEPTH_SORT]) {
 
531
      // continue with previous vertex, line and triangle count
 
532
      // all shapes are rendered at endDraw();
 
533
      shapeFirst = vertexCount;
 
534
      shapeLast = 0;
 
535
 
 
536
    } else {
 
537
      // reset vertex, line and triangle information
 
538
      // every shape is rendered at endShape();
 
539
      vertexCount = 0;
 
540
      if (line != null) line.reset();  // necessary?
 
541
      lineCount = 0;
 
542
//      pathCount = 0;
 
543
      if (triangle != null) triangle.reset();  // necessary?
 
544
      triangleCount = 0;
 
545
    }
 
546
 
 
547
    textureImage = null;
 
548
    curveVertexCount = 0;
 
549
    normalMode = NORMAL_MODE_AUTO;
 
550
//    normalCount = 0;
 
551
  }
 
552
 
 
553
 
 
554
  //public void normal(float nx, float ny, float nz)
 
555
 
 
556
 
 
557
  //public void textureMode(int mode)
 
558
 
 
559
 
 
560
  public void texture(PImage image) {
 
561
    textureImage = image;
 
562
 
 
563
    if (textureIndex == textures.length - 1) {
 
564
      textures = (PImage[]) PApplet.expand(textures);
 
565
    }
 
566
    if (textures[textureIndex] != null) {  // ???
 
567
      textureIndex++;
 
568
    }
 
569
    textures[textureIndex] = image;
 
570
  }
 
571
 
 
572
 
 
573
  public void vertex(float x, float y) {
 
574
    // override so that the default 3D implementation will be used,
 
575
    // which will pick up all 3D settings (e.g. emissive, ambient)
 
576
    vertex(x, y, 0);
 
577
  }
 
578
 
 
579
 
 
580
  //public void vertex(float x, float y, float z)
 
581
 
 
582
 
 
583
  public void vertex(float x, float y, float u, float v) {
 
584
    // see vertex(x, y) for note
 
585
    vertex(x, y, 0, u, v);
 
586
  }
 
587
 
 
588
 
 
589
  //public void vertex(float x, float y, float z, float u, float v)
 
590
 
 
591
 
 
592
  //public void breakShape()
 
593
 
 
594
 
 
595
  //public void endShape()
 
596
 
 
597
 
 
598
  public void endShape(int mode) {
 
599
    shapeLast = vertexCount;
 
600
    shapeLastPlusClipped = shapeLast;
 
601
 
 
602
    // don't try to draw if there are no vertices
 
603
    // (fixes a bug in LINE_LOOP that re-adds a nonexistent vertex)
 
604
    if (vertexCount == 0) {
 
605
      shape = 0;
 
606
      return;
 
607
    }
 
608
 
 
609
    // convert points from model (X/Y/Z) to camera space (VX/VY/VZ).
 
610
    // Do this now because we will be clipping them on add_triangle.
 
611
    endShapeModelToCamera(shapeFirst, shapeLast);
 
612
 
 
613
    if (stroke) {
 
614
      endShapeStroke(mode);
 
615
    }
 
616
 
 
617
    if (fill || textureImage != null) {
 
618
      endShapeFill();
 
619
    }
 
620
 
 
621
    // transform, light, and clip
 
622
    endShapeLighting(lightCount > 0 && fill);
 
623
 
 
624
    // convert points from camera space (VX, VY, VZ) to screen space (X, Y, Z)
 
625
    // (this appears to be wasted time with the OpenGL renderer)
 
626
    endShapeCameraToScreen(shapeFirst, shapeLastPlusClipped);
 
627
 
 
628
    // render shape and fill here if not saving the shapes for later
 
629
    // if true, the shapes will be rendered on endDraw
 
630
    if (!hints[ENABLE_DEPTH_SORT]) {
 
631
      if (fill || textureImage != null) {
 
632
        if (triangleCount > 0) {
 
633
          renderTriangles(0, triangleCount);
 
634
          if (raw != null) {
 
635
            rawTriangles(0, triangleCount);
 
636
          }
 
637
          triangleCount = 0;
 
638
        }
 
639
      }
 
640
      if (stroke) {
 
641
        if (pointCount > 0) {
 
642
          renderPoints(0, pointCount);
 
643
          if (raw != null) {
 
644
            rawPoints(0, pointCount);
 
645
          }
 
646
          pointCount = 0;
 
647
        }
 
648
 
 
649
        if (lineCount > 0) {
 
650
          renderLines(0, lineCount);
 
651
          if (raw != null) {
 
652
            rawLines(0, lineCount);
 
653
          }
 
654
          lineCount = 0;
 
655
        }
 
656
      }
 
657
      pathCount = 0;
 
658
    }
 
659
 
 
660
    shape = 0;
 
661
  }
 
662
 
 
663
 
 
664
  protected void endShapeModelToCamera(int start, int stop) {
 
665
    for (int i = start; i < stop; i++) {
 
666
      float vertex[] = vertices[i];
 
667
 
 
668
      vertex[VX] =
 
669
        modelview.m00*vertex[X] + modelview.m01*vertex[Y] +
 
670
        modelview.m02*vertex[Z] + modelview.m03;
 
671
      vertex[VY] =
 
672
        modelview.m10*vertex[X] + modelview.m11*vertex[Y] +
 
673
        modelview.m12*vertex[Z] + modelview.m13;
 
674
      vertex[VZ] =
 
675
        modelview.m20*vertex[X] + modelview.m21*vertex[Y] +
 
676
        modelview.m22*vertex[Z] + modelview.m23;
 
677
      vertex[VW] =
 
678
        modelview.m30*vertex[X] + modelview.m31*vertex[Y] +
 
679
        modelview.m32*vertex[Z] + modelview.m33;
 
680
 
 
681
      // normalize
 
682
      if (vertex[VW] != 0 && vertex[VW] != 1) {
 
683
        vertex[VX] /= vertex[VW];
 
684
        vertex[VY] /= vertex[VW];
 
685
        vertex[VZ] /= vertex[VW];
 
686
      }
 
687
      vertex[VW] = 1;
 
688
    }
 
689
  }
 
690
 
 
691
 
 
692
  protected void endShapeStroke(int mode) {
 
693
    switch (shape) {
 
694
    case POINTS:
 
695
    {
 
696
      int stop = shapeLast;
 
697
      for (int i = shapeFirst; i < stop; i++) {
 
698
//        if (strokeWeight == 1) {
 
699
        addPoint(i);
 
700
//        } else {
 
701
//          addLineBreak();  // total overkill for points
 
702
//          addLine(i, i);
 
703
//        }
 
704
      }
 
705
    }
 
706
    break;
 
707
 
 
708
    case LINES:
 
709
    {
 
710
      // store index of first vertex
 
711
      int first = lineCount;
 
712
      int stop = shapeLast - 1;
 
713
      //increment = (shape == LINES) ? 2 : 1;
 
714
 
 
715
      // for LINE_STRIP and LINE_LOOP, make this all one path
 
716
      if (shape != LINES) addLineBreak();
 
717
 
 
718
      for (int i = shapeFirst; i < stop; i += 2) {
 
719
        // for LINES, make a new path for each segment
 
720
        if (shape == LINES) addLineBreak();
 
721
        addLine(i, i+1);
 
722
      }
 
723
 
 
724
      // for LINE_LOOP, close the loop with a final segment
 
725
      //if (shape == LINE_LOOP) {
 
726
      if (mode == CLOSE) {
 
727
        addLine(stop, lines[first][VERTEX1]);
 
728
      }
 
729
    }
 
730
    break;
 
731
 
 
732
    case TRIANGLES:
 
733
    {
 
734
      for (int i = shapeFirst; i < shapeLast-2; i += 3) {
 
735
        addLineBreak();
 
736
        //counter = i - vertex_start;
 
737
        addLine(i+0, i+1);
 
738
        addLine(i+1, i+2);
 
739
        addLine(i+2, i+0);
 
740
      }
 
741
    }
 
742
    break;
 
743
 
 
744
    case TRIANGLE_STRIP:
 
745
    {
 
746
      // first draw all vertices as a line strip
 
747
      int stop = shapeLast-1;
 
748
 
 
749
      addLineBreak();
 
750
      for (int i = shapeFirst; i < stop; i++) {
 
751
        //counter = i - vertex_start;
 
752
        addLine(i, i+1);
 
753
      }
 
754
 
 
755
      // then draw from vertex (n) to (n+2)
 
756
      stop = shapeLast-2;
 
757
      for (int i = shapeFirst; i < stop; i++) {
 
758
        addLineBreak();
 
759
        addLine(i, i+2);
 
760
      }
 
761
    }
 
762
    break;
 
763
 
 
764
    case TRIANGLE_FAN:
 
765
    {
 
766
      // this just draws a series of line segments
 
767
      // from the center to each exterior point
 
768
      for (int i = shapeFirst + 1; i < shapeLast; i++) {
 
769
        addLineBreak();
 
770
        addLine(shapeFirst, i);
 
771
      }
 
772
 
 
773
      // then a single line loop around the outside.
 
774
      addLineBreak();
 
775
      for (int i = shapeFirst + 1; i < shapeLast-1; i++) {
 
776
        addLine(i, i+1);
 
777
      }
 
778
      // closing the loop
 
779
      addLine(shapeLast-1, shapeFirst + 1);
 
780
    }
 
781
    break;
 
782
 
 
783
    case QUADS:
 
784
    {
 
785
      for (int i = shapeFirst; i < shapeLast; i += 4) {
 
786
        addLineBreak();
 
787
        //counter = i - vertex_start;
 
788
        addLine(i+0, i+1);
 
789
        addLine(i+1, i+2);
 
790
        addLine(i+2, i+3);
 
791
        addLine(i+3, i+0);
 
792
      }
 
793
    }
 
794
    break;
 
795
 
 
796
    case QUAD_STRIP:
 
797
    {
 
798
      for (int i = shapeFirst; i < shapeLast - 3; i += 2) {
 
799
        addLineBreak();
 
800
        addLine(i+0, i+2);
 
801
        addLine(i+2, i+3);
 
802
        addLine(i+3, i+1);
 
803
        addLine(i+1, i+0);
 
804
      }
 
805
    }
 
806
    break;
 
807
 
 
808
    case POLYGON:
 
809
    {
 
810
      // store index of first vertex
 
811
      int stop = shapeLast - 1;
 
812
 
 
813
      addLineBreak();
 
814
      for (int i = shapeFirst; i < stop; i++) {
 
815
        addLine(i, i+1);
 
816
      }
 
817
      if (mode == CLOSE) {
 
818
        // draw the last line connecting back to the first point in poly
 
819
        addLine(stop, shapeFirst); //lines[first][VERTEX1]);
 
820
      }
 
821
    }
 
822
    break;
 
823
    }
 
824
  }
 
825
 
 
826
 
 
827
  protected void endShapeFill() {
 
828
    switch (shape) {
 
829
    case TRIANGLE_FAN:
 
830
    {
 
831
      int stop = shapeLast - 1;
 
832
      for (int i = shapeFirst + 1; i < stop; i++) {
 
833
        addTriangle(shapeFirst, i, i+1);
 
834
      }
 
835
    }
 
836
    break;
 
837
 
 
838
    case TRIANGLES:
 
839
    {
 
840
      int stop = shapeLast - 2;
 
841
      for (int i = shapeFirst; i < stop; i += 3) {
 
842
        // have to switch between clockwise/counter-clockwise
 
843
        // otherwise the feller is backwards and renderer won't draw
 
844
        if ((i % 2) == 0) {
 
845
          addTriangle(i, i+2, i+1);
 
846
        } else {
 
847
          addTriangle(i, i+1, i+2);
 
848
        }
 
849
      }
 
850
    }
 
851
    break;
 
852
 
 
853
    case TRIANGLE_STRIP:
 
854
    {
 
855
      int stop = shapeLast - 2;
 
856
      for (int i = shapeFirst; i < stop; i++) {
 
857
        // have to switch between clockwise/counter-clockwise
 
858
        // otherwise the feller is backwards and renderer won't draw
 
859
        if ((i % 2) == 0) {
 
860
          addTriangle(i, i+2, i+1);
 
861
        } else {
 
862
          addTriangle(i, i+1, i+2);
 
863
        }
 
864
      }
 
865
    }
 
866
    break;
 
867
 
 
868
    case QUADS:
 
869
    {
 
870
      int stop = vertexCount-3;
 
871
      for (int i = shapeFirst; i < stop; i += 4) {
 
872
        // first triangle
 
873
        addTriangle(i, i+1, i+2);
 
874
        // second triangle
 
875
        addTriangle(i, i+2, i+3);
 
876
      }
 
877
    }
 
878
    break;
 
879
 
 
880
    case QUAD_STRIP:
 
881
    {
 
882
      int stop = vertexCount-3;
 
883
      for (int i = shapeFirst; i < stop; i += 2) {
 
884
        // first triangle
 
885
        addTriangle(i+0, i+2, i+1);
 
886
        // second triangle
 
887
        addTriangle(i+2, i+3, i+1);
 
888
      }
 
889
    }
 
890
    break;
 
891
 
 
892
    case POLYGON:
 
893
    {
 
894
      addPolygonTriangles();
 
895
    }
 
896
    break;
 
897
    }
 
898
  }
 
899
 
 
900
 
 
901
  protected void endShapeLighting(boolean lights) {
 
902
    if (lights) {
 
903
      // If the lighting does not depend on vertex position and there is a single
 
904
      // normal specified for this shape, go ahead and apply the same lighting
 
905
      // contribution to every vertex in this shape (one lighting calc!)
 
906
      if (!lightingDependsOnVertexPosition && normalMode == NORMAL_MODE_SHAPE) {
 
907
        calcLightingContribution(shapeFirst, tempLightingContribution);
 
908
        for (int tri = 0; tri < triangleCount; tri++) {
 
909
          lightTriangle(tri, tempLightingContribution);
 
910
        }
 
911
      } else {  // Otherwise light each triangle individually...
 
912
        for (int tri = 0; tri < triangleCount; tri++) {
 
913
          lightTriangle(tri);
 
914
        }
 
915
      }
 
916
    } else {
 
917
      for (int tri = 0; tri < triangleCount; tri++) {
 
918
        int index = triangles[tri][VERTEX1];
 
919
        copyPrelitVertexColor(tri, index, 0);
 
920
        index = triangles[tri][VERTEX2];
 
921
        copyPrelitVertexColor(tri, index, 1);
 
922
        index = triangles[tri][VERTEX3];
 
923
        copyPrelitVertexColor(tri, index, 2);
 
924
      }
 
925
    }
 
926
  }
 
927
 
 
928
 
 
929
  protected void endShapeCameraToScreen(int start, int stop) {
 
930
    for (int i = start; i < stop; i++) {
 
931
      float vx[] = vertices[i];
 
932
 
 
933
      float ox =
 
934
        projection.m00*vx[VX] + projection.m01*vx[VY] +
 
935
        projection.m02*vx[VZ] + projection.m03*vx[VW];
 
936
      float oy =
 
937
        projection.m10*vx[VX] + projection.m11*vx[VY] +
 
938
        projection.m12*vx[VZ] + projection.m13*vx[VW];
 
939
      float oz =
 
940
        projection.m20*vx[VX] + projection.m21*vx[VY] +
 
941
        projection.m22*vx[VZ] + projection.m23*vx[VW];
 
942
      float ow =
 
943
        projection.m30*vx[VX] + projection.m31*vx[VY] +
 
944
        projection.m32*vx[VZ] + projection.m33*vx[VW];
 
945
 
 
946
      if (ow != 0 && ow != 1) {
 
947
        ox /= ow; oy /= ow; oz /= ow;
 
948
      }
 
949
 
 
950
      vx[TX] = width * (1 + ox) / 2.0f;
 
951
      vx[TY] = height * (1 + oy) / 2.0f;
 
952
      vx[TZ] = (oz + 1) / 2.0f;
 
953
    }
 
954
  }
 
955
 
 
956
 
 
957
 
 
958
  /////////////////////////////////////////////////////////////////////////////
 
959
 
 
960
  // POINTS
 
961
 
 
962
 
 
963
  protected void addPoint(int a) {
 
964
    if (pointCount == points.length) {
 
965
      int[][] temp = new int[pointCount << 1][LINE_FIELD_COUNT];
 
966
      System.arraycopy(points, 0, temp, 0, lineCount);
 
967
      points = temp;
 
968
    }
 
969
    points[pointCount][VERTEX1] = a;
 
970
    //points[pointCount][STROKE_MODE] = strokeCap | strokeJoin;
 
971
    points[pointCount][STROKE_COLOR] = strokeColor;
 
972
    //points[pointCount][STROKE_WEIGHT] = (int) (strokeWeight + 0.5f); // hmm
 
973
    pointCount++;
 
974
  }
 
975
 
 
976
 
 
977
  protected void renderPoints(int start, int stop) {
 
978
    if (strokeWeight != 1) {
 
979
      for (int i = start; i < stop; i++) {
 
980
        float[] a = vertices[points[i][VERTEX1]];
 
981
        renderLineVertices(a, a);
 
982
      }
 
983
    } else {
 
984
      for (int i = start; i < stop; i++) {
 
985
        float[] a = vertices[points[i][VERTEX1]];
 
986
        int sx = (int) (a[TX] + 0.4999f);
 
987
        int sy = (int) (a[TY] + 0.4999f);
 
988
        if (sx >= 0 && sx < width && sy >= 0 && sy < height) {
 
989
          int index = sy*width + sx;
 
990
          pixels[index] = points[i][STROKE_COLOR];
 
991
          zbuffer[index] = a[TZ];
 
992
        }
 
993
      }
 
994
    }
 
995
  }
 
996
 
 
997
 
 
998
  // alternative implementations of point rendering code...
 
999
 
 
1000
  /*
 
1001
      int sx = (int) (screenX(x, y, z) + 0.5f);
 
1002
      int sy = (int) (screenY(x, y, z) + 0.5f);
 
1003
 
 
1004
      int index = sy*width + sx;
 
1005
      pixels[index] = strokeColor;
 
1006
      zbuffer[index] = screenZ(x, y, z);
 
1007
 
 
1008
   */
 
1009
 
 
1010
  /*
 
1011
  protected void renderPoints(int start, int stop) {
 
1012
    for (int i = start; i < stop; i++) {
 
1013
      float a[] = vertices[points[i][VERTEX1]];
 
1014
 
 
1015
      line.reset();
 
1016
 
 
1017
      line.setIntensities(a[SR], a[SG], a[SB], a[SA],
 
1018
                          a[SR], a[SG], a[SB], a[SA]);
 
1019
 
 
1020
      line.setVertices(a[TX], a[TY], a[TZ],
 
1021
                       a[TX] + 0.5f, a[TY] + 0.5f, a[TZ] + 0.5f);
 
1022
 
 
1023
      line.draw();
 
1024
    }
 
1025
  }
 
1026
  */
 
1027
 
 
1028
  /*
 
1029
  // handle points with an actual stroke weight (or scaled by renderer)
 
1030
  private void point3(float x, float y, float z, int color) {
 
1031
    // need to get scaled version of the stroke
 
1032
    float x1 = screenX(x - 0.5f, y - 0.5f, z);
 
1033
    float y1 = screenY(x - 0.5f, y - 0.5f, z);
 
1034
    float x2 = screenX(x + 0.5f, y + 0.5f, z);
 
1035
    float y2 = screenY(x + 0.5f, y + 0.5f, z);
 
1036
 
 
1037
    float weight = (abs(x2 - x1) + abs(y2 - y1)) / 2f;
 
1038
    if (weight < 1.5f) {
 
1039
      int xx = (int) ((x1 + x2) / 2f);
 
1040
      int yy = (int) ((y1 + y2) / 2f);
 
1041
      //point0(xx, yy, z, color);
 
1042
      zbuffer[yy*width + xx] = screenZ(x, y, z);
 
1043
      //stencil?
 
1044
 
 
1045
    } else {
 
1046
      // actually has some weight, need to draw shapes instead
 
1047
      // these will be
 
1048
    }
 
1049
  }
 
1050
  */
 
1051
 
 
1052
 
 
1053
  protected void rawPoints(int start, int stop) {
 
1054
    raw.colorMode(RGB, 1);
 
1055
    raw.noFill();
 
1056
    raw.strokeWeight(vertices[lines[start][VERTEX1]][SW]);
 
1057
    raw.beginShape(POINTS);
 
1058
 
 
1059
    for (int i = start; i < stop; i++) {
 
1060
      float a[] = vertices[lines[i][VERTEX1]];
 
1061
 
 
1062
      if (raw.is3D()) {
 
1063
        if (a[VW] != 0) {
 
1064
          raw.stroke(a[SR], a[SG], a[SB], a[SA]);
 
1065
          raw.vertex(a[VX] / a[VW], a[VY] / a[VW], a[VZ] / a[VW]);
 
1066
        }
 
1067
      } else {  // if is2D()
 
1068
        raw.stroke(a[SR], a[SG], a[SB], a[SA]);
 
1069
        raw.vertex(a[TX], a[TY]);
 
1070
      }
 
1071
    }
 
1072
    raw.endShape();
 
1073
  }
 
1074
 
 
1075
 
 
1076
 
 
1077
  /////////////////////////////////////////////////////////////////////////////
 
1078
 
 
1079
  // LINES
 
1080
 
 
1081
 
 
1082
  /**
 
1083
   * Begin a new section of stroked geometry.
 
1084
   */
 
1085
  protected final void addLineBreak() {
 
1086
    if (pathCount == pathOffset.length) {
 
1087
      pathOffset = PApplet.expand(pathOffset);
 
1088
      pathLength = PApplet.expand(pathLength);
 
1089
    }
 
1090
    pathOffset[pathCount] = lineCount;
 
1091
    pathLength[pathCount] = 0;
 
1092
    pathCount++;
 
1093
  }
 
1094
 
 
1095
 
 
1096
  protected void addLine(int a, int b) {
 
1097
    addLineWithClip(a, b);
 
1098
  }
 
1099
 
 
1100
 
 
1101
  protected final void addLineWithClip(int a, int b) {
 
1102
    float az = vertices[a][VZ];
 
1103
    float bz = vertices[b][VZ];
 
1104
    if (az > cameraNear) {
 
1105
      if (bz > cameraNear) {
 
1106
        return;
 
1107
      }
 
1108
      int cb = interpolateClipVertex(a, b);
 
1109
      addLineWithoutClip(cb, b);
 
1110
      return;
 
1111
    }
 
1112
    else {
 
1113
      if (bz <= cameraNear) {
 
1114
        addLineWithoutClip(a, b);
 
1115
        return;
 
1116
      }
 
1117
      int cb = interpolateClipVertex(a, b);
 
1118
      addLineWithoutClip(a, cb);
 
1119
      return;
 
1120
    }
 
1121
  }
 
1122
 
 
1123
 
 
1124
  protected final void addLineWithoutClip(int a, int b) {
 
1125
    if (lineCount == lines.length) {
 
1126
      int temp[][] = new int[lineCount<<1][LINE_FIELD_COUNT];
 
1127
      System.arraycopy(lines, 0, temp, 0, lineCount);
 
1128
      lines = temp;
 
1129
    }
 
1130
    lines[lineCount][VERTEX1] = a;
 
1131
    lines[lineCount][VERTEX2] = b;
 
1132
 
 
1133
    //lines[lineCount][STROKE_MODE] = strokeCap | strokeJoin;
 
1134
    //lines[lineCount][STROKE_WEIGHT] = (int) (strokeWeight + 0.5f); // hmm
 
1135
    lineCount++;
 
1136
 
 
1137
    // mark this piece as being part of the current path
 
1138
    pathLength[pathCount-1]++;
 
1139
  }
 
1140
 
 
1141
 
 
1142
  protected void renderLines(int start, int stop) {
 
1143
    for (int i = start; i < stop; i++) {
 
1144
      renderLineVertices(vertices[lines[i][VERTEX1]],
 
1145
                         vertices[lines[i][VERTEX2]]);
 
1146
    }
 
1147
  }
 
1148
 
 
1149
 
 
1150
  protected void renderLineVertices(float[] a, float[] b) {
 
1151
    // 2D hack added by ewjordan 6/13/07
 
1152
    // Offset coordinates by a little bit if drawing 2D graphics.
 
1153
    // http://dev.processing.org/bugs/show_bug.cgi?id=95
 
1154
 
 
1155
    // This hack fixes a bug caused by numerical precision issues when
 
1156
    // applying the 3D transformations to coordinates in the screen plane
 
1157
    // that should actually not be altered under said transformations.
 
1158
    // It will not be applied if any transformations other than translations
 
1159
    // are active, nor should it apply in OpenGL mode (PGraphicsOpenGL
 
1160
    // overrides render_lines(), so this should be fine).
 
1161
    // This fix exposes a last-pixel bug in the lineClipCode() function
 
1162
    // of PLine.java, so that fix must remain in place if this one is used.
 
1163
 
 
1164
    // Note: the "true" fix for this bug is to change the pixel coverage
 
1165
    // model so that the threshold for display does not lie on an integer
 
1166
    // boundary. Search "diamond exit rule" for info the OpenGL approach.
 
1167
 
 
1168
    /*
 
1169
      // removing for 0149 with the return of P2D
 
1170
      if (drawing2D() && a[Z] == 0) {
 
1171
        a[TX] += 0.01;
 
1172
        a[TY] += 0.01;
 
1173
        a[VX] += 0.01*a[VW];
 
1174
        a[VY] += 0.01*a[VW];
 
1175
        b[TX] += 0.01;
 
1176
        b[TY] += 0.01;
 
1177
        b[VX] += 0.01*b[VW];
 
1178
        b[VY] += 0.01*b[VW];
 
1179
      }
 
1180
     */
 
1181
    // end 2d-hack
 
1182
 
 
1183
    if (a[SW] > 1.25f || a[SW] < 0.75f) {
 
1184
      float ox1 = a[TX];
 
1185
      float oy1 = a[TY];
 
1186
      float ox2 = b[TX];
 
1187
      float oy2 = b[TY];
 
1188
 
 
1189
      // TODO strokeWeight should be transformed!
 
1190
      float weight = a[SW] / 2;
 
1191
 
 
1192
      // when drawing points with stroke weight, need to extend a bit
 
1193
      if (ox1 == ox2 && oy1 == oy2) {
 
1194
        oy1 -= weight;
 
1195
        oy2 += weight;
 
1196
      }
 
1197
 
 
1198
      float dX = ox2 - ox1 + EPSILON;
 
1199
      float dY = oy2 - oy1 + EPSILON;
 
1200
      float len = (float) Math.sqrt(dX*dX + dY*dY);
 
1201
 
 
1202
      float rh = weight / len;
 
1203
 
 
1204
      float dx0 = rh * dY;
 
1205
      float dy0 = rh * dX;
 
1206
      float dx1 = rh * dY;
 
1207
      float dy1 = rh * dX;
 
1208
 
 
1209
      float ax1 = ox1+dx0;
 
1210
      float ay1 = oy1-dy0;
 
1211
 
 
1212
      float ax2 = ox1-dx0;
 
1213
      float ay2 = oy1+dy0;
 
1214
 
 
1215
      float bx1 = ox2+dx1;
 
1216
      float by1 = oy2-dy1;
 
1217
 
 
1218
      float bx2 = ox2-dx1;
 
1219
      float by2 = oy2+dy1;
 
1220
 
 
1221
      if (smooth) {
 
1222
        smoothTriangle.reset(3);
 
1223
        smoothTriangle.smooth = true;
 
1224
        smoothTriangle.interpARGB = true;  // ?
 
1225
 
 
1226
        // render first triangle for thick line
 
1227
        smoothTriangle.setVertices(ax1, ay1, a[TZ],
 
1228
                                   bx2, by2, b[TZ],
 
1229
                                   ax2, ay2, a[TZ]);
 
1230
        smoothTriangle.setIntensities(a[SR], a[SG], a[SB], a[SA],
 
1231
                                      b[SR], b[SG], b[SB], b[SA],
 
1232
                                      a[SR], a[SG], a[SB], a[SA]);
 
1233
        smoothTriangle.render();
 
1234
 
 
1235
        // render second triangle for thick line
 
1236
        smoothTriangle.setVertices(ax1, ay1, a[TZ],
 
1237
                                   bx2, by2, b[TZ],
 
1238
                                   bx1, by1, b[TZ]);
 
1239
        smoothTriangle.setIntensities(a[SR], a[SG], a[SB], a[SA],
 
1240
                                      b[SR], b[SG], b[SB], b[SA],
 
1241
                                      b[SR], b[SG], b[SB], b[SA]);
 
1242
        smoothTriangle.render();
 
1243
 
 
1244
      } else {
 
1245
        triangle.reset();
 
1246
 
 
1247
        // render first triangle for thick line
 
1248
        triangle.setVertices(ax1, ay1, a[TZ],
 
1249
                             bx2, by2, b[TZ],
 
1250
                             ax2, ay2, a[TZ]);
 
1251
        triangle.setIntensities(a[SR], a[SG], a[SB], a[SA],
 
1252
                                b[SR], b[SG], b[SB], b[SA],
 
1253
                                a[SR], a[SG], a[SB], a[SA]);
 
1254
        triangle.render();
 
1255
 
 
1256
        // render second triangle for thick line
 
1257
        triangle.setVertices(ax1, ay1, a[TZ],
 
1258
                             bx2, by2, b[TZ],
 
1259
                             bx1, by1, b[TZ]);
 
1260
        triangle.setIntensities(a[SR], a[SG], a[SB], a[SA],
 
1261
                                b[SR], b[SG], b[SB], b[SA],
 
1262
                                b[SR], b[SG], b[SB], b[SA]);
 
1263
        triangle.render();
 
1264
      }
 
1265
 
 
1266
    } else {
 
1267
      line.reset();
 
1268
 
 
1269
      line.setIntensities(a[SR], a[SG], a[SB], a[SA],
 
1270
                          b[SR], b[SG], b[SB], b[SA]);
 
1271
 
 
1272
      line.setVertices(a[TX], a[TY], a[TZ],
 
1273
                       b[TX], b[TY], b[TZ]);
 
1274
 
 
1275
        /*
 
1276
        // Seems okay to remove this because these vertices are not used again,
 
1277
        // but if problems arise, this needs to be uncommented because the above
 
1278
        // change is destructive and may need to be undone before proceeding.
 
1279
        if (drawing2D() && a[MZ] == 0) {
 
1280
          a[X] -= 0.01;
 
1281
          a[Y] -= 0.01;
 
1282
          a[VX] -= 0.01*a[VW];
 
1283
          a[VY] -= 0.01*a[VW];
 
1284
          b[X] -= 0.01;
 
1285
          b[Y] -= 0.01;
 
1286
          b[VX] -= 0.01*b[VW];
 
1287
          b[VY] -= 0.01*b[VW];
 
1288
        }
 
1289
        */
 
1290
 
 
1291
      line.draw();
 
1292
    }
 
1293
  }
 
1294
 
 
1295
 
 
1296
  /**
 
1297
   * Handle echoing line data to a raw shape recording renderer. This has been
 
1298
   * broken out of the renderLines() procedure so that renderLines() can be
 
1299
   * optimized per-renderer without having to deal with this code. This code,
 
1300
   * for instance, will stay the same when OpenGL is in use, but renderLines()
 
1301
   * can be optimized significantly.
 
1302
   * <br/> <br/>
 
1303
   * Values for start and stop are specified, so that in the future, sorted
 
1304
   * rendering can be implemented, which will require sequences of lines,
 
1305
   * triangles, or points to be rendered in the neighborhood of one another.
 
1306
   * That is, if we're gonna depth sort, we can't just draw all the triangles
 
1307
   * and then draw all the lines, cuz that defeats the purpose.
 
1308
   */
 
1309
  protected void rawLines(int start, int stop) {
 
1310
    raw.colorMode(RGB, 1);
 
1311
    raw.noFill();
 
1312
    raw.beginShape(LINES);
 
1313
 
 
1314
    for (int i = start; i < stop; i++) {
 
1315
      float a[] = vertices[lines[i][VERTEX1]];
 
1316
      float b[] = vertices[lines[i][VERTEX2]];
 
1317
      raw.strokeWeight(vertices[lines[i][VERTEX2]][SW]);
 
1318
 
 
1319
      if (raw.is3D()) {
 
1320
        if ((a[VW] != 0) && (b[VW] != 0)) {
 
1321
          raw.stroke(a[SR], a[SG], a[SB], a[SA]);
 
1322
          raw.vertex(a[VX] / a[VW], a[VY] / a[VW], a[VZ] / a[VW]);
 
1323
          raw.stroke(b[SR], b[SG], b[SB], b[SA]);
 
1324
          raw.vertex(b[VX] / b[VW], b[VY] / b[VW], b[VZ] / b[VW]);
 
1325
        }
 
1326
      } else if (raw.is2D()) {
 
1327
        raw.stroke(a[SR], a[SG], a[SB], a[SA]);
 
1328
        raw.vertex(a[TX], a[TY]);
 
1329
        raw.stroke(b[SR], b[SG], b[SB], b[SA]);
 
1330
        raw.vertex(b[TX], b[TY]);
 
1331
      }
 
1332
    }
 
1333
    raw.endShape();
 
1334
  }
 
1335
 
 
1336
 
 
1337
 
 
1338
  /////////////////////////////////////////////////////////////////////////////
 
1339
 
 
1340
  // TRIANGLES
 
1341
 
 
1342
 
 
1343
  protected void addTriangle(int a, int b, int c) {
 
1344
    addTriangleWithClip(a, b, c);
 
1345
  }
 
1346
 
 
1347
 
 
1348
  protected final void addTriangleWithClip(int a, int b, int c) {
 
1349
    boolean aClipped = false;
 
1350
    boolean bClipped = false;
 
1351
    int clippedCount = 0;
 
1352
 
 
1353
//    cameraNear = -8;
 
1354
    if (vertices[a][VZ] > cameraNear) {
 
1355
      aClipped = true;
 
1356
      clippedCount++;
 
1357
    }
 
1358
    if (vertices[b][VZ] > cameraNear) {
 
1359
      bClipped = true;
 
1360
      clippedCount++;
 
1361
    }
 
1362
    if (vertices[c][VZ] > cameraNear) {
 
1363
      //cClipped = true;
 
1364
      clippedCount++;
 
1365
    }
 
1366
    if (clippedCount == 0) {
 
1367
//        if (vertices[a][VZ] < cameraFar && 
 
1368
//                vertices[b][VZ] < cameraFar && 
 
1369
//                vertices[c][VZ] < cameraFar) {
 
1370
      addTriangleWithoutClip(a, b, c);
 
1371
//        }
 
1372
 
 
1373
//    } else if (true) {
 
1374
//        return;
 
1375
        
 
1376
    } else if (clippedCount == 3) {
 
1377
      // In this case there is only one visible point.            |/|
 
1378
      // So we'll have to make two new points on the clip line   <| |
 
1379
      // and add that triangle instead.                           |\|
 
1380
 
 
1381
    } else if (clippedCount == 2) {
 
1382
      //System.out.println("Clipped two");
 
1383
 
 
1384
      int ca, cb, cc, cd, ce;
 
1385
      if (!aClipped) {
 
1386
        ca = a;
 
1387
        cb = b;
 
1388
        cc = c;
 
1389
      }
 
1390
      else if (!bClipped) {
 
1391
        ca = b;
 
1392
        cb = a;
 
1393
        cc = c;
 
1394
      }
 
1395
      else { //if (!cClipped) {
 
1396
        ca = c;
 
1397
        cb = b;
 
1398
        cc = a;
 
1399
      }
 
1400
 
 
1401
      cd = interpolateClipVertex(ca, cb);
 
1402
      ce = interpolateClipVertex(ca, cc);
 
1403
      addTriangleWithoutClip(ca, cd, ce);
 
1404
 
 
1405
    } else { // (clippedCount == 1) {
 
1406
      //                                                          . |
 
1407
      // In this case there are two visible points.               |\|
 
1408
      // So we'll have to make two new points on the clip line    | |>
 
1409
      // and then add two new triangles.                          |/|
 
1410
      //                                                          . |
 
1411
      //System.out.println("Clipped one");
 
1412
      int ca, cb, cc, cd, ce;
 
1413
      if (aClipped) {
 
1414
        //System.out.println("aClipped");
 
1415
        ca = c;
 
1416
        cb = b;
 
1417
        cc = a;
 
1418
      }
 
1419
      else if (bClipped) {
 
1420
        //System.out.println("bClipped");
 
1421
        ca = a;
 
1422
        cb = c;
 
1423
        cc = b;
 
1424
      }
 
1425
      else { //if (cClipped) {
 
1426
        //System.out.println("cClipped");
 
1427
        ca = a;
 
1428
        cb = b;
 
1429
        cc = c;
 
1430
      }
 
1431
 
 
1432
      cd = interpolateClipVertex(ca, cc);
 
1433
      ce = interpolateClipVertex(cb, cc);
 
1434
      addTriangleWithoutClip(ca, cd, cb);
 
1435
      //System.out.println("ca: " + ca + ", " + vertices[ca][VX] + ", " + vertices[ca][VY] + ", " + vertices[ca][VZ]);
 
1436
      //System.out.println("cd: " + cd + ", " + vertices[cd][VX] + ", " + vertices[cd][VY] + ", " + vertices[cd][VZ]);
 
1437
      //System.out.println("cb: " + cb + ", " + vertices[cb][VX] + ", " + vertices[cb][VY] + ", " + vertices[cb][VZ]);
 
1438
      addTriangleWithoutClip(cb, cd, ce);
 
1439
    }
 
1440
  }
 
1441
 
 
1442
 
 
1443
  protected final int interpolateClipVertex(int a, int b) {
 
1444
    float[] va;
 
1445
    float[] vb;
 
1446
    // Set up va, vb such that va[VZ] >= vb[VZ]
 
1447
    if (vertices[a][VZ] < vertices[b][VZ]) {
 
1448
      va = vertices[b];
 
1449
      vb = vertices[a];
 
1450
    }
 
1451
    else {
 
1452
      va = vertices[a];
 
1453
      vb = vertices[b];
 
1454
    }
 
1455
    float az = va[VZ];
 
1456
    float bz = vb[VZ];
 
1457
 
 
1458
    float dz = az - bz;
 
1459
    // If they have the same z, just use pt. a.
 
1460
    if (dz == 0) {
 
1461
      return a;
 
1462
    }
 
1463
    //float pa = (az - cameraNear) / dz;
 
1464
    //float pb = (cameraNear - bz) / dz;
 
1465
    float pa = (cameraNear - bz) / dz;
 
1466
    float pb = 1 - pa;
 
1467
 
 
1468
    vertex(pa * va[X] + pb * vb[X],
 
1469
           pa * va[Y] + pb * vb[Y],
 
1470
           pa * va[Z] + pb * vb[Z]);
 
1471
    int irv = vertexCount - 1;
 
1472
    shapeLastPlusClipped++;
 
1473
 
 
1474
    float[] rv = vertices[irv];
 
1475
 
 
1476
    rv[TX] = pa * va[TX] + pb * vb[TX];
 
1477
    rv[TY] = pa * va[TY] + pb * vb[TY];
 
1478
    rv[TZ] = pa * va[TZ] + pb * vb[TZ];
 
1479
 
 
1480
    rv[VX] = pa * va[VX] + pb * vb[VX];
 
1481
    rv[VY] = pa * va[VY] + pb * vb[VY];
 
1482
    rv[VZ] = pa * va[VZ] + pb * vb[VZ];
 
1483
    rv[VW] = pa * va[VW] + pb * vb[VW];
 
1484
 
 
1485
    rv[R] = pa * va[R] + pb * vb[R];
 
1486
    rv[G] = pa * va[G] + pb * vb[G];
 
1487
    rv[B] = pa * va[B] + pb * vb[B];
 
1488
    rv[A] = pa * va[A] + pb * vb[A];
 
1489
 
 
1490
    rv[U] = pa * va[U] + pb * vb[U];
 
1491
    rv[V] = pa * va[V] + pb * vb[V];
 
1492
 
 
1493
    rv[SR] = pa * va[SR] + pb * vb[SR];
 
1494
    rv[SG] = pa * va[SG] + pb * vb[SG];
 
1495
    rv[SB] = pa * va[SB] + pb * vb[SB];
 
1496
    rv[SA] = pa * va[SA] + pb * vb[SA];
 
1497
 
 
1498
    rv[NX] = pa * va[NX] + pb * vb[NX];
 
1499
    rv[NY] = pa * va[NY] + pb * vb[NY];
 
1500
    rv[NZ] = pa * va[NZ] + pb * vb[NZ];
 
1501
 
 
1502
//    rv[SW] = pa * va[SW] + pb * vb[SW];
 
1503
 
 
1504
    rv[AR] = pa * va[AR] + pb * vb[AR];
 
1505
    rv[AG] = pa * va[AG] + pb * vb[AG];
 
1506
    rv[AB] = pa * va[AB] + pb * vb[AB];
 
1507
 
 
1508
    rv[SPR] = pa * va[SPR] + pb * vb[SPR];
 
1509
    rv[SPG] = pa * va[SPG] + pb * vb[SPG];
 
1510
    rv[SPB] = pa * va[SPB] + pb * vb[SPB];
 
1511
    //rv[SPA] = pa * va[SPA] + pb * vb[SPA];
 
1512
 
 
1513
    rv[ER] = pa * va[ER] + pb * vb[ER];
 
1514
    rv[EG] = pa * va[EG] + pb * vb[EG];
 
1515
    rv[EB] = pa * va[EB] + pb * vb[EB];
 
1516
 
 
1517
    rv[SHINE] = pa * va[SHINE] + pb * vb[SHINE];
 
1518
 
 
1519
    rv[BEEN_LIT] = 0;
 
1520
 
 
1521
    return irv;
 
1522
  }
 
1523
 
 
1524
 
 
1525
  protected final void addTriangleWithoutClip(int a, int b, int c) {
 
1526
    if (triangleCount == triangles.length) {
 
1527
      int temp[][] = new int[triangleCount<<1][TRIANGLE_FIELD_COUNT];
 
1528
      System.arraycopy(triangles, 0, temp, 0, triangleCount);
 
1529
      triangles = temp;
 
1530
      //message(CHATTER, "allocating more triangles " + triangles.length);
 
1531
      float ftemp[][][] = new float[triangleCount<<1][3][TRI_COLOR_COUNT];
 
1532
      System.arraycopy(triangleColors, 0, ftemp, 0, triangleCount);
 
1533
      triangleColors = ftemp;
 
1534
    }
 
1535
    triangles[triangleCount][VERTEX1] = a;
 
1536
    triangles[triangleCount][VERTEX2] = b;
 
1537
    triangles[triangleCount][VERTEX3] = c;
 
1538
 
 
1539
    if (textureImage == null) {
 
1540
      triangles[triangleCount][TEXTURE_INDEX] = -1;
 
1541
    } else {
 
1542
      triangles[triangleCount][TEXTURE_INDEX] = textureIndex;
 
1543
    }
 
1544
 
 
1545
//    triangles[triangleCount][INDEX] = shape_index;
 
1546
    triangleCount++;
 
1547
  }
 
1548
 
 
1549
 
 
1550
  /**
 
1551
   * Triangulate the current polygon.
 
1552
   * <BR> <BR>
 
1553
   * Simple ear clipping polygon triangulation adapted from code by
 
1554
   * John W. Ratcliff (jratcliff at verant.com). Presumably
 
1555
   * <A HREF="http://www.flipcode.org/cgi-bin/fcarticles.cgi?show=63943">this</A>
 
1556
   * bit of code from the web.
 
1557
   */
 
1558
  protected void addPolygonTriangles() {
 
1559
    if (vertexOrder.length != vertices.length) {
 
1560
      int[] temp = new int[vertices.length];
 
1561
      // vertex_start may not be zero, might need to keep old stuff around
 
1562
      // also, copy vertexOrder.length, not vertexCount because vertexCount
 
1563
      // may be larger than vertexOrder.length (since this is a post-processing
 
1564
      // step that happens after the vertex arrays are built).
 
1565
      PApplet.arrayCopy(vertexOrder, temp, vertexOrder.length);
 
1566
      vertexOrder = temp;
 
1567
    }
 
1568
 
 
1569
    // this clipping algorithm only works in 2D, so in cases where a
 
1570
    // polygon is drawn perpendicular to the z-axis, the area will be zero,
 
1571
    // and triangulation will fail. as such, when the area calculates to
 
1572
    // zero, figure out whether x or y is empty, and calculate based on the
 
1573
    // two dimensions that actually contain information.
 
1574
    // http://dev.processing.org/bugs/show_bug.cgi?id=111
 
1575
    int d1 = X;
 
1576
    int d2 = Y;
 
1577
    // this brings up the nastier point that there may be cases where
 
1578
    // a polygon is irregular in space and will throw off the
 
1579
    // clockwise/counterclockwise calculation. for instance, if clockwise
 
1580
    // relative to x and z, but counter relative to y and z or something
 
1581
    // like that.. will wait to see if this is in fact a problem before
 
1582
    // hurting my head on the math.
 
1583
 
 
1584
    /*
 
1585
    // trying to track down bug #774
 
1586
    for (int i = vertex_start; i < vertex_end; i++) {
 
1587
      if (i > vertex_start) {
 
1588
        if (vertices[i-1][MX] == vertices[i][MX] &&
 
1589
            vertices[i-1][MY] == vertices[i][MY]) {
 
1590
          System.out.print("**** " );
 
1591
        }
 
1592
      }
 
1593
      System.out.println(i + " " + vertices[i][MX] + " " + vertices[i][MY]);
 
1594
    }
 
1595
    System.out.println();
 
1596
    */
 
1597
 
 
1598
    // first we check if the polygon goes clockwise or counterclockwise
 
1599
    float area = 0;
 
1600
    for (int p = shapeLast - 1, q = shapeFirst; q < shapeLast; p = q++) {
 
1601
      area += (vertices[q][d1] * vertices[p][d2] -
 
1602
               vertices[p][d1] * vertices[q][d2]);
 
1603
    }
 
1604
    // rather than checking for the perpendicular case first, only do it
 
1605
    // when the area calculates to zero. checking for perpendicular would be
 
1606
    // a needless waste of time for the 99% case.
 
1607
    if (area == 0) {
 
1608
      // figure out which dimension is the perpendicular axis
 
1609
      boolean foundValidX = false;
 
1610
      boolean foundValidY = false;
 
1611
 
 
1612
      for (int i = shapeFirst; i < shapeLast; i++) {
 
1613
        for (int j = i; j < shapeLast; j++){
 
1614
          if ( vertices[i][X] != vertices[j][X] ) foundValidX = true;
 
1615
          if ( vertices[i][Y] != vertices[j][Y] ) foundValidY = true;
 
1616
        }
 
1617
      }
 
1618
 
 
1619
      if (foundValidX) {
 
1620
        //d1 = MX;  // already the case
 
1621
        d2 = Z;
 
1622
      } else if (foundValidY) {
 
1623
        // ermm.. which is the proper order for cw/ccw here?
 
1624
        d1 = Y;
 
1625
        d2 = Z;
 
1626
      } else {
 
1627
        // screw it, this polygon is just f-ed up
 
1628
        return;
 
1629
      }
 
1630
 
 
1631
      // re-calculate the area, with what should be good values
 
1632
      for (int p = shapeLast - 1, q = shapeFirst; q < shapeLast; p = q++) {
 
1633
        area += (vertices[q][d1] * vertices[p][d2] -
 
1634
                 vertices[p][d1] * vertices[q][d2]);
 
1635
      }
 
1636
    }
 
1637
 
 
1638
    // don't allow polygons to come back and meet themselves,
 
1639
    // otherwise it will anger the triangulator
 
1640
    // http://dev.processing.org/bugs/show_bug.cgi?id=97
 
1641
    float vfirst[] = vertices[shapeFirst];
 
1642
    float vlast[] = vertices[shapeLast-1];
 
1643
    if ((abs(vfirst[X] - vlast[X]) < EPSILON) &&
 
1644
        (abs(vfirst[Y] - vlast[Y]) < EPSILON) &&
 
1645
        (abs(vfirst[Z] - vlast[Z]) < EPSILON)) {
 
1646
      shapeLast--;
 
1647
    }
 
1648
 
 
1649
    // then sort the vertices so they are always in a counterclockwise order
 
1650
    int j = 0;
 
1651
    if (area > 0) {
 
1652
      for (int i = shapeFirst; i < shapeLast; i++) {
 
1653
        j = i - shapeFirst;
 
1654
        vertexOrder[j] = i;
 
1655
      }
 
1656
    } else {
 
1657
      for (int i = shapeFirst; i < shapeLast; i++) {
 
1658
        j = i - shapeFirst;
 
1659
        vertexOrder[j] = (shapeLast - 1) - j;
 
1660
      }
 
1661
    }
 
1662
 
 
1663
    // remove vc-2 Vertices, creating 1 triangle every time
 
1664
    int vc = shapeLast - shapeFirst;
 
1665
    int count = 2*vc;  // complex polygon detection
 
1666
 
 
1667
    for (int m = 0, v = vc - 1; vc > 2; ) {
 
1668
      boolean snip = true;
 
1669
 
 
1670
      // if we start over again, is a complex polygon
 
1671
      if (0 >= (count--)) {
 
1672
        break; // triangulation failed
 
1673
      }
 
1674
 
 
1675
      // get 3 consecutive vertices <u,v,w>
 
1676
      int u = v ; if (vc <= u) u = 0;    // previous
 
1677
      v = u + 1; if (vc <= v) v = 0;     // current
 
1678
      int w = v + 1; if (vc <= w) w = 0; // next
 
1679
 
 
1680
      // Upgrade values to doubles, and multiply by 10 so that we can have
 
1681
      // some better accuracy as we tessellate. This seems to have negligible
 
1682
      // speed differences on Windows and Intel Macs, but causes a 50% speed
 
1683
      // drop for PPC Macs with the bug's example code that draws ~200 points
 
1684
      // in a concave polygon. Apple has abandoned PPC so we may as well too.
 
1685
      // http://dev.processing.org/bugs/show_bug.cgi?id=774
 
1686
 
 
1687
      // triangle A B C
 
1688
      double Ax = -10 * vertices[vertexOrder[u]][d1];
 
1689
      double Ay =  10 * vertices[vertexOrder[u]][d2];
 
1690
      double Bx = -10 * vertices[vertexOrder[v]][d1];
 
1691
      double By =  10 * vertices[vertexOrder[v]][d2];
 
1692
      double Cx = -10 * vertices[vertexOrder[w]][d1];
 
1693
      double Cy =  10 * vertices[vertexOrder[w]][d2];
 
1694
 
 
1695
      // first we check if <u,v,w> continues going ccw
 
1696
      if (EPSILON > (((Bx-Ax) * (Cy-Ay)) - ((By-Ay) * (Cx-Ax)))) {
 
1697
        continue;
 
1698
      }
 
1699
 
 
1700
      for (int p = 0; p < vc; p++) {
 
1701
        if ((p == u) || (p == v) || (p == w)) {
 
1702
          continue;
 
1703
        }
 
1704
 
 
1705
        double Px = -10 * vertices[vertexOrder[p]][d1];
 
1706
        double Py =  10 * vertices[vertexOrder[p]][d2];
 
1707
 
 
1708
        double ax  = Cx - Bx;  double ay  = Cy - By;
 
1709
        double bx  = Ax - Cx;  double by  = Ay - Cy;
 
1710
        double cx  = Bx - Ax;  double cy  = By - Ay;
 
1711
        double apx = Px - Ax;  double apy = Py - Ay;
 
1712
        double bpx = Px - Bx;  double bpy = Py - By;
 
1713
        double cpx = Px - Cx;  double cpy = Py - Cy;
 
1714
 
 
1715
        double aCROSSbp = ax * bpy - ay * bpx;
 
1716
        double cCROSSap = cx * apy - cy * apx;
 
1717
        double bCROSScp = bx * cpy - by * cpx;
 
1718
 
 
1719
        if ((aCROSSbp >= 0.0) && (bCROSScp >= 0.0) && (cCROSSap >= 0.0)) {
 
1720
          snip = false;
 
1721
        }
 
1722
      }
 
1723
 
 
1724
      if (snip) {
 
1725
        addTriangle(vertexOrder[u], vertexOrder[v], vertexOrder[w]);
 
1726
 
 
1727
        m++;
 
1728
 
 
1729
        // remove v from remaining polygon
 
1730
        for (int s = v, t = v + 1; t < vc; s++, t++) {
 
1731
          vertexOrder[s] = vertexOrder[t];
 
1732
        }
 
1733
        vc--;
 
1734
 
 
1735
        // reset error detection counter
 
1736
        count = 2 * vc;
 
1737
      }
 
1738
    }
 
1739
  }
 
1740
 
 
1741
 
 
1742
  private void toWorldNormal(float nx, float ny, float nz, float[] out) {
 
1743
    out[0] =
 
1744
      modelviewInv.m00*nx + modelviewInv.m10*ny +
 
1745
      modelviewInv.m20*nz + modelviewInv.m30;
 
1746
    out[1] =
 
1747
      modelviewInv.m01*nx + modelviewInv.m11*ny +
 
1748
      modelviewInv.m21*nz + modelviewInv.m31;
 
1749
    out[2] =
 
1750
      modelviewInv.m02*nx + modelviewInv.m12*ny +
 
1751
      modelviewInv.m22*nz + modelviewInv.m32;
 
1752
    out[3] =
 
1753
      modelviewInv.m03*nx + modelviewInv.m13*ny +
 
1754
      modelviewInv.m23*nz + modelviewInv.m33;
 
1755
 
 
1756
    if (out[3] != 0 && out[3] != 1) {
 
1757
      // divide by perspective coordinate
 
1758
      out[0] /= out[3]; out[1] /= out[3]; out[2] /= out[3];
 
1759
    }
 
1760
    out[3] = 1;
 
1761
 
 
1762
    float nlen = mag(out[0], out[1], out[2]);  // normalize
 
1763
    if (nlen != 0 && nlen != 1) {
 
1764
      out[0] /= nlen; out[1] /= nlen; out[2] /= nlen;
 
1765
    }
 
1766
  }
 
1767
 
 
1768
 
 
1769
  //private PVector calcLightingNorm = new PVector();
 
1770
  //private PVector calcLightingWorldNorm = new PVector();
 
1771
  float[] worldNormal = new float[4];
 
1772
 
 
1773
 
 
1774
  private void calcLightingContribution(int vIndex,
 
1775
                                        float[] contribution) {
 
1776
    calcLightingContribution(vIndex, contribution, false);
 
1777
  }
 
1778
 
 
1779
 
 
1780
  private void calcLightingContribution(int vIndex,
 
1781
                                        float[] contribution,
 
1782
                                        boolean normalIsWorld) {
 
1783
    float[] v = vertices[vIndex];
 
1784
 
 
1785
    float sr = v[SPR];
 
1786
    float sg = v[SPG];
 
1787
    float sb = v[SPB];
 
1788
 
 
1789
    float wx = v[VX];
 
1790
    float wy = v[VY];
 
1791
    float wz = v[VZ];
 
1792
    float shine = v[SHINE];
 
1793
 
 
1794
    float nx = v[NX];
 
1795
    float ny = v[NY];
 
1796
    float nz = v[NZ];
 
1797
 
 
1798
    if (!normalIsWorld) {
 
1799
//      System.out.println("um, hello?");
 
1800
//      calcLightingNorm.set(nx, ny, nz);
 
1801
//      //modelviewInv.mult(calcLightingNorm, calcLightingWorldNorm);
 
1802
//
 
1803
////      PMatrix3D mvi = modelViewInv;
 
1804
////      float ox = mvi.m00*nx + mvi.m10*ny + mvi*m20+nz +
 
1805
//      modelviewInv.cmult(calcLightingNorm, calcLightingWorldNorm);
 
1806
//
 
1807
//      calcLightingWorldNorm.normalize();
 
1808
//      nx = calcLightingWorldNorm.x;
 
1809
//      ny = calcLightingWorldNorm.y;
 
1810
//      nz = calcLightingWorldNorm.z;
 
1811
 
 
1812
      toWorldNormal(v[NX], v[NY], v[NZ], worldNormal);
 
1813
      nx = worldNormal[X];
 
1814
      ny = worldNormal[Y];
 
1815
      nz = worldNormal[Z];
 
1816
 
 
1817
//      float wnx = modelviewInv.multX(nx, ny, nz);
 
1818
//      float wny = modelviewInv.multY(nx, ny, nz);
 
1819
//      float wnz = modelviewInv.multZ(nx, ny, nz);
 
1820
//      float wnw = modelviewInv.multW(nx, ny, nz);
 
1821
 
 
1822
//      if (wnw != 0 && wnw != 1) {
 
1823
//        wnx /= wnw;
 
1824
//        wny /= wnw;
 
1825
//        wnz /= wnw;
 
1826
//      }
 
1827
//      float nlen = mag(wnx, wny, wnw);
 
1828
//      if (nlen != 0 && nlen != 1) {
 
1829
//        nx = wnx / nlen;
 
1830
//        ny = wny / nlen;
 
1831
//        nz = wnz / nlen;
 
1832
//      } else {
 
1833
//        nx = wnx;
 
1834
//        ny = wny;
 
1835
//        nz = wnz;
 
1836
//      }
 
1837
//      */
 
1838
    } else {
 
1839
      nx = v[NX];
 
1840
      ny = v[NY];
 
1841
      nz = v[NZ];
 
1842
    }
 
1843
 
 
1844
    // Since the camera space == world space,
 
1845
    // we can test for visibility by the dot product of
 
1846
    // the normal with the direction from pt. to eye.
 
1847
    float dir = dot(nx, ny, nz, -wx, -wy, -wz);
 
1848
    // If normal is away from camera, choose its opposite.
 
1849
    // If we add backface culling, this will be backfacing
 
1850
    // (but since this is per vertex, it's more complicated)
 
1851
    if (dir < 0) {
 
1852
      nx = -nx;
 
1853
      ny = -ny;
 
1854
      nz = -nz;
 
1855
    }
 
1856
 
 
1857
    // These two terms will sum the contributions from the various lights
 
1858
    contribution[LIGHT_AMBIENT_R] = 0;
 
1859
    contribution[LIGHT_AMBIENT_G] = 0;
 
1860
    contribution[LIGHT_AMBIENT_B] = 0;
 
1861
 
 
1862
    contribution[LIGHT_DIFFUSE_R] = 0;
 
1863
    contribution[LIGHT_DIFFUSE_G] = 0;
 
1864
    contribution[LIGHT_DIFFUSE_B] = 0;
 
1865
 
 
1866
    contribution[LIGHT_SPECULAR_R] = 0;
 
1867
    contribution[LIGHT_SPECULAR_G] = 0;
 
1868
    contribution[LIGHT_SPECULAR_B] = 0;
 
1869
 
 
1870
    // for (int i = 0; i < MAX_LIGHTS; i++) {
 
1871
    // if (!light[i]) continue;
 
1872
    for (int i = 0; i < lightCount; i++) {
 
1873
 
 
1874
      float denom = lightFalloffConstant[i];
 
1875
      float spotTerm = 1;
 
1876
 
 
1877
      if (lightType[i] == AMBIENT) {
 
1878
        if (lightFalloffQuadratic[i] != 0 || lightFalloffLinear[i] != 0) {
 
1879
          // Falloff depends on distance
 
1880
          float distSq = mag(lightPosition[i].x - wx,
 
1881
                             lightPosition[i].y - wy,
 
1882
                             lightPosition[i].z - wz);
 
1883
          denom +=
 
1884
            lightFalloffQuadratic[i] * distSq +
 
1885
            lightFalloffLinear[i] * sqrt(distSq);
 
1886
        }
 
1887
        if (denom == 0) denom = 1;
 
1888
 
 
1889
        contribution[LIGHT_AMBIENT_R] += lightDiffuse[i][0] / denom;
 
1890
        contribution[LIGHT_AMBIENT_G] += lightDiffuse[i][1] / denom;
 
1891
        contribution[LIGHT_AMBIENT_B] += lightDiffuse[i][2] / denom;
 
1892
 
 
1893
      } else {
 
1894
        // If not ambient, we must deal with direction
 
1895
 
 
1896
        // li is the vector from the vertex to the light
 
1897
        float lix, liy, liz;
 
1898
        float lightDir_dot_li = 0;
 
1899
        float n_dot_li = 0;
 
1900
 
 
1901
        if (lightType[i] == DIRECTIONAL) {
 
1902
          lix = -lightNormal[i].x;
 
1903
          liy = -lightNormal[i].y;
 
1904
          liz = -lightNormal[i].z;
 
1905
          denom = 1;
 
1906
          n_dot_li = (nx * lix + ny * liy + nz * liz);
 
1907
          // If light is lighting the face away from the camera, ditch
 
1908
          if (n_dot_li <= 0) {
 
1909
            continue;
 
1910
          }
 
1911
        } else { // Point or spot light (must deal also with light location)
 
1912
          lix = lightPosition[i].x - wx;
 
1913
          liy = lightPosition[i].y - wy;
 
1914
          liz = lightPosition[i].z - wz;
 
1915
          // normalize
 
1916
          float distSq = mag(lix, liy, liz);
 
1917
          if (distSq != 0) {
 
1918
            lix /= distSq;
 
1919
            liy /= distSq;
 
1920
            liz /= distSq;
 
1921
          }
 
1922
          n_dot_li = (nx * lix + ny * liy + nz * liz);
 
1923
          // If light is lighting the face away from the camera, ditch
 
1924
          if (n_dot_li <= 0) {
 
1925
            continue;
 
1926
          }
 
1927
 
 
1928
          if (lightType[i] == SPOT) { // Must deal with spot cone
 
1929
            lightDir_dot_li =
 
1930
              -(lightNormal[i].x * lix +
 
1931
                lightNormal[i].y * liy +
 
1932
                lightNormal[i].z * liz);
 
1933
            // Outside of spot cone
 
1934
            if (lightDir_dot_li <= lightSpotAngleCos[i]) {
 
1935
              continue;
 
1936
            }
 
1937
            spotTerm = (float) Math.pow(lightDir_dot_li, lightSpotConcentration[i]);
 
1938
          }
 
1939
 
 
1940
          if (lightFalloffQuadratic[i] != 0 || lightFalloffLinear[i] != 0) {
 
1941
            // Falloff depends on distance
 
1942
            denom +=
 
1943
              lightFalloffQuadratic[i] * distSq +
 
1944
              lightFalloffLinear[i] * (float) sqrt(distSq);
 
1945
          }
 
1946
        }
 
1947
        // Directional, point, or spot light:
 
1948
 
 
1949
        // We know n_dot_li > 0 from above "continues"
 
1950
 
 
1951
        if (denom == 0)
 
1952
          denom = 1;
 
1953
        float mul = n_dot_li * spotTerm / denom;
 
1954
        contribution[LIGHT_DIFFUSE_R] += lightDiffuse[i][0] * mul;
 
1955
        contribution[LIGHT_DIFFUSE_G] += lightDiffuse[i][1] * mul;
 
1956
        contribution[LIGHT_DIFFUSE_B] += lightDiffuse[i][2] * mul;
 
1957
 
 
1958
        // SPECULAR
 
1959
 
 
1960
        // If the material and light have a specular component.
 
1961
        if ((sr > 0 || sg > 0 || sb > 0) &&
 
1962
            (lightSpecular[i][0] > 0 ||
 
1963
             lightSpecular[i][1] > 0 ||
 
1964
             lightSpecular[i][2] > 0)) {
 
1965
 
 
1966
          float vmag = mag(wx, wy, wz);
 
1967
          if (vmag != 0) {
 
1968
            wx /= vmag;
 
1969
            wy /= vmag;
 
1970
            wz /= vmag;
 
1971
          }
 
1972
          float sx = lix - wx;
 
1973
          float sy = liy - wy;
 
1974
          float sz = liz - wz;
 
1975
          vmag = mag(sx, sy, sz);
 
1976
          if (vmag != 0) {
 
1977
            sx /= vmag;
 
1978
            sy /= vmag;
 
1979
            sz /= vmag;
 
1980
          }
 
1981
          float s_dot_n = (sx * nx + sy * ny + sz * nz);
 
1982
 
 
1983
          if (s_dot_n > 0) {
 
1984
            s_dot_n = (float) Math.pow(s_dot_n, shine);
 
1985
            mul = s_dot_n * spotTerm / denom;
 
1986
            contribution[LIGHT_SPECULAR_R] += lightSpecular[i][0] * mul;
 
1987
            contribution[LIGHT_SPECULAR_G] += lightSpecular[i][1] * mul;
 
1988
            contribution[LIGHT_SPECULAR_B] += lightSpecular[i][2] * mul;
 
1989
          }
 
1990
 
 
1991
        }
 
1992
      }
 
1993
    }
 
1994
    return;
 
1995
  }
 
1996
 
 
1997
 
 
1998
  // Multiply the lighting contribution into the vertex's colors.
 
1999
  // Only do this when there is ONE lighting per vertex
 
2000
  // (MANUAL_VERTEX_NORMAL or SHAPE_NORMAL mode).
 
2001
  private void applyLightingContribution(int vIndex, float[] contribution) {
 
2002
    float[] v = vertices[vIndex];
 
2003
 
 
2004
    v[R] = clamp(v[ER] + v[AR] * contribution[LIGHT_AMBIENT_R] + v[DR] * contribution[LIGHT_DIFFUSE_R]);
 
2005
    v[G] = clamp(v[EG] + v[AG] * contribution[LIGHT_AMBIENT_G] + v[DG] * contribution[LIGHT_DIFFUSE_G]);
 
2006
    v[B] = clamp(v[EB] + v[AB] * contribution[LIGHT_AMBIENT_B] + v[DB] * contribution[LIGHT_DIFFUSE_B]);
 
2007
    v[A] = clamp(v[DA]);
 
2008
 
 
2009
    v[SPR] = clamp(v[SPR] * contribution[LIGHT_SPECULAR_R]);
 
2010
    v[SPG] = clamp(v[SPG] * contribution[LIGHT_SPECULAR_G]);
 
2011
    v[SPB] = clamp(v[SPB] * contribution[LIGHT_SPECULAR_B]);
 
2012
    //v[SPA] = min(1, v[SPA]);
 
2013
 
 
2014
    v[BEEN_LIT] = 1;
 
2015
  }
 
2016
 
 
2017
 
 
2018
  private void lightVertex(int vIndex, float[] contribution) {
 
2019
    calcLightingContribution(vIndex, contribution);
 
2020
    applyLightingContribution(vIndex, contribution);
 
2021
  }
 
2022
 
 
2023
 
 
2024
  private void lightUnlitVertex(int vIndex, float[] contribution) {
 
2025
    if (vertices[vIndex][BEEN_LIT] == 0) {
 
2026
      lightVertex(vIndex, contribution);
 
2027
    }
 
2028
  }
 
2029
 
 
2030
 
 
2031
  private void copyPrelitVertexColor(int triIndex, int index, int colorIndex) {
 
2032
    float[] triColor = triangleColors[triIndex][colorIndex];
 
2033
    float[] v = vertices[index];
 
2034
 
 
2035
    triColor[TRI_DIFFUSE_R] = v[R];
 
2036
    triColor[TRI_DIFFUSE_G] = v[G];
 
2037
    triColor[TRI_DIFFUSE_B] = v[B];
 
2038
    triColor[TRI_DIFFUSE_A] = v[A];
 
2039
    triColor[TRI_SPECULAR_R] = v[SPR];
 
2040
    triColor[TRI_SPECULAR_G] = v[SPG];
 
2041
    triColor[TRI_SPECULAR_B] = v[SPB];
 
2042
    //triColor[TRI_SPECULAR_A] = v[SPA];
 
2043
  }
 
2044
 
 
2045
 
 
2046
  private void copyVertexColor(int triIndex, int index, int colorIndex,
 
2047
                               float[] contrib) {
 
2048
    float[] triColor = triangleColors[triIndex][colorIndex];
 
2049
    float[] v = vertices[index];
 
2050
 
 
2051
    triColor[TRI_DIFFUSE_R] =
 
2052
      clamp(v[ER] + v[AR] * contrib[LIGHT_AMBIENT_R] + v[DR] * contrib[LIGHT_DIFFUSE_R]);
 
2053
    triColor[TRI_DIFFUSE_G] =
 
2054
      clamp(v[EG] + v[AG] * contrib[LIGHT_AMBIENT_G] + v[DG] * contrib[LIGHT_DIFFUSE_G]);
 
2055
    triColor[TRI_DIFFUSE_B] =
 
2056
      clamp(v[EB] + v[AB] * contrib[LIGHT_AMBIENT_B] + v[DB] * contrib[LIGHT_DIFFUSE_B]);
 
2057
    triColor[TRI_DIFFUSE_A] = clamp(v[DA]);
 
2058
 
 
2059
    triColor[TRI_SPECULAR_R] = clamp(v[SPR] * contrib[LIGHT_SPECULAR_R]);
 
2060
    triColor[TRI_SPECULAR_G] = clamp(v[SPG] * contrib[LIGHT_SPECULAR_G]);
 
2061
    triColor[TRI_SPECULAR_B] = clamp(v[SPB] * contrib[LIGHT_SPECULAR_B]);
 
2062
  }
 
2063
 
 
2064
 
 
2065
  private void lightTriangle(int triIndex, float[] lightContribution) {
 
2066
    int vIndex = triangles[triIndex][VERTEX1];
 
2067
    copyVertexColor(triIndex, vIndex, 0, lightContribution);
 
2068
    vIndex = triangles[triIndex][VERTEX2];
 
2069
    copyVertexColor(triIndex, vIndex, 1, lightContribution);
 
2070
    vIndex = triangles[triIndex][VERTEX3];
 
2071
    copyVertexColor(triIndex, vIndex, 2, lightContribution);
 
2072
  }
 
2073
 
 
2074
 
 
2075
  private void lightTriangle(int triIndex) {
 
2076
    int vIndex;
 
2077
 
 
2078
    // Handle lighting on, but no lights (in this case, just use emissive)
 
2079
    // This wont be used currently because lightCount == 0 is don't use
 
2080
    // lighting at all... So. OK. If that ever changes, use the below:
 
2081
    /*
 
2082
    if (lightCount == 0) {
 
2083
      vIndex = triangles[triIndex][VERTEX1];
 
2084
      copy_emissive_vertex_color_to_triangle(triIndex, vIndex, 0);
 
2085
      vIndex = triangles[triIndex][VERTEX2];
 
2086
      copy_emissive_vertex_color_to_triangle(triIndex, vIndex, 1);
 
2087
      vIndex = triangles[triIndex][VERTEX3];
 
2088
      copy_emissive_vertex_color_to_triangle(triIndex, vIndex, 2);
 
2089
      return;
 
2090
    }
 
2091
    */
 
2092
 
 
2093
    // In MANUAL_VERTEX_NORMAL mode, we have a specific normal
 
2094
    // for each vertex. In that case, we light any verts that
 
2095
    // haven't already been lit and copy their colors straight
 
2096
    // into the triangle.
 
2097
    if (normalMode == NORMAL_MODE_VERTEX) {
 
2098
      vIndex = triangles[triIndex][VERTEX1];
 
2099
      lightUnlitVertex(vIndex, tempLightingContribution);
 
2100
      copyPrelitVertexColor(triIndex, vIndex, 0);
 
2101
 
 
2102
      vIndex = triangles[triIndex][VERTEX2];
 
2103
      lightUnlitVertex(vIndex, tempLightingContribution);
 
2104
      copyPrelitVertexColor(triIndex, vIndex, 1);
 
2105
 
 
2106
      vIndex = triangles[triIndex][VERTEX3];
 
2107
      lightUnlitVertex(vIndex, tempLightingContribution);
 
2108
      copyPrelitVertexColor(triIndex, vIndex, 2);
 
2109
 
 
2110
    }
 
2111
 
 
2112
    // If the lighting doesn't depend on the vertex position, do the
 
2113
    // following: We've already dealt with NORMAL_MODE_SHAPE mode before
 
2114
    // we got into this function, so here we only have to deal with
 
2115
    // NORMAL_MODE_AUTO. So we calculate the normal for this triangle,
 
2116
    // and use that for the lighting.
 
2117
    else if (!lightingDependsOnVertexPosition) {
 
2118
      vIndex = triangles[triIndex][VERTEX1];
 
2119
      int vIndex2 = triangles[triIndex][VERTEX2];
 
2120
      int vIndex3 = triangles[triIndex][VERTEX3];
 
2121
 
 
2122
      /*
 
2123
      dv1[0] = vertices[vIndex2][VX] - vertices[vIndex][VX];
 
2124
      dv1[1] = vertices[vIndex2][VY] - vertices[vIndex][VY];
 
2125
      dv1[2] = vertices[vIndex2][VZ] - vertices[vIndex][VZ];
 
2126
 
 
2127
      dv2[0] = vertices[vIndex3][VX] - vertices[vIndex][VX];
 
2128
      dv2[1] = vertices[vIndex3][VY] - vertices[vIndex][VY];
 
2129
      dv2[2] = vertices[vIndex3][VZ] - vertices[vIndex][VZ];
 
2130
 
 
2131
      cross(dv1, dv2, norm);
 
2132
      */
 
2133
 
 
2134
      cross(vertices[vIndex2][VX] - vertices[vIndex][VX],
 
2135
            vertices[vIndex2][VY] - vertices[vIndex][VY],
 
2136
            vertices[vIndex2][VZ] - vertices[vIndex][VZ],
 
2137
            vertices[vIndex3][VX] - vertices[vIndex][VX],
 
2138
            vertices[vIndex3][VY] - vertices[vIndex][VY],
 
2139
            vertices[vIndex3][VZ] - vertices[vIndex][VZ], lightTriangleNorm);
 
2140
 
 
2141
      lightTriangleNorm.normalize();
 
2142
      vertices[vIndex][NX] = lightTriangleNorm.x;
 
2143
      vertices[vIndex][NY] = lightTriangleNorm.y;
 
2144
      vertices[vIndex][NZ] = lightTriangleNorm.z;
 
2145
 
 
2146
      // The true at the end says the normal is already in world coordinates
 
2147
      calcLightingContribution(vIndex, tempLightingContribution, true);
 
2148
      copyVertexColor(triIndex, vIndex, 0, tempLightingContribution);
 
2149
      copyVertexColor(triIndex, vIndex2, 1, tempLightingContribution);
 
2150
      copyVertexColor(triIndex, vIndex3, 2, tempLightingContribution);
 
2151
    }
 
2152
 
 
2153
    // If lighting is position-dependent
 
2154
    else {
 
2155
      if (normalMode == NORMAL_MODE_SHAPE) {
 
2156
        vIndex = triangles[triIndex][VERTEX1];
 
2157
        vertices[vIndex][NX] = vertices[shapeFirst][NX];
 
2158
        vertices[vIndex][NY] = vertices[shapeFirst][NY];
 
2159
        vertices[vIndex][NZ] = vertices[shapeFirst][NZ];
 
2160
        calcLightingContribution(vIndex, tempLightingContribution);
 
2161
        copyVertexColor(triIndex, vIndex, 0, tempLightingContribution);
 
2162
 
 
2163
        vIndex = triangles[triIndex][VERTEX2];
 
2164
        vertices[vIndex][NX] = vertices[shapeFirst][NX];
 
2165
        vertices[vIndex][NY] = vertices[shapeFirst][NY];
 
2166
        vertices[vIndex][NZ] = vertices[shapeFirst][NZ];
 
2167
        calcLightingContribution(vIndex, tempLightingContribution);
 
2168
        copyVertexColor(triIndex, vIndex, 1, tempLightingContribution);
 
2169
 
 
2170
        vIndex = triangles[triIndex][VERTEX3];
 
2171
        vertices[vIndex][NX] = vertices[shapeFirst][NX];
 
2172
        vertices[vIndex][NY] = vertices[shapeFirst][NY];
 
2173
        vertices[vIndex][NZ] = vertices[shapeFirst][NZ];
 
2174
        calcLightingContribution(vIndex, tempLightingContribution);
 
2175
        copyVertexColor(triIndex, vIndex, 2, tempLightingContribution);
 
2176
      }
 
2177
 
 
2178
      // lighting mode is AUTO_NORMAL
 
2179
      else {
 
2180
        vIndex = triangles[triIndex][VERTEX1];
 
2181
        int vIndex2 = triangles[triIndex][VERTEX2];
 
2182
        int vIndex3 = triangles[triIndex][VERTEX3];
 
2183
 
 
2184
        /*
 
2185
        dv1[0] = vertices[vIndex2][VX] - vertices[vIndex][VX];
 
2186
        dv1[1] = vertices[vIndex2][VY] - vertices[vIndex][VY];
 
2187
        dv1[2] = vertices[vIndex2][VZ] - vertices[vIndex][VZ];
 
2188
 
 
2189
        dv2[0] = vertices[vIndex3][VX] - vertices[vIndex][VX];
 
2190
        dv2[1] = vertices[vIndex3][VY] - vertices[vIndex][VY];
 
2191
        dv2[2] = vertices[vIndex3][VZ] - vertices[vIndex][VZ];
 
2192
 
 
2193
        cross(dv1, dv2, norm);
 
2194
        */
 
2195
 
 
2196
        cross(vertices[vIndex2][VX] - vertices[vIndex][VX],
 
2197
              vertices[vIndex2][VY] - vertices[vIndex][VY],
 
2198
              vertices[vIndex2][VZ] - vertices[vIndex][VZ],
 
2199
              vertices[vIndex3][VX] - vertices[vIndex][VX],
 
2200
              vertices[vIndex3][VY] - vertices[vIndex][VY],
 
2201
              vertices[vIndex3][VZ] - vertices[vIndex][VZ], lightTriangleNorm);
 
2202
//        float nmag = mag(norm[X], norm[Y], norm[Z]);
 
2203
//        if (nmag != 0 && nmag != 1) {
 
2204
//          norm[X] /= nmag; norm[Y] /= nmag; norm[Z] /= nmag;
 
2205
//        }
 
2206
        lightTriangleNorm.normalize();
 
2207
        vertices[vIndex][NX] = lightTriangleNorm.x;
 
2208
        vertices[vIndex][NY] = lightTriangleNorm.y;
 
2209
        vertices[vIndex][NZ] = lightTriangleNorm.z;
 
2210
        // The true at the end says the normal is already in world coordinates
 
2211
        calcLightingContribution(vIndex, tempLightingContribution, true);
 
2212
        copyVertexColor(triIndex, vIndex, 0, tempLightingContribution);
 
2213
 
 
2214
        vertices[vIndex2][NX] = lightTriangleNorm.x;
 
2215
        vertices[vIndex2][NY] = lightTriangleNorm.y;
 
2216
        vertices[vIndex2][NZ] = lightTriangleNorm.z;
 
2217
        // The true at the end says the normal is already in world coordinates
 
2218
        calcLightingContribution(vIndex2, tempLightingContribution, true);
 
2219
        copyVertexColor(triIndex, vIndex2, 1, tempLightingContribution);
 
2220
 
 
2221
        vertices[vIndex3][NX] = lightTriangleNorm.x;
 
2222
        vertices[vIndex3][NY] = lightTriangleNorm.y;
 
2223
        vertices[vIndex3][NZ] = lightTriangleNorm.z;
 
2224
        // The true at the end says the normal is already in world coordinates
 
2225
        calcLightingContribution(vIndex3, tempLightingContribution, true);
 
2226
        copyVertexColor(triIndex, vIndex3, 2, tempLightingContribution);
 
2227
      }
 
2228
    }
 
2229
  }
 
2230
 
 
2231
 
 
2232
  protected void renderTriangles(int start, int stop) {
 
2233
    for (int i = start; i < stop; i++) {
 
2234
      float a[] = vertices[triangles[i][VERTEX1]];
 
2235
      float b[] = vertices[triangles[i][VERTEX2]];
 
2236
      float c[] = vertices[triangles[i][VERTEX3]];
 
2237
      int tex = triangles[i][TEXTURE_INDEX];
 
2238
 
 
2239
      /*
 
2240
      // removing for 0149 with the return of P2D
 
2241
      // ewjordan: hack to 'fix' accuracy issues when drawing in 2d
 
2242
      // see also render_lines() where similar hack is employed
 
2243
      float shift = 0.15f;//was 0.49f
 
2244
      boolean shifted = false;
 
2245
      if (drawing2D() && (a[Z] == 0)) {
 
2246
        shifted = true;
 
2247
        a[TX] += shift;
 
2248
        a[TY] += shift;
 
2249
        a[VX] += shift*a[VW];
 
2250
        a[VY] += shift*a[VW];
 
2251
        b[TX] += shift;
 
2252
        b[TY] += shift;
 
2253
        b[VX] += shift*b[VW];
 
2254
        b[VY] += shift*b[VW];
 
2255
        c[TX] += shift;
 
2256
        c[TY] += shift;
 
2257
        c[VX] += shift*c[VW];
 
2258
        c[VY] += shift*c[VW];
 
2259
      }
 
2260
      */
 
2261
 
 
2262
      triangle.reset();
 
2263
 
 
2264
      // This is only true when not textured.
 
2265
      // We really should pass specular straight through to triangle rendering.
 
2266
      float ar = clamp(triangleColors[i][0][TRI_DIFFUSE_R] + triangleColors[i][0][TRI_SPECULAR_R]);
 
2267
      float ag = clamp(triangleColors[i][0][TRI_DIFFUSE_G] + triangleColors[i][0][TRI_SPECULAR_G]);
 
2268
      float ab = clamp(triangleColors[i][0][TRI_DIFFUSE_B] + triangleColors[i][0][TRI_SPECULAR_B]);
 
2269
      float br = clamp(triangleColors[i][1][TRI_DIFFUSE_R] + triangleColors[i][1][TRI_SPECULAR_R]);
 
2270
      float bg = clamp(triangleColors[i][1][TRI_DIFFUSE_G] + triangleColors[i][1][TRI_SPECULAR_G]);
 
2271
      float bb = clamp(triangleColors[i][1][TRI_DIFFUSE_B] + triangleColors[i][1][TRI_SPECULAR_B]);
 
2272
      float cr = clamp(triangleColors[i][2][TRI_DIFFUSE_R] + triangleColors[i][2][TRI_SPECULAR_R]);
 
2273
      float cg = clamp(triangleColors[i][2][TRI_DIFFUSE_G] + triangleColors[i][2][TRI_SPECULAR_G]);
 
2274
      float cb = clamp(triangleColors[i][2][TRI_DIFFUSE_B] + triangleColors[i][2][TRI_SPECULAR_B]);
 
2275
 
 
2276
      // ACCURATE TEXTURE CODE
 
2277
      boolean failedToPrecalc = false;
 
2278
      if (s_enableAccurateTextures && frustumMode){
 
2279
        boolean textured = true;
 
2280
        smoothTriangle.reset(3);
 
2281
        smoothTriangle.smooth = true;
 
2282
        smoothTriangle.interpARGB = true;
 
2283
        smoothTriangle.setIntensities(ar, ag, ab, a[A],
 
2284
                                      br, bg, bb, b[A],
 
2285
                                      cr, cg, cb, c[A]);
 
2286
        if (tex > -1 && textures[tex] != null) {
 
2287
          smoothTriangle.setCamVertices(a[VX], a[VY], a[VZ],
 
2288
                                        b[VX], b[VY], b[VZ],
 
2289
                                        c[VX], c[VY], c[VZ]);
 
2290
          smoothTriangle.interpUV = true;
 
2291
          smoothTriangle.texture(textures[tex]);
 
2292
          float umult = textures[tex].width;  // apparently no check for textureMode is needed here
 
2293
          float vmult = textures[tex].height;
 
2294
          smoothTriangle.vertices[0][U] = a[U]*umult;
 
2295
          smoothTriangle.vertices[0][V] = a[V]*vmult;
 
2296
          smoothTriangle.vertices[1][U] = b[U]*umult;
 
2297
          smoothTriangle.vertices[1][V] = b[V]*vmult;
 
2298
          smoothTriangle.vertices[2][U] = c[U]*umult;
 
2299
          smoothTriangle.vertices[2][V] = c[V]*vmult;
 
2300
        } else {
 
2301
          smoothTriangle.interpUV = false;
 
2302
          textured = false;
 
2303
        }
 
2304
 
 
2305
        smoothTriangle.setVertices(a[TX], a[TY], a[TZ],
 
2306
                                   b[TX], b[TY], b[TZ],
 
2307
                                   c[TX], c[TY], c[TZ]);
 
2308
 
 
2309
 
 
2310
        if (!textured || smoothTriangle.precomputeAccurateTexturing()){
 
2311
                smoothTriangle.render();
 
2312
        } else {
 
2313
                // Something went wrong with the precomputation,
 
2314
                // so we need to fall back on normal PTriangle
 
2315
                // rendering.
 
2316
                failedToPrecalc = true;
 
2317
        }
 
2318
      }
 
2319
 
 
2320
      // Normal triangle rendering
 
2321
      // Note: this is not an end-if from the smoothed texturing mode
 
2322
      // because it's possible that the precalculation will fail and we
 
2323
      // need to fall back on normal rendering.
 
2324
      if (!s_enableAccurateTextures || failedToPrecalc || (frustumMode == false)){
 
2325
      if (tex > -1 && textures[tex] != null) {
 
2326
        triangle.setTexture(textures[tex]);
 
2327
        triangle.setUV(a[U], a[V], b[U], b[V], c[U], c[V]);
 
2328
      }
 
2329
 
 
2330
      triangle.setIntensities(ar, ag, ab, a[A],
 
2331
                              br, bg, bb, b[A],
 
2332
                              cr, cg, cb, c[A]);
 
2333
 
 
2334
      triangle.setVertices(a[TX], a[TY], a[TZ],
 
2335
                           b[TX], b[TY], b[TZ],
 
2336
                           c[TX], c[TY], c[TZ]);
 
2337
 
 
2338
          triangle.render();
 
2339
      }
 
2340
 
 
2341
      /*
 
2342
      // removing for 0149 with the return of P2D
 
2343
      if (drawing2D() && shifted){
 
2344
        a[TX] -= shift;
 
2345
        a[TY] -= shift;
 
2346
        a[VX] -= shift*a[VW];
 
2347
        a[VY] -= shift*a[VW];
 
2348
        b[TX] -= shift;
 
2349
        b[TY] -= shift;
 
2350
        b[VX] -= shift*b[VW];
 
2351
        b[VY] -= shift*b[VW];
 
2352
        c[TX] -= shift;
 
2353
        c[TY] -= shift;
 
2354
        c[VX] -= shift*c[VW];
 
2355
        c[VY] -= shift*c[VW];
 
2356
      }
 
2357
      */
 
2358
    }
 
2359
  }
 
2360
 
 
2361
 
 
2362
  protected void rawTriangles(int start, int stop) {
 
2363
    raw.colorMode(RGB, 1);
 
2364
    raw.noStroke();
 
2365
    raw.beginShape(TRIANGLES);
 
2366
 
 
2367
    for (int i = start; i < stop; i++) {
 
2368
      float a[] = vertices[triangles[i][VERTEX1]];
 
2369
      float b[] = vertices[triangles[i][VERTEX2]];
 
2370
      float c[] = vertices[triangles[i][VERTEX3]];
 
2371
 
 
2372
      float ar = clamp(triangleColors[i][0][TRI_DIFFUSE_R] + triangleColors[i][0][TRI_SPECULAR_R]);
 
2373
      float ag = clamp(triangleColors[i][0][TRI_DIFFUSE_G] + triangleColors[i][0][TRI_SPECULAR_G]);
 
2374
      float ab = clamp(triangleColors[i][0][TRI_DIFFUSE_B] + triangleColors[i][0][TRI_SPECULAR_B]);
 
2375
      float br = clamp(triangleColors[i][1][TRI_DIFFUSE_R] + triangleColors[i][1][TRI_SPECULAR_R]);
 
2376
      float bg = clamp(triangleColors[i][1][TRI_DIFFUSE_G] + triangleColors[i][1][TRI_SPECULAR_G]);
 
2377
      float bb = clamp(triangleColors[i][1][TRI_DIFFUSE_B] + triangleColors[i][1][TRI_SPECULAR_B]);
 
2378
      float cr = clamp(triangleColors[i][2][TRI_DIFFUSE_R] + triangleColors[i][2][TRI_SPECULAR_R]);
 
2379
      float cg = clamp(triangleColors[i][2][TRI_DIFFUSE_G] + triangleColors[i][2][TRI_SPECULAR_G]);
 
2380
      float cb = clamp(triangleColors[i][2][TRI_DIFFUSE_B] + triangleColors[i][2][TRI_SPECULAR_B]);
 
2381
 
 
2382
      int tex = triangles[i][TEXTURE_INDEX];
 
2383
      PImage texImage = (tex > -1) ? textures[tex] : null;
 
2384
      if (texImage != null) {
 
2385
        if (raw.is3D()) {
 
2386
          if ((a[VW] != 0) && (b[VW] != 0) && (c[VW] != 0)) {
 
2387
            raw.fill(ar, ag, ab, a[A]);
 
2388
            raw.vertex(a[VX] / a[VW], a[VY] / a[VW], a[VZ] / a[VW], a[U], a[V]);
 
2389
            raw.fill(br, bg, bb, b[A]);
 
2390
            raw.vertex(b[VX] / b[VW], b[VY] / b[VW], b[VZ] / b[VW], b[U], b[V]);
 
2391
            raw.fill(cr, cg, cb, c[A]);
 
2392
            raw.vertex(c[VX] / c[VW], c[VY] / c[VW], c[VZ] / c[VW], c[U], c[V]);
 
2393
          }
 
2394
        } else if (raw.is2D()) {
 
2395
          raw.fill(ar, ag, ab, a[A]);
 
2396
          raw.vertex(a[TX], a[TY], a[U], a[V]);
 
2397
          raw.fill(br, bg, bb, b[A]);
 
2398
          raw.vertex(b[TX], b[TY], b[U], b[V]);
 
2399
          raw.fill(cr, cg, cb, c[A]);
 
2400
          raw.vertex(c[TX], c[TY], c[U], c[V]);
 
2401
        }
 
2402
      } else {  // no texture
 
2403
        if (raw.is3D()) {
 
2404
          if ((a[VW] != 0) && (b[VW] != 0) && (c[VW] != 0)) {
 
2405
            raw.fill(ar, ag, ab, a[A]);
 
2406
            raw.vertex(a[VX] / a[VW], a[VY] / a[VW], a[VZ] / a[VW]);
 
2407
            raw.fill(br, bg, bb, b[A]);
 
2408
            raw.vertex(b[VX] / b[VW], b[VY] / b[VW], b[VZ] / b[VW]);
 
2409
            raw.fill(cr, cg, cb, c[A]);
 
2410
            raw.vertex(c[VX] / c[VW], c[VY] / c[VW], c[VZ] / c[VW]);
 
2411
          }
 
2412
        } else if (raw.is2D()) {
 
2413
          raw.fill(ar, ag, ab, a[A]);
 
2414
          raw.vertex(a[TX], a[TY]);
 
2415
          raw.fill(br, bg, bb, b[A]);
 
2416
          raw.vertex(b[TX], b[TY]);
 
2417
          raw.fill(cr, cg, cb, c[A]);
 
2418
          raw.vertex(c[TX], c[TY]);
 
2419
        }
 
2420
      }
 
2421
    }
 
2422
 
 
2423
    raw.endShape();
 
2424
  }
 
2425
 
 
2426
 
 
2427
  //////////////////////////////////////////////////////////////
 
2428
 
 
2429
 
 
2430
  //public void bezierVertex(float x2, float y2,
 
2431
  //                         float x3, float y3,
 
2432
  //                         float x4, float y4)
 
2433
 
 
2434
 
 
2435
  //public void bezierVertex(float x2, float y2, float z2,
 
2436
  //                         float x3, float y3, float z3,
 
2437
  //                         float x4, float y4, float z4)
 
2438
 
 
2439
 
 
2440
 
 
2441
  //////////////////////////////////////////////////////////////
 
2442
 
 
2443
 
 
2444
  //public void curveVertex(float x, float y)
 
2445
 
 
2446
 
 
2447
  //public void curveVertex(float x, float y, float z)
 
2448
 
 
2449
 
 
2450
 
 
2451
  ////////////////////////////////////////////////////////////
 
2452
 
 
2453
 
 
2454
  /**
 
2455
   * Emit any sorted geometry that's been collected on this frame.
 
2456
   */
 
2457
  public void flush() {
 
2458
    if (hints[ENABLE_DEPTH_SORT]) {
 
2459
      sort();
 
2460
    }
 
2461
    render();
 
2462
 
 
2463
    /*
 
2464
    if (triangleCount > 0) {
 
2465
      if (hints[ENABLE_DEPTH_SORT]) {
 
2466
        sortTriangles();
 
2467
      }
 
2468
      renderTriangles();
 
2469
    }
 
2470
    if (lineCount > 0) {
 
2471
      if (hints[ENABLE_DEPTH_SORT]) {
 
2472
        sortLines();
 
2473
      }
 
2474
      renderLines();
 
2475
    }
 
2476
    // Clear this out in case flush() is called again.
 
2477
    // For instance, with hint(ENABLE_DEPTH_SORT), it will be called
 
2478
    // once on endRaw(), and once again at endDraw().
 
2479
    triangleCount = 0;
 
2480
    lineCount = 0;
 
2481
    */
 
2482
  }
 
2483
 
 
2484
 
 
2485
  protected void render() {
 
2486
    if (pointCount > 0) {
 
2487
      renderPoints(0, pointCount);
 
2488
      if (raw != null) {
 
2489
        rawPoints(0, pointCount);
 
2490
      }
 
2491
      pointCount = 0;
 
2492
    }
 
2493
    if (lineCount > 0) {
 
2494
      renderLines(0, lineCount);
 
2495
      if (raw != null) {
 
2496
        rawLines(0, lineCount);
 
2497
      }
 
2498
      lineCount = 0;
 
2499
      pathCount = 0;
 
2500
    }
 
2501
    if (triangleCount > 0) {
 
2502
      renderTriangles(0, triangleCount);
 
2503
      if (raw != null) {
 
2504
        rawTriangles(0, triangleCount);
 
2505
      }
 
2506
      triangleCount = 0;
 
2507
    }
 
2508
  }
 
2509
 
 
2510
 
 
2511
  /**
 
2512
   * Handle depth sorting of geometry. Currently this only handles triangles,
 
2513
   * however in the future it will be expanded for points and lines, which
 
2514
   * will also need to be interspersed with one another while rendering.
 
2515
   */
 
2516
  protected void sort() {
 
2517
    if (triangleCount > 0) {
 
2518
      sortTrianglesInternal(0, triangleCount-1);
 
2519
    }
 
2520
  }
 
2521
 
 
2522
 
 
2523
  private void sortTrianglesInternal(int i, int j) {
 
2524
    int pivotIndex = (i+j)/2;
 
2525
    sortTrianglesSwap(pivotIndex, j);
 
2526
    int k = sortTrianglesPartition(i-1, j);
 
2527
    sortTrianglesSwap(k, j);
 
2528
    if ((k-i) > 1) sortTrianglesInternal(i, k-1);
 
2529
    if ((j-k) > 1) sortTrianglesInternal(k+1, j);
 
2530
  }
 
2531
 
 
2532
 
 
2533
  private int sortTrianglesPartition(int left, int right) {
 
2534
    int pivot = right;
 
2535
    do {
 
2536
      while (sortTrianglesCompare(++left, pivot) < 0) { }
 
2537
      while ((right != 0) &&
 
2538
             (sortTrianglesCompare(--right, pivot) > 0)) { }
 
2539
      sortTrianglesSwap(left, right);
 
2540
    } while (left < right);
 
2541
    sortTrianglesSwap(left, right);
 
2542
    return left;
 
2543
  }
 
2544
 
 
2545
 
 
2546
  private void sortTrianglesSwap(int a, int b) {
 
2547
    int tempi[] = triangles[a];
 
2548
    triangles[a] = triangles[b];
 
2549
    triangles[b] = tempi;
 
2550
    float tempf[][] = triangleColors[a];
 
2551
    triangleColors[a] = triangleColors[b];
 
2552
    triangleColors[b] = tempf;
 
2553
  }
 
2554
 
 
2555
 
 
2556
  private float sortTrianglesCompare(int a, int b) {
 
2557
    /*
 
2558
    if (Float.isNaN(vertices[triangles[a][VERTEX1]][TZ]) ||
 
2559
        Float.isNaN(vertices[triangles[a][VERTEX2]][TZ]) ||
 
2560
        Float.isNaN(vertices[triangles[a][VERTEX3]][TZ]) ||
 
2561
        Float.isNaN(vertices[triangles[b][VERTEX1]][TZ]) ||
 
2562
        Float.isNaN(vertices[triangles[b][VERTEX2]][TZ]) ||
 
2563
        Float.isNaN(vertices[triangles[b][VERTEX3]][TZ])) {
 
2564
      System.err.println("NaN values in triangle");
 
2565
    }
 
2566
    */
 
2567
    return ((vertices[triangles[b][VERTEX1]][TZ] +
 
2568
             vertices[triangles[b][VERTEX2]][TZ] +
 
2569
             vertices[triangles[b][VERTEX3]][TZ]) -
 
2570
            (vertices[triangles[a][VERTEX1]][TZ] +
 
2571
             vertices[triangles[a][VERTEX2]][TZ] +
 
2572
             vertices[triangles[a][VERTEX3]][TZ]));
 
2573
  }
 
2574
 
 
2575
 
 
2576
 
 
2577
  //////////////////////////////////////////////////////////////
 
2578
 
 
2579
  // POINT, LINE, TRIANGLE, QUAD
 
2580
 
 
2581
  // Because vertex(x, y) is mapped to vertex(x, y, 0), none of these commands
 
2582
  // need to be overridden from their default implementation in PGraphics.
 
2583
 
 
2584
 
 
2585
  //public void point(float x, float y)
 
2586
 
 
2587
 
 
2588
  //public void point(float x, float y, float z)
 
2589
 
 
2590
 
 
2591
  //public void line(float x1, float y1, float x2, float y2)
 
2592
 
 
2593
 
 
2594
  //public void line(float x1, float y1, float z1,
 
2595
  //                 float x2, float y2, float z2)
 
2596
 
 
2597
 
 
2598
  //public void triangle(float x1, float y1, float x2, float y2,
 
2599
  //                     float x3, float y3)
 
2600
 
 
2601
 
 
2602
  //public void quad(float x1, float y1, float x2, float y2,
 
2603
  //                 float x3, float y3, float x4, float y4)
 
2604
 
 
2605
 
 
2606
 
 
2607
  //////////////////////////////////////////////////////////////
 
2608
 
 
2609
  // RECT
 
2610
 
 
2611
 
 
2612
  //public void rectMode(int mode)
 
2613
 
 
2614
 
 
2615
  //public void rect(float a, float b, float c, float d)
 
2616
 
 
2617
 
 
2618
  //protected void rectImpl(float x1, float y1, float x2, float y2)
 
2619
 
 
2620
 
 
2621
 
 
2622
  //////////////////////////////////////////////////////////////
 
2623
 
 
2624
  // ELLIPSE
 
2625
 
 
2626
 
 
2627
  //public void ellipseMode(int mode)
 
2628
 
 
2629
 
 
2630
  //public void ellipse(float a, float b, float c, float d)
 
2631
 
 
2632
 
 
2633
  protected void ellipseImpl(float x, float y, float w, float h) {
 
2634
    float radiusH = w / 2;
 
2635
    float radiusV = h / 2;
 
2636
 
 
2637
    float centerX = x + radiusH;
 
2638
    float centerY = y + radiusV;
 
2639
 
 
2640
//    float sx1 = screenX(x, y);
 
2641
//    float sy1 = screenY(x, y);
 
2642
//    float sx2 = screenX(x+w, y+h);
 
2643
//    float sy2 = screenY(x+w, y+h);
 
2644
 
 
2645
    // returning to pre-1.0 version of algorithm because of problems
 
2646
    int rough = (int)(4+Math.sqrt(w+h)*3);
 
2647
    int accuracy = PApplet.constrain(rough, 6, 100);
 
2648
 
 
2649
    if (fill) {
 
2650
      // returning to pre-1.0 version of algorithm because of problems
 
2651
//      int rough = (int)(4+Math.sqrt(w+h)*3);
 
2652
//      int rough = (int) (TWO_PI * PApplet.dist(sx1, sy1, sx2, sy2) / 20);
 
2653
//      int accuracy = PApplet.constrain(rough, 6, 100);
 
2654
 
 
2655
      float inc = (float)SINCOS_LENGTH / accuracy;
 
2656
      float val = 0;
 
2657
 
 
2658
      boolean strokeSaved = stroke;
 
2659
      stroke = false;
 
2660
      boolean smoothSaved = smooth;
 
2661
      if (smooth && stroke) {
 
2662
        smooth = false;
 
2663
      }
 
2664
 
 
2665
      beginShape(TRIANGLE_FAN);
 
2666
      normal(0, 0, 1);
 
2667
      vertex(centerX, centerY);
 
2668
      for (int i = 0; i < accuracy; i++) {
 
2669
        vertex(centerX + cosLUT[(int) val] * radiusH,
 
2670
               centerY + sinLUT[(int) val] * radiusV);
 
2671
        val = (val + inc) % SINCOS_LENGTH;
 
2672
      }
 
2673
      // back to the beginning
 
2674
      vertex(centerX + cosLUT[0] * radiusH,
 
2675
             centerY + sinLUT[0] * radiusV);
 
2676
      endShape();
 
2677
 
 
2678
      stroke = strokeSaved;
 
2679
      smooth = smoothSaved;
 
2680
    }
 
2681
 
 
2682
    if (stroke) {
 
2683
//      int rough = (int) (TWO_PI * PApplet.dist(sx1, sy1, sx2, sy2) / 8);
 
2684
//      int accuracy = PApplet.constrain(rough, 6, 100);
 
2685
 
 
2686
      float inc = (float)SINCOS_LENGTH / accuracy;
 
2687
      float val = 0;
 
2688
 
 
2689
      boolean savedFill = fill;
 
2690
      fill = false;
 
2691
 
 
2692
      val = 0;
 
2693
      beginShape();
 
2694
      for (int i = 0; i < accuracy; i++) {
 
2695
        vertex(centerX + cosLUT[(int) val] * radiusH,
 
2696
               centerY + sinLUT[(int) val] * radiusV);
 
2697
        val = (val + inc) % SINCOS_LENGTH;
 
2698
      }
 
2699
      endShape(CLOSE);
 
2700
 
 
2701
      fill = savedFill;
 
2702
    }
 
2703
  }
 
2704
 
 
2705
 
 
2706
  //public void arc(float a, float b, float c, float d,
 
2707
  //                float start, float stop)
 
2708
 
 
2709
 
 
2710
  protected void arcImpl(float x, float y, float w, float h,
 
2711
                         float start, float stop) {
 
2712
    float hr = w / 2f;
 
2713
    float vr = h / 2f;
 
2714
 
 
2715
    float centerX = x + hr;
 
2716
    float centerY = y + vr;
 
2717
 
 
2718
    if (fill) {
 
2719
      // shut off stroke for a minute
 
2720
      boolean savedStroke = stroke;
 
2721
      stroke = false;
 
2722
 
 
2723
      int startLUT = (int) (0.5f + (start / TWO_PI) * SINCOS_LENGTH);
 
2724
      int stopLUT = (int) (0.5f + (stop / TWO_PI) * SINCOS_LENGTH);
 
2725
 
 
2726
      beginShape(TRIANGLE_FAN);
 
2727
      vertex(centerX, centerY);
 
2728
      int increment = 1; // what's a good algorithm? stopLUT - startLUT;
 
2729
      for (int i = startLUT; i < stopLUT; i += increment) {
 
2730
        int ii = i % SINCOS_LENGTH;
 
2731
        // modulo won't make the value positive
 
2732
        if (ii < 0) ii += SINCOS_LENGTH;
 
2733
        vertex(centerX + cosLUT[ii] * hr,
 
2734
               centerY + sinLUT[ii] * vr);
 
2735
      }
 
2736
      // draw last point explicitly for accuracy
 
2737
      vertex(centerX + cosLUT[stopLUT % SINCOS_LENGTH] * hr,
 
2738
             centerY + sinLUT[stopLUT % SINCOS_LENGTH] * vr);
 
2739
      endShape();
 
2740
 
 
2741
      stroke = savedStroke;
 
2742
    }
 
2743
 
 
2744
    if (stroke) {
 
2745
      // Almost identical to above, but this uses a LINE_STRIP
 
2746
      // and doesn't include the first (center) vertex.
 
2747
 
 
2748
      boolean savedFill = fill;
 
2749
      fill = false;
 
2750
 
 
2751
      int startLUT = (int) (0.5f + (start / TWO_PI) * SINCOS_LENGTH);
 
2752
      int stopLUT = (int) (0.5f + (stop / TWO_PI) * SINCOS_LENGTH);
 
2753
 
 
2754
      beginShape(); //LINE_STRIP);
 
2755
      int increment = 1; // what's a good algorithm? stopLUT - startLUT;
 
2756
      for (int i = startLUT; i < stopLUT; i += increment) {
 
2757
        int ii = i % SINCOS_LENGTH;
 
2758
        if (ii < 0) ii += SINCOS_LENGTH;
 
2759
        vertex(centerX + cosLUT[ii] * hr,
 
2760
               centerY + sinLUT[ii] * vr);
 
2761
      }
 
2762
      // draw last point explicitly for accuracy
 
2763
      vertex(centerX + cosLUT[stopLUT % SINCOS_LENGTH] * hr,
 
2764
             centerY + sinLUT[stopLUT % SINCOS_LENGTH] * vr);
 
2765
      endShape();
 
2766
 
 
2767
      fill = savedFill;
 
2768
    }
 
2769
  }
 
2770
 
 
2771
 
 
2772
 
 
2773
  //////////////////////////////////////////////////////////////
 
2774
 
 
2775
  // BOX
 
2776
 
 
2777
 
 
2778
  //public void box(float size)
 
2779
 
 
2780
 
 
2781
  public void box(float w, float h, float d) {
 
2782
    if (triangle != null) {  // triangle is null in gl
 
2783
      triangle.setCulling(true);
 
2784
    }
 
2785
 
 
2786
    super.box(w, h, d);
 
2787
 
 
2788
    if (triangle != null) {  // triangle is null in gl
 
2789
      triangle.setCulling(false);
 
2790
    }
 
2791
  }
 
2792
 
 
2793
 
 
2794
 
 
2795
  //////////////////////////////////////////////////////////////
 
2796
 
 
2797
  // SPHERE
 
2798
 
 
2799
 
 
2800
  //public void sphereDetail(int res)
 
2801
 
 
2802
 
 
2803
  //public void sphereDetail(int ures, int vres)
 
2804
 
 
2805
 
 
2806
  public void sphere(float r) {
 
2807
    if (triangle != null) {  // triangle is null in gl
 
2808
      triangle.setCulling(true);
 
2809
    }
 
2810
 
 
2811
    super.sphere(r);
 
2812
 
 
2813
    if (triangle != null) {  // triangle is null in gl
 
2814
      triangle.setCulling(false);
 
2815
    }
 
2816
  }
 
2817
 
 
2818
 
 
2819
 
 
2820
  //////////////////////////////////////////////////////////////
 
2821
 
 
2822
  // BEZIER
 
2823
 
 
2824
 
 
2825
  //public float bezierPoint(float a, float b, float c, float d, float t)
 
2826
 
 
2827
 
 
2828
  //public float bezierTangent(float a, float b, float c, float d, float t)
 
2829
 
 
2830
 
 
2831
  //public void bezierDetail(int detail)
 
2832
 
 
2833
 
 
2834
  //public void bezier(float x1, float y1,
 
2835
  //                   float x2, float y2,
 
2836
  //                   float x3, float y3,
 
2837
  //                   float x4, float y4)
 
2838
 
 
2839
 
 
2840
  //public void bezier(float x1, float y1, float z1,
 
2841
  //                   float x2, float y2, float z2,
 
2842
  //                   float x3, float y3, float z3,
 
2843
  //                   float x4, float y4, float z4)
 
2844
 
 
2845
 
 
2846
 
 
2847
  //////////////////////////////////////////////////////////////
 
2848
 
 
2849
  // CATMULL-ROM CURVES
 
2850
 
 
2851
 
 
2852
  //public float curvePoint(float a, float b, float c, float d, float t)
 
2853
 
 
2854
 
 
2855
  //public float curveTangent(float a, float b, float c, float d, float t)
 
2856
 
 
2857
 
 
2858
  //public void curveDetail(int detail)
 
2859
 
 
2860
 
 
2861
  //public void curveTightness(float tightness)
 
2862
 
 
2863
 
 
2864
  //public void curve(float x1, float y1,
 
2865
  //                  float x2, float y2,
 
2866
  //                  float x3, float y3,
 
2867
  //                  float x4, float y4)
 
2868
 
 
2869
 
 
2870
  //public void curve(float x1, float y1, float z1,
 
2871
  //                  float x2, float y2, float z2,
 
2872
  //                  float x3, float y3, float z3,
 
2873
  //                  float x4, float y4, float z4)
 
2874
 
 
2875
 
 
2876
 
 
2877
  //////////////////////////////////////////////////////////////
 
2878
 
 
2879
  // SMOOTH
 
2880
 
 
2881
 
 
2882
  public void smooth() {
 
2883
    //showMethodWarning("smooth");
 
2884
          s_enableAccurateTextures = true;
 
2885
          smooth = true;
 
2886
  }
 
2887
 
 
2888
 
 
2889
  public void noSmooth() {
 
2890
          s_enableAccurateTextures = false;
 
2891
          smooth = false;
 
2892
  }
 
2893
 
 
2894
 
 
2895
 
 
2896
  //////////////////////////////////////////////////////////////
 
2897
 
 
2898
  // IMAGES
 
2899
 
 
2900
 
 
2901
  //public void imageMode(int mode)
 
2902
 
 
2903
 
 
2904
  //public void image(PImage image, float x, float y)
 
2905
 
 
2906
 
 
2907
  //public void image(PImage image, float x, float y, float c, float d)
 
2908
 
 
2909
 
 
2910
  //public void image(PImage image,
 
2911
  //                  float a, float b, float c, float d,
 
2912
  //                  int u1, int v1, int u2, int v2)
 
2913
 
 
2914
 
 
2915
  //protected void imageImpl(PImage image,
 
2916
  //                         float x1, float y1, float x2, float y2,
 
2917
  //                         int u1, int v1, int u2, int v2)
 
2918
 
 
2919
 
 
2920
 
 
2921
  //////////////////////////////////////////////////////////////
 
2922
 
 
2923
  // SHAPE
 
2924
 
 
2925
 
 
2926
  //public void shapeMode(int mode)
 
2927
 
 
2928
 
 
2929
  //public void shape(PShape shape)
 
2930
 
 
2931
 
 
2932
  //public void shape(PShape shape, float x, float y)
 
2933
 
 
2934
 
 
2935
  //public void shape(PShape shape, float x, float y, float c, float d)
 
2936
 
 
2937
 
 
2938
 
 
2939
  //////////////////////////////////////////////////////////////
 
2940
 
 
2941
  // TEXT SETTINGS
 
2942
 
 
2943
  // Only textModeCheck overridden from PGraphics, no textAlign, textAscent,
 
2944
  // textDescent, textFont, textLeading, textMode, textSize, textWidth
 
2945
 
 
2946
 
 
2947
  protected boolean textModeCheck(int mode) {
 
2948
    return (textMode == MODEL) || (textMode == SCREEN);
 
2949
  }
 
2950
 
 
2951
 
 
2952
 
 
2953
  //////////////////////////////////////////////////////////////
 
2954
 
 
2955
  // TEXT
 
2956
 
 
2957
  // None of the variations of text() are overridden from PGraphics.
 
2958
 
 
2959
 
 
2960
 
 
2961
  //////////////////////////////////////////////////////////////
 
2962
 
 
2963
  // TEXT IMPL
 
2964
 
 
2965
  // Not even the text drawing implementation stuff is overridden.
 
2966
 
 
2967
 
 
2968
 
 
2969
  //////////////////////////////////////////////////////////////
 
2970
 
 
2971
  // MATRIX STACK
 
2972
 
 
2973
 
 
2974
  public void pushMatrix() {
 
2975
    if (matrixStackDepth == MATRIX_STACK_DEPTH) {
 
2976
      throw new RuntimeException(ERROR_PUSHMATRIX_OVERFLOW);
 
2977
    }
 
2978
    modelview.get(matrixStack[matrixStackDepth]);
 
2979
    modelviewInv.get(matrixInvStack[matrixStackDepth]);
 
2980
    matrixStackDepth++;
 
2981
  }
 
2982
 
 
2983
 
 
2984
  public void popMatrix() {
 
2985
    if (matrixStackDepth == 0) {
 
2986
      throw new RuntimeException(ERROR_PUSHMATRIX_UNDERFLOW);
 
2987
    }
 
2988
    matrixStackDepth--;
 
2989
    modelview.set(matrixStack[matrixStackDepth]);
 
2990
    modelviewInv.set(matrixInvStack[matrixStackDepth]);
 
2991
  }
 
2992
 
 
2993
 
 
2994
 
 
2995
  //////////////////////////////////////////////////////////////
 
2996
 
 
2997
  // MATRIX TRANSFORMATIONS
 
2998
 
 
2999
 
 
3000
  public void translate(float tx, float ty) {
 
3001
    translate(tx, ty, 0);
 
3002
  }
 
3003
 
 
3004
 
 
3005
  public void translate(float tx, float ty, float tz) {
 
3006
    forwardTransform.translate(tx, ty, tz);
 
3007
    reverseTransform.invTranslate(tx, ty, tz);
 
3008
  }
 
3009
 
 
3010
 
 
3011
  /**
 
3012
   * Two dimensional rotation. Same as rotateZ (this is identical
 
3013
   * to a 3D rotation along the z-axis) but included for clarity --
 
3014
   * it'd be weird for people drawing 2D graphics to be using rotateZ.
 
3015
   * And they might kick our a-- for the confusion.
 
3016
   */
 
3017
  public void rotate(float angle) {
 
3018
    rotateZ(angle);
 
3019
  }
 
3020
 
 
3021
 
 
3022
  public void rotateX(float angle) {
 
3023
    forwardTransform.rotateX(angle);
 
3024
    reverseTransform.invRotateX(angle);
 
3025
  }
 
3026
 
 
3027
 
 
3028
  public void rotateY(float angle) {
 
3029
    forwardTransform.rotateY(angle);
 
3030
    reverseTransform.invRotateY(angle);
 
3031
  }
 
3032
 
 
3033
 
 
3034
  public void rotateZ(float angle) {
 
3035
    forwardTransform.rotateZ(angle);
 
3036
    reverseTransform.invRotateZ(angle);
 
3037
  }
 
3038
 
 
3039
 
 
3040
  /**
 
3041
   * Rotate around an arbitrary vector, similar to glRotate(),
 
3042
   * except that it takes radians (instead of degrees).
 
3043
   */
 
3044
  public void rotate(float angle, float v0, float v1, float v2) {
 
3045
    forwardTransform.rotate(angle, v0, v1, v2);
 
3046
    reverseTransform.invRotate(angle, v0, v1, v2);
 
3047
  }
 
3048
 
 
3049
 
 
3050
  /**
 
3051
   * Same as scale(s, s, s).
 
3052
   */
 
3053
  public void scale(float s) {
 
3054
    scale(s, s, s);
 
3055
  }
 
3056
 
 
3057
 
 
3058
  /**
 
3059
   * Same as scale(sx, sy, 1).
 
3060
   */
 
3061
  public void scale(float sx, float sy) {
 
3062
    scale(sx, sy, 1);
 
3063
  }
 
3064
 
 
3065
 
 
3066
  /**
 
3067
   * Scale in three dimensions.
 
3068
   */
 
3069
  public void scale(float x, float y, float z) {
 
3070
    forwardTransform.scale(x, y, z);
 
3071
    reverseTransform.invScale(x, y, z);
 
3072
  }
 
3073
 
 
3074
 
 
3075
 
 
3076
  //////////////////////////////////////////////////////////////
 
3077
 
 
3078
  // MATRIX MORE!
 
3079
 
 
3080
 
 
3081
  public void resetMatrix() {
 
3082
    forwardTransform.reset();
 
3083
    reverseTransform.reset();
 
3084
  }
 
3085
 
 
3086
 
 
3087
  public void applyMatrix(PMatrix2D source) {
 
3088
    applyMatrix(source.m00, source.m01, source.m02,
 
3089
                source.m10, source.m11, source.m12);
 
3090
  }
 
3091
 
 
3092
 
 
3093
  public void applyMatrix(float n00, float n01, float n02,
 
3094
                          float n10, float n11, float n12) {
 
3095
    applyMatrix(n00, n01, n02, 0,
 
3096
                n10, n11, n12, 0,
 
3097
                0,   0,   1,   0,
 
3098
                0,   0,   0,   1);
 
3099
  }
 
3100
 
 
3101
 
 
3102
  public void applyMatrix(PMatrix3D source) {
 
3103
    applyMatrix(source.m00, source.m01, source.m02, source.m03,
 
3104
                source.m10, source.m11, source.m12, source.m13,
 
3105
                source.m20, source.m21, source.m22, source.m23,
 
3106
                source.m30, source.m31, source.m32, source.m33);
 
3107
  }
 
3108
 
 
3109
 
 
3110
  /**
 
3111
   * Apply a 4x4 transformation matrix. Same as glMultMatrix().
 
3112
   * This call will be slow because it will try to calculate the
 
3113
   * inverse of the transform. So avoid it whenever possible.
 
3114
   */
 
3115
  public void applyMatrix(float n00, float n01, float n02, float n03,
 
3116
                          float n10, float n11, float n12, float n13,
 
3117
                          float n20, float n21, float n22, float n23,
 
3118
                          float n30, float n31, float n32, float n33) {
 
3119
 
 
3120
    forwardTransform.apply(n00, n01, n02, n03,
 
3121
                           n10, n11, n12, n13,
 
3122
                           n20, n21, n22, n23,
 
3123
                           n30, n31, n32, n33);
 
3124
 
 
3125
    reverseTransform.invApply(n00, n01, n02, n03,
 
3126
                              n10, n11, n12, n13,
 
3127
                              n20, n21, n22, n23,
 
3128
                              n30, n31, n32, n33);
 
3129
  }
 
3130
 
 
3131
 
 
3132
 
 
3133
  //////////////////////////////////////////////////////////////
 
3134
 
 
3135
  // MATRIX GET/SET/PRINT
 
3136
 
 
3137
 
 
3138
  public PMatrix getMatrix() {
 
3139
    return modelview.get();
 
3140
  }
 
3141
 
 
3142
 
 
3143
  //public PMatrix2D getMatrix(PMatrix2D target)
 
3144
 
 
3145
 
 
3146
  public PMatrix3D getMatrix(PMatrix3D target) {
 
3147
    if (target == null) {
 
3148
      target = new PMatrix3D();
 
3149
    }
 
3150
    target.set(modelview);
 
3151
    return target;
 
3152
  }
 
3153
 
 
3154
 
 
3155
  //public void setMatrix(PMatrix source)
 
3156
 
 
3157
 
 
3158
  public void setMatrix(PMatrix2D source) {
 
3159
    // not efficient, but at least handles the inverse stuff.
 
3160
    resetMatrix();
 
3161
    applyMatrix(source);
 
3162
  }
 
3163
 
 
3164
 
 
3165
  /**
 
3166
   * Set the current transformation to the contents of the specified source.
 
3167
   */
 
3168
  public void setMatrix(PMatrix3D source) {
 
3169
    // not efficient, but at least handles the inverse stuff.
 
3170
    resetMatrix();
 
3171
    applyMatrix(source);
 
3172
  }
 
3173
 
 
3174
 
 
3175
  /**
 
3176
   * Print the current model (or "transformation") matrix.
 
3177
   */
 
3178
  public void printMatrix() {
 
3179
    modelview.print();
 
3180
  }
 
3181
 
 
3182
 
 
3183
  /*
 
3184
   * This function checks if the modelview matrix is set up to likely be
 
3185
   * drawing in 2D. It merely checks if the non-translational piece of the
 
3186
   * matrix is unity. If this is to be used, it should be coupled with a
 
3187
   * check that the raw vertex coordinates lie in the z=0 plane.
 
3188
   * Mainly useful for applying sub-pixel shifts to avoid 2d artifacts
 
3189
   * in the screen plane.
 
3190
   * Added by ewjordan 6/13/07
 
3191
   *
 
3192
   * TODO need to invert the logic here so that we can simply return
 
3193
   * the value, rather than calculating true/false and returning it.
 
3194
   */
 
3195
  /*
 
3196
  private boolean drawing2D() {
 
3197
    if (modelview.m00 != 1.0f ||
 
3198
        modelview.m11 != 1.0f ||
 
3199
        modelview.m22 != 1.0f || // check scale
 
3200
        modelview.m01 != 0.0f ||
 
3201
        modelview.m02 != 0.0f || // check rotational pieces
 
3202
        modelview.m10 != 0.0f ||
 
3203
        modelview.m12 != 0.0f ||
 
3204
        modelview.m20 != 0.0f ||
 
3205
        modelview.m21 != 0.0f ||
 
3206
        !((camera.m23-modelview.m23) <= EPSILON &&
 
3207
          (camera.m23-modelview.m23) >= -EPSILON)) { // check for z-translation
 
3208
      // Something about the modelview matrix indicates 3d drawing
 
3209
      // (or rotated 2d, in which case 2d subpixel fixes probably aren't needed)
 
3210
      return false;
 
3211
    } else {
 
3212
      //The matrix is mapping z=0 vertices to the screen plane,
 
3213
      // which means it's likely that 2D drawing is happening.
 
3214
      return true;
 
3215
    }
 
3216
  }
 
3217
  */
 
3218
 
 
3219
 
 
3220
 
 
3221
  //////////////////////////////////////////////////////////////
 
3222
 
 
3223
  // CAMERA
 
3224
 
 
3225
 
 
3226
  /**
 
3227
   * Set matrix mode to the camera matrix (instead of the current
 
3228
   * transformation matrix). This means applyMatrix, resetMatrix, etc.
 
3229
   * will affect the camera.
 
3230
   * <P>
 
3231
   * Note that the camera matrix is *not* the perspective matrix,
 
3232
   * it is in front of the modelview matrix (hence the name "model"
 
3233
   * and "view" for that matrix).
 
3234
   * <P>
 
3235
   * beginCamera() specifies that all coordinate transforms until endCamera()
 
3236
   * should be pre-applied in inverse to the camera transform matrix.
 
3237
   * Note that this is only challenging when a user specifies an arbitrary
 
3238
   * matrix with applyMatrix(). Then that matrix will need to be inverted,
 
3239
   * which may not be possible. But take heart, if a user is applying a
 
3240
   * non-invertible matrix to the camera transform, then he is clearly
 
3241
   * up to no good, and we can wash our hands of those bad intentions.
 
3242
   * <P>
 
3243
   * begin/endCamera clauses do not automatically reset the camera transform
 
3244
   * matrix. That's because we set up a nice default camera transform int
 
3245
   * setup(), and we expect it to hold through draw(). So we don't reset
 
3246
   * the camera transform matrix at the top of draw(). That means that an
 
3247
   * innocuous-looking clause like
 
3248
   * <PRE>
 
3249
   * beginCamera();
 
3250
   * translate(0, 0, 10);
 
3251
   * endCamera();
 
3252
   * </PRE>
 
3253
   * at the top of draw(), will result in a runaway camera that shoots
 
3254
   * infinitely out of the screen over time. In order to prevent this,
 
3255
   * it is necessary to call some function that does a hard reset of the
 
3256
   * camera transform matrix inside of begin/endCamera. Two options are
 
3257
   * <PRE>
 
3258
   * camera(); // sets up the nice default camera transform
 
3259
   * resetMatrix(); // sets up the identity camera transform
 
3260
   * </PRE>
 
3261
   * So to rotate a camera a constant amount, you might try
 
3262
   * <PRE>
 
3263
   * beginCamera();
 
3264
   * camera();
 
3265
   * rotateY(PI/8);
 
3266
   * endCamera();
 
3267
   * </PRE>
 
3268
   */
 
3269
  public void beginCamera() {
 
3270
    if (manipulatingCamera) {
 
3271
      throw new RuntimeException("beginCamera() cannot be called again " +
 
3272
                                 "before endCamera()");
 
3273
    } else {
 
3274
      manipulatingCamera = true;
 
3275
      forwardTransform = cameraInv;
 
3276
      reverseTransform = camera;
 
3277
    }
 
3278
  }
 
3279
 
 
3280
 
 
3281
  /**
 
3282
   * Record the current settings into the camera matrix, and set
 
3283
   * the matrix mode back to the current transformation matrix.
 
3284
   * <P>
 
3285
   * Note that this will destroy any settings to scale(), translate(),
 
3286
   * or whatever, because the final camera matrix will be copied
 
3287
   * (not multiplied) into the modelview.
 
3288
   */
 
3289
  public void endCamera() {
 
3290
    if (!manipulatingCamera) {
 
3291
      throw new RuntimeException("Cannot call endCamera() " +
 
3292
                                 "without first calling beginCamera()");
 
3293
    }
 
3294
    // reset the modelview to use this new camera matrix
 
3295
    modelview.set(camera);
 
3296
    modelviewInv.set(cameraInv);
 
3297
 
 
3298
    // set matrix mode back to modelview
 
3299
    forwardTransform = modelview;
 
3300
    reverseTransform = modelviewInv;
 
3301
 
 
3302
    // all done
 
3303
    manipulatingCamera = false;
 
3304
  }
 
3305
 
 
3306
 
 
3307
  /**
 
3308
   * Set camera to the default settings.
 
3309
   * <P>
 
3310
   * Processing camera behavior:
 
3311
   * <P>
 
3312
   * Camera behavior can be split into two separate components, camera
 
3313
   * transformation, and projection. The transformation corresponds to the
 
3314
   * physical location, orientation, and scale of the camera. In a physical
 
3315
   * camera metaphor, this is what can manipulated by handling the camera
 
3316
   * body (with the exception of scale, which doesn't really have a physcial
 
3317
   * analog). The projection corresponds to what can be changed by
 
3318
   * manipulating the lens.
 
3319
   * <P>
 
3320
   * We maintain separate matrices to represent the camera transform and
 
3321
   * projection. An important distinction between the two is that the camera
 
3322
   * transform should be invertible, where the projection matrix should not,
 
3323
   * since it serves to map three dimensions to two. It is possible to bake
 
3324
   * the two matrices into a single one just by multiplying them together,
 
3325
   * but it isn't a good idea, since lighting, z-ordering, and z-buffering
 
3326
   * all demand a true camera z coordinate after modelview and camera
 
3327
   * transforms have been applied but before projection. If the camera
 
3328
   * transform and projection are combined there is no way to recover a
 
3329
   * good camera-space z-coordinate from a model coordinate.
 
3330
   * <P>
 
3331
   * Fortunately, there are no functions that manipulate both camera
 
3332
   * transformation and projection.
 
3333
   * <P>
 
3334
   * camera() sets the camera position, orientation, and center of the scene.
 
3335
   * It replaces the camera transform with a new one. This is different from
 
3336
   * gluLookAt(), but I think the only reason that GLU's lookat doesn't fully
 
3337
   * replace the camera matrix with the new one, but instead multiplies it,
 
3338
   * is that GL doesn't enforce the separation of camera transform and
 
3339
   * projection, so it wouldn't be safe (you'd probably stomp your projection).
 
3340
   * <P>
 
3341
   * The transformation functions are the same ones used to manipulate the
 
3342
   * modelview matrix (scale, translate, rotate, etc.). But they are bracketed
 
3343
   * with beginCamera(), endCamera() to indicate that they should apply
 
3344
   * (in inverse), to the camera transformation matrix.
 
3345
   * <P>
 
3346
   * This differs considerably from camera transformation in OpenGL.
 
3347
   * OpenGL only lets you say, apply everything from here out to the
 
3348
   * projection or modelview matrix. This makes it very hard to treat camera
 
3349
   * manipulation as if it were a physical camera. Imagine that you want to
 
3350
   * move your camera 100 units forward. In OpenGL, you need to apply the
 
3351
   * inverse of that transformation or else you'll move your scene 100 units
 
3352
   * forward--whether or not you've specified modelview or projection matrix.
 
3353
   * Remember they're just multiplied by model coods one after another.
 
3354
   * So in order to treat a camera like a physical camera, it is necessary
 
3355
   * to pre-apply inverse transforms to a matrix that will be applied to model
 
3356
   * coordinates. OpenGL provides nothing of this sort, but Processing does!
 
3357
   * This is the camera transform matrix.
 
3358
   */
 
3359
  public void camera() {
 
3360
    camera(cameraX, cameraY, cameraZ,
 
3361
           cameraX, cameraY, 0,
 
3362
           0, 1, 0);
 
3363
  }
 
3364
 
 
3365
 
 
3366
  /**
 
3367
   * More flexible method for dealing with camera().
 
3368
   * <P>
 
3369
   * The actual call is like gluLookat. Here's the real skinny on
 
3370
   * what does what:
 
3371
   * <PRE>
 
3372
   * camera(); or
 
3373
   * camera(ex, ey, ez, cx, cy, cz, ux, uy, uz);
 
3374
   * </PRE>
 
3375
   * do not need to be called from with beginCamera();/endCamera();
 
3376
   * That's because they always apply to the camera transformation,
 
3377
   * and they always totally replace it. That means that any coordinate
 
3378
   * transforms done before camera(); in draw() will be wiped out.
 
3379
   * It also means that camera() always operates in untransformed world
 
3380
   * coordinates. Therefore it is always redundant to call resetMatrix();
 
3381
   * before camera(); This isn't technically true of gluLookat, but it's
 
3382
   * pretty much how it's used.
 
3383
   * <P>
 
3384
   * Now, beginCamera(); and endCamera(); are useful if you want to move
 
3385
   * the camera around using transforms like translate(), etc. They will
 
3386
   * wipe out any coordinate system transforms that occur before them in
 
3387
   * draw(), but they will not automatically wipe out the camera transform.
 
3388
   * This means that they should be at the top of draw(). It also means
 
3389
   * that the following:
 
3390
   * <PRE>
 
3391
   * beginCamera();
 
3392
   * rotateY(PI/8);
 
3393
   * endCamera();
 
3394
   * </PRE>
 
3395
   * will result in a camera that spins without stopping. If you want to
 
3396
   * just rotate a small constant amount, try this:
 
3397
   * <PRE>
 
3398
   * beginCamera();
 
3399
   * camera(); // sets up the default view
 
3400
   * rotateY(PI/8);
 
3401
   * endCamera();
 
3402
   * </PRE>
 
3403
   * That will rotate a little off of the default view. Note that this
 
3404
   * is entirely equivalent to
 
3405
   * <PRE>
 
3406
   * camera(); // sets up the default view
 
3407
   * beginCamera();
 
3408
   * rotateY(PI/8);
 
3409
   * endCamera();
 
3410
   * </PRE>
 
3411
   * because camera() doesn't care whether or not it's inside a
 
3412
   * begin/end clause. Basically it's safe to use camera() or
 
3413
   * camera(ex, ey, ez, cx, cy, cz, ux, uy, uz) as naked calls because
 
3414
   * they do all the matrix resetting automatically.
 
3415
   */
 
3416
  public void camera(float eyeX, float eyeY, float eyeZ,
 
3417
                     float centerX, float centerY, float centerZ,
 
3418
                     float upX, float upY, float upZ) {
 
3419
    float z0 = eyeX - centerX;
 
3420
    float z1 = eyeY - centerY;
 
3421
    float z2 = eyeZ - centerZ;
 
3422
    float mag = sqrt(z0*z0 + z1*z1 + z2*z2);
 
3423
 
 
3424
    if (mag != 0) {
 
3425
      z0 /= mag;
 
3426
      z1 /= mag;
 
3427
      z2 /= mag;
 
3428
    }
 
3429
 
 
3430
    float y0 = upX;
 
3431
    float y1 = upY;
 
3432
    float y2 = upZ;
 
3433
 
 
3434
    float x0 =  y1*z2 - y2*z1;
 
3435
    float x1 = -y0*z2 + y2*z0;
 
3436
    float x2 =  y0*z1 - y1*z0;
 
3437
 
 
3438
    y0 =  z1*x2 - z2*x1;
 
3439
    y1 = -z0*x2 + z2*x0;
 
3440
    y2 =  z0*x1 - z1*x0;
 
3441
 
 
3442
    mag = sqrt(x0*x0 + x1*x1 + x2*x2);
 
3443
    if (mag != 0) {
 
3444
      x0 /= mag;
 
3445
      x1 /= mag;
 
3446
      x2 /= mag;
 
3447
    }
 
3448
 
 
3449
    mag = sqrt(y0*y0 + y1*y1 + y2*y2);
 
3450
    if (mag != 0) {
 
3451
      y0 /= mag;
 
3452
      y1 /= mag;
 
3453
      y2 /= mag;
 
3454
    }
 
3455
 
 
3456
    // just does an apply to the main matrix,
 
3457
    // since that'll be copied out on endCamera
 
3458
    camera.set(x0, x1, x2, 0,
 
3459
               y0, y1, y2, 0,
 
3460
               z0, z1, z2, 0,
 
3461
               0,  0,  0,  1);
 
3462
    camera.translate(-eyeX, -eyeY, -eyeZ);
 
3463
 
 
3464
    cameraInv.reset();
 
3465
    cameraInv.invApply(x0, x1, x2, 0,
 
3466
                       y0, y1, y2, 0,
 
3467
                       z0, z1, z2, 0,
 
3468
                       0,  0,  0,  1);
 
3469
    cameraInv.translate(eyeX, eyeY, eyeZ);
 
3470
 
 
3471
    modelview.set(camera);
 
3472
    modelviewInv.set(cameraInv);
 
3473
  }
 
3474
 
 
3475
 
 
3476
  /**
 
3477
   * Print the current camera matrix.
 
3478
   */
 
3479
  public void printCamera() {
 
3480
    camera.print();
 
3481
  }
 
3482
 
 
3483
 
 
3484
  //////////////////////////////////////////////////////////////
 
3485
 
 
3486
  // PROJECTION
 
3487
 
 
3488
 
 
3489
  /**
 
3490
   * Calls ortho() with the proper parameters for Processing's
 
3491
   * standard orthographic projection.
 
3492
   */
 
3493
  public void ortho() {
 
3494
    ortho(0, width, 0, height, -10, 10);
 
3495
  }
 
3496
 
 
3497
 
 
3498
  /**
 
3499
   * Similar to gluOrtho(), but wipes out the current projection matrix.
 
3500
   * <P>
 
3501
   * Implementation partially based on Mesa's matrix.c.
 
3502
   */
 
3503
  public void ortho(float left, float right,
 
3504
                    float bottom, float top,
 
3505
                    float near, float far) {
 
3506
    float x =  2.0f / (right - left);
 
3507
    float y =  2.0f / (top - bottom);
 
3508
    float z = -2.0f / (far - near);
 
3509
 
 
3510
    float tx = -(right + left) / (right - left);
 
3511
    float ty = -(top + bottom) / (top - bottom);
 
3512
    float tz = -(far + near) / (far - near);
 
3513
 
 
3514
    projection.set(x, 0, 0, tx,
 
3515
                   0, y, 0, ty,
 
3516
                   0, 0, z, tz,
 
3517
                   0, 0, 0, 1);
 
3518
    updateProjection();
 
3519
 
 
3520
    frustumMode = false;
 
3521
  }
 
3522
 
 
3523
 
 
3524
  /**
 
3525
   * Calls perspective() with Processing's standard coordinate projection.
 
3526
   * <P>
 
3527
   * Projection functions:
 
3528
   * <UL>
 
3529
   * <LI>frustrum()
 
3530
   * <LI>ortho()
 
3531
   * <LI>perspective()
 
3532
   * </UL>
 
3533
   * Each of these three functions completely replaces the projection
 
3534
   * matrix with a new one. They can be called inside setup(), and their
 
3535
   * effects will be felt inside draw(). At the top of draw(), the projection
 
3536
   * matrix is not reset. Therefore the last projection function to be
 
3537
   * called always dominates. On resize, the default projection is always
 
3538
   * established, which has perspective.
 
3539
   * <P>
 
3540
   * This behavior is pretty much familiar from OpenGL, except where
 
3541
   * functions replace matrices, rather than multiplying against the
 
3542
   * previous.
 
3543
   * <P>
 
3544
   */
 
3545
  public void perspective() {
 
3546
    perspective(cameraFOV, cameraAspect, cameraNear, cameraFar);
 
3547
  }
 
3548
 
 
3549
 
 
3550
  /**
 
3551
   * Similar to gluPerspective(). Implementation based on Mesa's glu.c
 
3552
   */
 
3553
  public void perspective(float fov, float aspect, float zNear, float zFar) {
 
3554
    //float ymax = zNear * tan(fovy * PI / 360.0f);
 
3555
    float ymax = zNear * (float) Math.tan(fov / 2);
 
3556
    float ymin = -ymax;
 
3557
 
 
3558
    float xmin = ymin * aspect;
 
3559
    float xmax = ymax * aspect;
 
3560
 
 
3561
    frustum(xmin, xmax, ymin, ymax, zNear, zFar);
 
3562
  }
 
3563
 
 
3564
 
 
3565
  /**
 
3566
   * Same as glFrustum(), except that it wipes out (rather than
 
3567
   * multiplies against) the current perspective matrix.
 
3568
   * <P>
 
3569
   * Implementation based on the explanation in the OpenGL blue book.
 
3570
   */
 
3571
  public void frustum(float left, float right, float bottom,
 
3572
                      float top, float znear, float zfar) {
 
3573
 
 
3574
    leftScreen = left;
 
3575
    rightScreen = right;
 
3576
    bottomScreen = bottom;
 
3577
    topScreen = top;
 
3578
    nearPlane = znear;
 
3579
    frustumMode = true;
 
3580
 
 
3581
    //System.out.println(projection);
 
3582
    projection.set((2*znear)/(right-left), 0, (right+left)/(right-left), 0,
 
3583
                   0, (2*znear)/(top-bottom), (top+bottom)/(top-bottom), 0,
 
3584
                   0, 0, -(zfar+znear)/(zfar-znear),-(2*zfar*znear)/(zfar-znear),
 
3585
                   0, 0, -1, 0);
 
3586
    updateProjection();
 
3587
  }
 
3588
 
 
3589
 
 
3590
  /** Called after the 'projection' PMatrix3D has changed. */
 
3591
  protected void updateProjection() {
 
3592
  }
 
3593
 
 
3594
 
 
3595
  /**
 
3596
   * Print the current projection matrix.
 
3597
   */
 
3598
  public void printProjection() {
 
3599
    projection.print();
 
3600
  }
 
3601
 
 
3602
 
 
3603
 
 
3604
  //////////////////////////////////////////////////////////////
 
3605
 
 
3606
  // SCREEN AND MODEL COORDS
 
3607
 
 
3608
 
 
3609
  public float screenX(float x, float y) {
 
3610
    return screenX(x, y, 0);
 
3611
  }
 
3612
 
 
3613
 
 
3614
  public float screenY(float x, float y) {
 
3615
    return screenY(x, y, 0);
 
3616
  }
 
3617
 
 
3618
 
 
3619
  public float screenX(float x, float y, float z) {
 
3620
    float ax =
 
3621
      modelview.m00*x + modelview.m01*y + modelview.m02*z + modelview.m03;
 
3622
    float ay =
 
3623
      modelview.m10*x + modelview.m11*y + modelview.m12*z + modelview.m13;
 
3624
    float az =
 
3625
      modelview.m20*x + modelview.m21*y + modelview.m22*z + modelview.m23;
 
3626
    float aw =
 
3627
      modelview.m30*x + modelview.m31*y + modelview.m32*z + modelview.m33;
 
3628
 
 
3629
    float ox =
 
3630
      projection.m00*ax + projection.m01*ay +
 
3631
      projection.m02*az + projection.m03*aw;
 
3632
    float ow =
 
3633
      projection.m30*ax + projection.m31*ay +
 
3634
      projection.m32*az + projection.m33*aw;
 
3635
 
 
3636
    if (ow != 0) ox /= ow;
 
3637
    return width * (1 + ox) / 2.0f;
 
3638
  }
 
3639
 
 
3640
 
 
3641
  public float screenY(float x, float y, float z) {
 
3642
    float ax =
 
3643
      modelview.m00*x + modelview.m01*y + modelview.m02*z + modelview.m03;
 
3644
    float ay =
 
3645
      modelview.m10*x + modelview.m11*y + modelview.m12*z + modelview.m13;
 
3646
    float az =
 
3647
      modelview.m20*x + modelview.m21*y + modelview.m22*z + modelview.m23;
 
3648
    float aw =
 
3649
      modelview.m30*x + modelview.m31*y + modelview.m32*z + modelview.m33;
 
3650
 
 
3651
    float oy =
 
3652
      projection.m10*ax + projection.m11*ay +
 
3653
      projection.m12*az + projection.m13*aw;
 
3654
    float ow =
 
3655
      projection.m30*ax + projection.m31*ay +
 
3656
      projection.m32*az + projection.m33*aw;
 
3657
 
 
3658
    if (ow != 0) oy /= ow;
 
3659
    return height * (1 + oy) / 2.0f;
 
3660
  }
 
3661
 
 
3662
 
 
3663
  public float screenZ(float x, float y, float z) {
 
3664
    float ax =
 
3665
      modelview.m00*x + modelview.m01*y + modelview.m02*z + modelview.m03;
 
3666
    float ay =
 
3667
      modelview.m10*x + modelview.m11*y + modelview.m12*z + modelview.m13;
 
3668
    float az =
 
3669
      modelview.m20*x + modelview.m21*y + modelview.m22*z + modelview.m23;
 
3670
    float aw =
 
3671
      modelview.m30*x + modelview.m31*y + modelview.m32*z + modelview.m33;
 
3672
 
 
3673
    float oz =
 
3674
      projection.m20*ax + projection.m21*ay +
 
3675
      projection.m22*az + projection.m23*aw;
 
3676
    float ow =
 
3677
      projection.m30*ax + projection.m31*ay +
 
3678
      projection.m32*az + projection.m33*aw;
 
3679
 
 
3680
    if (ow != 0) oz /= ow;
 
3681
    return (oz + 1) / 2.0f;
 
3682
  }
 
3683
 
 
3684
 
 
3685
  public float modelX(float x, float y, float z) {
 
3686
    float ax =
 
3687
      modelview.m00*x + modelview.m01*y + modelview.m02*z + modelview.m03;
 
3688
    float ay =
 
3689
      modelview.m10*x + modelview.m11*y + modelview.m12*z + modelview.m13;
 
3690
    float az =
 
3691
      modelview.m20*x + modelview.m21*y + modelview.m22*z + modelview.m23;
 
3692
    float aw =
 
3693
      modelview.m30*x + modelview.m31*y + modelview.m32*z + modelview.m33;
 
3694
 
 
3695
    float ox =
 
3696
      cameraInv.m00*ax + cameraInv.m01*ay +
 
3697
      cameraInv.m02*az + cameraInv.m03*aw;
 
3698
    float ow =
 
3699
      cameraInv.m30*ax + cameraInv.m31*ay +
 
3700
      cameraInv.m32*az + cameraInv.m33*aw;
 
3701
 
 
3702
    return (ow != 0) ? ox / ow : ox;
 
3703
  }
 
3704
 
 
3705
 
 
3706
  public float modelY(float x, float y, float z) {
 
3707
    float ax =
 
3708
      modelview.m00*x + modelview.m01*y + modelview.m02*z + modelview.m03;
 
3709
    float ay =
 
3710
      modelview.m10*x + modelview.m11*y + modelview.m12*z + modelview.m13;
 
3711
    float az =
 
3712
      modelview.m20*x + modelview.m21*y + modelview.m22*z + modelview.m23;
 
3713
    float aw =
 
3714
      modelview.m30*x + modelview.m31*y + modelview.m32*z + modelview.m33;
 
3715
 
 
3716
    float oy =
 
3717
      cameraInv.m10*ax + cameraInv.m11*ay +
 
3718
      cameraInv.m12*az + cameraInv.m13*aw;
 
3719
    float ow =
 
3720
      cameraInv.m30*ax + cameraInv.m31*ay +
 
3721
      cameraInv.m32*az + cameraInv.m33*aw;
 
3722
 
 
3723
    return (ow != 0) ? oy / ow : oy;
 
3724
  }
 
3725
 
 
3726
 
 
3727
  public float modelZ(float x, float y, float z) {
 
3728
    float ax =
 
3729
      modelview.m00*x + modelview.m01*y + modelview.m02*z + modelview.m03;
 
3730
    float ay =
 
3731
      modelview.m10*x + modelview.m11*y + modelview.m12*z + modelview.m13;
 
3732
    float az =
 
3733
      modelview.m20*x + modelview.m21*y + modelview.m22*z + modelview.m23;
 
3734
    float aw =
 
3735
      modelview.m30*x + modelview.m31*y + modelview.m32*z + modelview.m33;
 
3736
 
 
3737
    float oz =
 
3738
      cameraInv.m20*ax + cameraInv.m21*ay +
 
3739
      cameraInv.m22*az + cameraInv.m23*aw;
 
3740
    float ow =
 
3741
      cameraInv.m30*ax + cameraInv.m31*ay +
 
3742
      cameraInv.m32*az + cameraInv.m33*aw;
 
3743
 
 
3744
    return (ow != 0) ? oz / ow : oz;
 
3745
  }
 
3746
 
 
3747
 
 
3748
 
 
3749
  //////////////////////////////////////////////////////////////
 
3750
 
 
3751
  // STYLE
 
3752
 
 
3753
  // pushStyle(), popStyle(), style() and getStyle() inherited.
 
3754
 
 
3755
 
 
3756
 
 
3757
  //////////////////////////////////////////////////////////////
 
3758
 
 
3759
  // STROKE CAP/JOIN/WEIGHT
 
3760
 
 
3761
 
 
3762
//  public void strokeWeight(float weight) {
 
3763
//    if (weight != DEFAULT_STROKE_WEIGHT) {
 
3764
//      showMethodWarning("strokeWeight");
 
3765
//    }
 
3766
//  }
 
3767
 
 
3768
 
 
3769
  public void strokeJoin(int join) {
 
3770
    if (join != DEFAULT_STROKE_JOIN) {
 
3771
      showMethodWarning("strokeJoin");
 
3772
    }
 
3773
  }
 
3774
 
 
3775
 
 
3776
  public void strokeCap(int cap) {
 
3777
    if (cap != DEFAULT_STROKE_CAP) {
 
3778
      showMethodWarning("strokeCap");
 
3779
    }
 
3780
  }
 
3781
 
 
3782
 
 
3783
 
 
3784
  //////////////////////////////////////////////////////////////
 
3785
 
 
3786
  // STROKE COLOR
 
3787
 
 
3788
  // All methods inherited from PGraphics.
 
3789
 
 
3790
 
 
3791
 
 
3792
  //////////////////////////////////////////////////////////////
 
3793
 
 
3794
  // TINT COLOR
 
3795
 
 
3796
  // All methods inherited from PGraphics.
 
3797
 
 
3798
 
 
3799
 
 
3800
  //////////////////////////////////////////////////////////////
 
3801
 
 
3802
  // FILL COLOR
 
3803
 
 
3804
 
 
3805
  protected void fillFromCalc() {
 
3806
    super.fillFromCalc();
 
3807
    ambientFromCalc();
 
3808
  }
 
3809
 
 
3810
 
 
3811
 
 
3812
  //////////////////////////////////////////////////////////////
 
3813
 
 
3814
  // MATERIAL PROPERTIES
 
3815
 
 
3816
  // ambient, specular, shininess, and emissive all inherited.
 
3817
 
 
3818
 
 
3819
 
 
3820
  //////////////////////////////////////////////////////////////
 
3821
 
 
3822
  // LIGHTS
 
3823
 
 
3824
 
 
3825
  PVector lightPositionVec = new PVector();
 
3826
  PVector lightDirectionVec = new PVector();
 
3827
 
 
3828
  /**
 
3829
   * Sets up an ambient and directional light.
 
3830
   * <PRE>
 
3831
   * The Lighting Skinny:
 
3832
   *
 
3833
   * The way lighting works is complicated enough that it's worth
 
3834
   * producing a document to describe it. Lighting calculations proceed
 
3835
   * pretty much exactly as described in the OpenGL red book.
 
3836
   *
 
3837
   * Light-affecting material properties:
 
3838
   *
 
3839
   *   AMBIENT COLOR
 
3840
   *   - multiplies by light's ambient component
 
3841
   *   - for believability this should match diffuse color
 
3842
   *
 
3843
   *   DIFFUSE COLOR
 
3844
   *   - multiplies by light's diffuse component
 
3845
   *
 
3846
   *   SPECULAR COLOR
 
3847
   *   - multiplies by light's specular component
 
3848
   *   - usually less colored than diffuse/ambient
 
3849
   *
 
3850
   *   SHININESS
 
3851
   *   - the concentration of specular effect
 
3852
   *   - this should be set pretty high (20-50) to see really
 
3853
   *     noticeable specularity
 
3854
   *
 
3855
   *   EMISSIVE COLOR
 
3856
   *   - constant additive color effect
 
3857
   *
 
3858
   * Light types:
 
3859
   *
 
3860
   *   AMBIENT
 
3861
   *   - one color
 
3862
   *   - no specular color
 
3863
   *   - no direction
 
3864
   *   - may have falloff (constant, linear, and quadratic)
 
3865
   *   - may have position (which matters in non-constant falloff case)
 
3866
   *   - multiplies by a material's ambient reflection
 
3867
   *
 
3868
   *   DIRECTIONAL
 
3869
   *   - has diffuse color
 
3870
   *   - has specular color
 
3871
   *   - has direction
 
3872
   *   - no position
 
3873
   *   - no falloff
 
3874
   *   - multiplies by a material's diffuse and specular reflections
 
3875
   *
 
3876
   *   POINT
 
3877
   *   - has diffuse color
 
3878
   *   - has specular color
 
3879
   *   - has position
 
3880
   *   - no direction
 
3881
   *   - may have falloff (constant, linear, and quadratic)
 
3882
   *   - multiplies by a material's diffuse and specular reflections
 
3883
   *
 
3884
   *   SPOT
 
3885
   *   - has diffuse color
 
3886
   *   - has specular color
 
3887
   *   - has position
 
3888
   *   - has direction
 
3889
   *   - has cone angle (set to half the total cone angle)
 
3890
   *   - has concentration value
 
3891
   *   - may have falloff (constant, linear, and quadratic)
 
3892
   *   - multiplies by a material's diffuse and specular reflections
 
3893
   *
 
3894
   * Normal modes:
 
3895
   *
 
3896
   * All of the primitives (rect, box, sphere, etc.) have their normals
 
3897
   * set nicely. During beginShape/endShape normals can be set by the user.
 
3898
   *
 
3899
   *   AUTO-NORMAL
 
3900
   *   - if no normal is set during the shape, we are in auto-normal mode
 
3901
   *   - auto-normal calculates one normal per triangle (face-normal mode)
 
3902
   *
 
3903
   *   SHAPE-NORMAL
 
3904
   *   - if one normal is set during the shape, it will be used for
 
3905
   *     all vertices
 
3906
   *
 
3907
   *   VERTEX-NORMAL
 
3908
   *   - if multiple normals are set, each normal applies to
 
3909
   *     subsequent vertices
 
3910
   *   - (except for the first one, which applies to previous
 
3911
   *     and subsequent vertices)
 
3912
   *
 
3913
   * Efficiency consequences:
 
3914
   *
 
3915
   *   There is a major efficiency consequence of position-dependent
 
3916
   *   lighting calculations per vertex. (See below for determining
 
3917
   *   whether lighting is vertex position-dependent.) If there is no
 
3918
   *   position dependency then the only factors that affect the lighting
 
3919
   *   contribution per vertex are its colors and its normal.
 
3920
   *   There is a major efficiency win if
 
3921
   *
 
3922
   *   1) lighting is not position dependent
 
3923
   *   2) we are in AUTO-NORMAL or SHAPE-NORMAL mode
 
3924
   *
 
3925
   *   because then we can calculate one lighting contribution per shape
 
3926
   *   (SHAPE-NORMAL) or per triangle (AUTO-NORMAL) and simply multiply it
 
3927
   *   into the vertex colors. The converse is our worst-case performance when
 
3928
   *
 
3929
   *   1) lighting is position dependent
 
3930
   *   2) we are in AUTO-NORMAL mode
 
3931
   *
 
3932
   *   because then we must calculate lighting per-face * per-vertex.
 
3933
   *   Each vertex has a different lighting contribution per face in
 
3934
   *   which it appears. Yuck.
 
3935
   *
 
3936
   * Determining vertex position dependency:
 
3937
   *
 
3938
   *   If any of the following factors are TRUE then lighting is
 
3939
   *   vertex position dependent:
 
3940
   *
 
3941
   *   1) Any lights uses non-constant falloff
 
3942
   *   2) There are any point or spot lights
 
3943
   *   3) There is a light with specular color AND there is a
 
3944
   *      material with specular color
 
3945
   *
 
3946
   * So worth noting is that default lighting (a no-falloff ambient
 
3947
   * and a directional without specularity) is not position-dependent.
 
3948
   * We should capitalize.
 
3949
   *
 
3950
   * Simon Greenwold, April 2005
 
3951
   * </PRE>
 
3952
   */
 
3953
  public void lights() {
 
3954
    // need to make sure colorMode is RGB 255 here
 
3955
    int colorModeSaved = colorMode;
 
3956
    colorMode = RGB;
 
3957
 
 
3958
    lightFalloff(1, 0, 0);
 
3959
    lightSpecular(0, 0, 0);
 
3960
 
 
3961
    ambientLight(colorModeX * 0.5f,
 
3962
                 colorModeY * 0.5f,
 
3963
                 colorModeZ * 0.5f);
 
3964
    directionalLight(colorModeX * 0.5f,
 
3965
                     colorModeY * 0.5f,
 
3966
                     colorModeZ * 0.5f,
 
3967
                     0, 0, -1);
 
3968
 
 
3969
    colorMode = colorModeSaved;
 
3970
 
 
3971
    lightingDependsOnVertexPosition = false;
 
3972
  }
 
3973
 
 
3974
 
 
3975
  /**
 
3976
   * Turn off all lights.
 
3977
   */
 
3978
  public void noLights() {
 
3979
    // write any queued geometry, because lighting will be goofed after
 
3980
    flush();
 
3981
    // set the light count back to zero
 
3982
    lightCount = 0;
 
3983
  }
 
3984
 
 
3985
 
 
3986
  /**
 
3987
   * Add an ambient light based on the current color mode.
 
3988
   */
 
3989
  public void ambientLight(float r, float g, float b) {
 
3990
    ambientLight(r, g, b, 0, 0, 0);
 
3991
  }
 
3992
 
 
3993
 
 
3994
  /**
 
3995
   * Add an ambient light based on the current color mode.
 
3996
   * This version includes an (x, y, z) position for situations
 
3997
   * where the falloff distance is used.
 
3998
   */
 
3999
  public void ambientLight(float r, float g, float b,
 
4000
                           float x, float y, float z) {
 
4001
    if (lightCount == MAX_LIGHTS) {
 
4002
      throw new RuntimeException("can only create " + MAX_LIGHTS + " lights");
 
4003
    }
 
4004
    colorCalc(r, g, b);
 
4005
    lightDiffuse[lightCount][0] = calcR;
 
4006
    lightDiffuse[lightCount][1] = calcG;
 
4007
    lightDiffuse[lightCount][2] = calcB;
 
4008
 
 
4009
    lightType[lightCount] = AMBIENT;
 
4010
    lightFalloffConstant[lightCount] = currentLightFalloffConstant;
 
4011
    lightFalloffLinear[lightCount] = currentLightFalloffLinear;
 
4012
    lightFalloffQuadratic[lightCount] = currentLightFalloffQuadratic;
 
4013
    lightPosition(lightCount, x, y, z);
 
4014
    lightCount++;
 
4015
    //return lightCount-1;
 
4016
  }
 
4017
 
 
4018
 
 
4019
  public void directionalLight(float r, float g, float b,
 
4020
                               float nx, float ny, float nz) {
 
4021
    if (lightCount == MAX_LIGHTS) {
 
4022
      throw new RuntimeException("can only create " + MAX_LIGHTS + " lights");
 
4023
    }
 
4024
    colorCalc(r, g, b);
 
4025
    lightDiffuse[lightCount][0] = calcR;
 
4026
    lightDiffuse[lightCount][1] = calcG;
 
4027
    lightDiffuse[lightCount][2] = calcB;
 
4028
 
 
4029
    lightType[lightCount] = DIRECTIONAL;
 
4030
    lightFalloffConstant[lightCount] = currentLightFalloffConstant;
 
4031
    lightFalloffLinear[lightCount] = currentLightFalloffLinear;
 
4032
    lightFalloffQuadratic[lightCount] = currentLightFalloffQuadratic;
 
4033
    lightSpecular[lightCount][0] = currentLightSpecular[0];
 
4034
    lightSpecular[lightCount][1] = currentLightSpecular[1];
 
4035
    lightSpecular[lightCount][2] = currentLightSpecular[2];
 
4036
    lightDirection(lightCount, nx, ny, nz);
 
4037
    lightCount++;
 
4038
  }
 
4039
 
 
4040
 
 
4041
  public void pointLight(float r, float g, float b,
 
4042
                         float x, float y, float z) {
 
4043
    if (lightCount == MAX_LIGHTS) {
 
4044
      throw new RuntimeException("can only create " + MAX_LIGHTS + " lights");
 
4045
    }
 
4046
    colorCalc(r, g, b);
 
4047
    lightDiffuse[lightCount][0] = calcR;
 
4048
    lightDiffuse[lightCount][1] = calcG;
 
4049
    lightDiffuse[lightCount][2] = calcB;
 
4050
 
 
4051
    lightType[lightCount] = POINT;
 
4052
    lightFalloffConstant[lightCount] = currentLightFalloffConstant;
 
4053
    lightFalloffLinear[lightCount] = currentLightFalloffLinear;
 
4054
    lightFalloffQuadratic[lightCount] = currentLightFalloffQuadratic;
 
4055
    lightSpecular[lightCount][0] = currentLightSpecular[0];
 
4056
    lightSpecular[lightCount][1] = currentLightSpecular[1];
 
4057
    lightSpecular[lightCount][2] = currentLightSpecular[2];
 
4058
    lightPosition(lightCount, x, y, z);
 
4059
    lightCount++;
 
4060
 
 
4061
    lightingDependsOnVertexPosition = true;
 
4062
  }
 
4063
 
 
4064
 
 
4065
  public void spotLight(float r, float g, float b,
 
4066
                        float x, float y, float z,
 
4067
                        float nx, float ny, float nz,
 
4068
                        float angle, float concentration) {
 
4069
    if (lightCount == MAX_LIGHTS) {
 
4070
      throw new RuntimeException("can only create " + MAX_LIGHTS + " lights");
 
4071
    }
 
4072
    colorCalc(r, g, b);
 
4073
    lightDiffuse[lightCount][0] = calcR;
 
4074
    lightDiffuse[lightCount][1] = calcG;
 
4075
    lightDiffuse[lightCount][2] = calcB;
 
4076
 
 
4077
    lightType[lightCount] = SPOT;
 
4078
    lightFalloffConstant[lightCount] = currentLightFalloffConstant;
 
4079
    lightFalloffLinear[lightCount] = currentLightFalloffLinear;
 
4080
    lightFalloffQuadratic[lightCount] = currentLightFalloffQuadratic;
 
4081
    lightSpecular[lightCount][0] = currentLightSpecular[0];
 
4082
    lightSpecular[lightCount][1] = currentLightSpecular[1];
 
4083
    lightSpecular[lightCount][2] = currentLightSpecular[2];
 
4084
    lightPosition(lightCount, x, y, z);
 
4085
    lightDirection(lightCount, nx, ny, nz);
 
4086
    lightSpotAngle[lightCount] = angle;
 
4087
    lightSpotAngleCos[lightCount] = Math.max(0, (float) Math.cos(angle));
 
4088
    lightSpotConcentration[lightCount] = concentration;
 
4089
    lightCount++;
 
4090
 
 
4091
    lightingDependsOnVertexPosition = true;
 
4092
  }
 
4093
 
 
4094
 
 
4095
  /**
 
4096
   * Set the light falloff rates for the last light that was created.
 
4097
   * Default is lightFalloff(1, 0, 0).
 
4098
   */
 
4099
  public void lightFalloff(float constant, float linear, float quadratic) {
 
4100
    currentLightFalloffConstant = constant;
 
4101
    currentLightFalloffLinear = linear;
 
4102
    currentLightFalloffQuadratic = quadratic;
 
4103
 
 
4104
    lightingDependsOnVertexPosition = true;
 
4105
  }
 
4106
 
 
4107
 
 
4108
  /**
 
4109
   * Set the specular color of the last light created.
 
4110
   */
 
4111
  public void lightSpecular(float x, float y, float z) {
 
4112
    colorCalc(x, y, z);
 
4113
    currentLightSpecular[0] = calcR;
 
4114
    currentLightSpecular[1] = calcG;
 
4115
    currentLightSpecular[2] = calcB;
 
4116
 
 
4117
    lightingDependsOnVertexPosition = true;
 
4118
  }
 
4119
 
 
4120
 
 
4121
  /**
 
4122
   * internal function to set the light position
 
4123
   * based on the current modelview matrix.
 
4124
   */
 
4125
  protected void lightPosition(int num, float x, float y, float z) {
 
4126
    lightPositionVec.set(x, y, z);
 
4127
    modelview.mult(lightPositionVec, lightPosition[num]);
 
4128
    /*
 
4129
    lightPosition[num][0] =
 
4130
      modelview.m00*x + modelview.m01*y + modelview.m02*z + modelview.m03;
 
4131
    lightPosition[num][1] =
 
4132
      modelview.m10*x + modelview.m11*y + modelview.m12*z + modelview.m13;
 
4133
    lightPosition[num][2] =
 
4134
      modelview.m20*x + modelview.m21*y + modelview.m22*z + modelview.m23;
 
4135
    */
 
4136
  }
 
4137
 
 
4138
 
 
4139
  /**
 
4140
   * internal function to set the light direction
 
4141
   * based on the current modelview matrix.
 
4142
   */
 
4143
  protected void lightDirection(int num, float x, float y, float z) {
 
4144
    lightNormal[num].set(modelviewInv.m00*x + modelviewInv.m10*y + modelviewInv.m20*z + modelviewInv.m30,
 
4145
                         modelviewInv.m01*x + modelviewInv.m11*y + modelviewInv.m21*z + modelviewInv.m31,
 
4146
                         modelviewInv.m02*x + modelviewInv.m12*y + modelviewInv.m22*z + modelviewInv.m32);
 
4147
    lightNormal[num].normalize();
 
4148
 
 
4149
    /*
 
4150
    lightDirectionVec.set(x, y, z);
 
4151
    System.out.println("dir vec " + lightDirectionVec);
 
4152
    //modelviewInv.mult(lightDirectionVec, lightNormal[num]);
 
4153
    modelviewInv.cmult(lightDirectionVec, lightNormal[num]);
 
4154
    System.out.println("cmult vec " + lightNormal[num]);
 
4155
    lightNormal[num].normalize();
 
4156
    System.out.println("setting light direction " + lightNormal[num]);
 
4157
    */
 
4158
 
 
4159
    /*
 
4160
    // Multiply by inverse transpose.
 
4161
    lightNormal[num][0] =
 
4162
      modelviewInv.m00*x + modelviewInv.m10*y +
 
4163
      modelviewInv.m20*z + modelviewInv.m30;
 
4164
    lightNormal[num][1] =
 
4165
      modelviewInv.m01*x + modelviewInv.m11*y +
 
4166
      modelviewInv.m21*z + modelviewInv.m31;
 
4167
    lightNormal[num][2] =
 
4168
      modelviewInv.m02*x + modelviewInv.m12*y +
 
4169
      modelviewInv.m22*z + modelviewInv.m32;
 
4170
 
 
4171
    float n = mag(lightNormal[num][0], lightNormal[num][1], lightNormal[num][2]);
 
4172
    if (n == 0 || n == 1) return;
 
4173
 
 
4174
    lightNormal[num][0] /= n;
 
4175
    lightNormal[num][1] /= n;
 
4176
    lightNormal[num][2] /= n;
 
4177
    */
 
4178
  }
 
4179
 
 
4180
 
 
4181
 
 
4182
  //////////////////////////////////////////////////////////////
 
4183
 
 
4184
  // BACKGROUND
 
4185
 
 
4186
  // Base background() variations inherited from PGraphics.
 
4187
 
 
4188
 
 
4189
  protected void backgroundImpl(PImage image) {
 
4190
    System.arraycopy(image.pixels, 0, pixels, 0, pixels.length);
 
4191
    Arrays.fill(zbuffer, Float.MAX_VALUE);
 
4192
  }
 
4193
 
 
4194
 
 
4195
  /**
 
4196
   * Clear pixel buffer. With P3D and OPENGL, this also clears the zbuffer.
 
4197
   */
 
4198
  protected void backgroundImpl() {
 
4199
    Arrays.fill(pixels, backgroundColor);
 
4200
    Arrays.fill(zbuffer, Float.MAX_VALUE);
 
4201
  }
 
4202
 
 
4203
 
 
4204
 
 
4205
  //////////////////////////////////////////////////////////////
 
4206
 
 
4207
  // COLOR MODE
 
4208
 
 
4209
  // all colorMode() variations inherited from PGraphics.
 
4210
 
 
4211
 
 
4212
 
 
4213
  //////////////////////////////////////////////////////////////
 
4214
 
 
4215
  // COLOR CALCULATIONS
 
4216
 
 
4217
  // protected colorCalc and colorCalcARGB inherited.
 
4218
 
 
4219
 
 
4220
 
 
4221
  //////////////////////////////////////////////////////////////
 
4222
 
 
4223
  // COLOR DATATYPE STUFFING
 
4224
 
 
4225
  // final color() variations inherited.
 
4226
 
 
4227
 
 
4228
 
 
4229
  //////////////////////////////////////////////////////////////
 
4230
 
 
4231
  // COLOR DATATYPE EXTRACTION
 
4232
 
 
4233
  // final methods alpha, red, green, blue,
 
4234
  // hue, saturation, and brightness all inherited.
 
4235
 
 
4236
 
 
4237
 
 
4238
  //////////////////////////////////////////////////////////////
 
4239
 
 
4240
  // COLOR DATATYPE INTERPOLATION
 
4241
 
 
4242
  // both lerpColor variants inherited.
 
4243
 
 
4244
 
 
4245
 
 
4246
  //////////////////////////////////////////////////////////////
 
4247
 
 
4248
  // BEGIN/END RAW
 
4249
 
 
4250
  // beginRaw, endRaw() both inherited.
 
4251
 
 
4252
 
 
4253
 
 
4254
  //////////////////////////////////////////////////////////////
 
4255
 
 
4256
  // WARNINGS and EXCEPTIONS
 
4257
 
 
4258
  // showWarning and showException inherited.
 
4259
 
 
4260
 
 
4261
 
 
4262
  //////////////////////////////////////////////////////////////
 
4263
 
 
4264
  // RENDERER SUPPORT QUERIES
 
4265
 
 
4266
 
 
4267
  //public boolean displayable()
 
4268
 
 
4269
 
 
4270
  public boolean is2D() {
 
4271
    return false;
 
4272
  }
 
4273
 
 
4274
 
 
4275
  public boolean is3D() {
 
4276
    return true;
 
4277
  }
 
4278
 
 
4279
 
 
4280
 
 
4281
  //////////////////////////////////////////////////////////////
 
4282
 
 
4283
  // PIMAGE METHODS
 
4284
 
 
4285
  // All these methods are inherited, because this render has a
 
4286
  // pixels[] array that can be accessed directly.
 
4287
 
 
4288
  // getImage
 
4289
  // setCache, getCache, removeCache
 
4290
  // isModified, setModified
 
4291
  // loadPixels, updatePixels
 
4292
  // resize
 
4293
  // get, getImpl, set, setImpl
 
4294
  // mask
 
4295
  // filter
 
4296
  // copy
 
4297
  // blendColor, blend
 
4298
 
 
4299
 
 
4300
 
 
4301
  //////////////////////////////////////////////////////////////
 
4302
 
 
4303
  // MATH (internal use only)
 
4304
 
 
4305
 
 
4306
  private final float sqrt(float a) {
 
4307
    return (float) Math.sqrt(a);
 
4308
  }
 
4309
 
 
4310
 
 
4311
  private final float mag(float a, float b, float c) {
 
4312
    return (float) Math.sqrt(a*a + b*b + c*c);
 
4313
  }
 
4314
 
 
4315
 
 
4316
  private final float clamp(float a) {
 
4317
    return (a < 1) ? a : 1;
 
4318
  }
 
4319
 
 
4320
 
 
4321
  private final float abs(float a) {
 
4322
    return (a < 0) ? -a : a;
 
4323
  }
 
4324
 
 
4325
 
 
4326
  private float dot(float ax, float ay, float az,
 
4327
                    float bx, float by, float bz) {
 
4328
    return ax*bx + ay*by + az*bz;
 
4329
  }
 
4330
 
 
4331
 
 
4332
  /*
 
4333
  private final void cross(float a0, float a1, float a2,
 
4334
                           float b0, float b1, float b2,
 
4335
                           float[] out) {
 
4336
    out[0] = a1*b2 - a2*b1;
 
4337
    out[1] = a2*b0 - a0*b2;
 
4338
    out[2] = a0*b1 - a1*b0;
 
4339
  }
 
4340
  */
 
4341
 
 
4342
 
 
4343
  private final void cross(float a0, float a1, float a2,
 
4344
                           float b0, float b1, float b2,
 
4345
                           PVector out) {
 
4346
    out.x = a1*b2 - a2*b1;
 
4347
    out.y = a2*b0 - a0*b2;
 
4348
    out.z = a0*b1 - a1*b0;
 
4349
  }
 
4350
 
 
4351
 
 
4352
  /*
 
4353
  private final void cross(float[] a, float[] b, float[] out) {
 
4354
    out[0] = a[1]*b[2] - a[2]*b[1];
 
4355
    out[1] = a[2]*b[0] - a[0]*b[2];
 
4356
    out[2] = a[0]*b[1] - a[1]*b[0];
 
4357
  }
 
4358
  */
 
4359
}
 
4360