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

« back to all changes in this revision

Viewing changes to src/processing/core/PSmoothTriangle.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
 
 
28
/**
 
29
 * Smoothed triangle renderer for P3D.
 
30
 *
 
31
 * Based off of the PPolygon class in old versions of Processing.
 
32
 * Name and location of this class will change in a future release.
 
33
 */
 
34
public class PSmoothTriangle implements PConstants {
 
35
 
 
36
  // really this is "debug" but..
 
37
  private static final boolean EWJORDAN = false;
 
38
  private static final boolean FRY = false;
 
39
 
 
40
  // identical to the constants from PGraphics
 
41
 
 
42
  static final int X = 0; // transformed xyzw
 
43
  static final int Y = 1; // formerly SX SY SZ
 
44
  static final int Z = 2;
 
45
 
 
46
  static final int R = 3;  // actual rgb, after lighting
 
47
  static final int G = 4;  // fill stored here, transform in place
 
48
  static final int B = 5;
 
49
  static final int A = 6;
 
50
 
 
51
  static final int U = 7; // texture
 
52
  static final int V = 8;
 
53
 
 
54
  static final int DEFAULT_SIZE = 64; // this is needed for spheres
 
55
  float vertices[][] = new float[DEFAULT_SIZE][PGraphics.VERTEX_FIELD_COUNT];
 
56
  int vertexCount;
 
57
 
 
58
 
 
59
  // after some fiddling, this seems to produce the best results
 
60
  static final int ZBUFFER_MIN_COVERAGE = 204;
 
61
 
 
62
  float r[]   = new float[DEFAULT_SIZE]; // storage used by incrementalize
 
63
  float dr[]  = new float[DEFAULT_SIZE];
 
64
  float l[]   = new float[DEFAULT_SIZE]; // more storage for incrementalize
 
65
  float dl[]  = new float[DEFAULT_SIZE];
 
66
  float sp[]  = new float[DEFAULT_SIZE]; // temporary storage for scanline
 
67
  float sdp[] = new float[DEFAULT_SIZE];
 
68
 
 
69
  // color and xyz are always interpolated
 
70
  boolean interpX;
 
71
  boolean interpZ;
 
72
  boolean interpUV; // is this necessary? could just check timage != null
 
73
  boolean interpARGB;
 
74
 
 
75
  int rgba;
 
76
  int r2, g2, b2, a2, a2orig;
 
77
 
 
78
  boolean noDepthTest;
 
79
 
 
80
  PGraphics3D parent;
 
81
  int pixels[];
 
82
  float[] zbuffer;
 
83
 
 
84
  // the parent's width/height,
 
85
  // or if smooth is enabled, parent's w/h scaled
 
86
  // up by the smooth dimension
 
87
  int width, height;
 
88
  int width1, height1;
 
89
 
 
90
  PImage timage;
 
91
  int tpixels[];
 
92
  int theight, twidth;
 
93
  int theight1, twidth1;
 
94
  int tformat;
 
95
 
 
96
  // temp fix to behave like SMOOTH_IMAGES
 
97
  // TODO ewjordan: can probably remove this variable
 
98
  boolean texture_smooth;
 
99
 
 
100
  // for anti-aliasing
 
101
  static final int SUBXRES  = 8;
 
102
  static final int SUBXRES1 = 7;
 
103
  static final int SUBYRES  = 8;
 
104
  static final int SUBYRES1 = 7;
 
105
  static final int MAX_COVERAGE = SUBXRES * SUBYRES;
 
106
 
 
107
  boolean smooth;
 
108
  int firstModY;
 
109
  int lastModY;
 
110
  int lastY;
 
111
  int aaleft[] = new int[SUBYRES];
 
112
  int aaright[] = new int[SUBYRES];
 
113
  int aaleftmin, aarightmin;
 
114
  int aaleftmax, aarightmax;
 
115
  int aaleftfull, aarightfull;
 
116
 
 
117
  /* Variables needed for accurate texturing. */
 
118
  //private PMatrix textureMatrix = new PMatrix3D();
 
119
  private float[] camX = new float[3];
 
120
  private float[] camY = new float[3];
 
121
  private float[] camZ = new float[3];
 
122
  private float ax,ay,az;
 
123
  private float bx,by,bz;
 
124
  private float cx,cy,cz;
 
125
  private float nearPlaneWidth, nearPlaneHeight, nearPlaneDepth;
 
126
  //private float newax, newbx, newcx;
 
127
  private float xmult, ymult;
 
128
 
 
129
 
 
130
  final private int MODYRES(int y) {
 
131
    return (y & SUBYRES1);
 
132
  }
 
133
 
 
134
 
 
135
  public PSmoothTriangle(PGraphics3D iparent) {
 
136
    parent = iparent;
 
137
    reset(0);
 
138
  }
 
139
 
 
140
 
 
141
  public void reset(int count) {
 
142
    vertexCount = count;
 
143
    interpX = true;
 
144
    interpZ = true;
 
145
    interpUV = false;
 
146
    interpARGB = true;
 
147
    timage = null;
 
148
  }
 
149
 
 
150
 
 
151
  public float[] nextVertex() {
 
152
    if (vertexCount == vertices.length) {
 
153
      //parent.message(CHATTER, "re-allocating for " +
 
154
      //             (vertexCount*2) + " vertices");
 
155
      float temp[][] = new float[vertexCount<<1][PGraphics.VERTEX_FIELD_COUNT];
 
156
      System.arraycopy(vertices, 0, temp, 0, vertexCount);
 
157
      vertices = temp;
 
158
 
 
159
      r   = new float[vertices.length];
 
160
      dr  = new float[vertices.length];
 
161
      l   = new float[vertices.length];
 
162
      dl  = new float[vertices.length];
 
163
      sp  = new float[vertices.length];
 
164
      sdp = new float[vertices.length];
 
165
    }
 
166
    return vertices[vertexCount++];  // returns v[0], sets vc to 1
 
167
  }
 
168
 
 
169
 
 
170
  public void texture(PImage image) {
 
171
    this.timage = image;
 
172
    this.tpixels = image.pixels;
 
173
    this.twidth = image.width;
 
174
    this.theight = image.height;
 
175
    this.tformat = image.format;
 
176
 
 
177
    twidth1 = twidth - 1;
 
178
    theight1 = theight - 1;
 
179
    interpUV = true;
 
180
  }
 
181
 
 
182
  public void render() {
 
183
    if (vertexCount < 3) return;
 
184
 
 
185
    smooth = true;//TODO
 
186
    // these may have changed due to a resize()
 
187
    // so they should be refreshed here
 
188
    pixels = parent.pixels;
 
189
    zbuffer = parent.zbuffer;
 
190
 
 
191
    noDepthTest = false;//parent.hints[DISABLE_DEPTH_TEST];
 
192
 
 
193
    // In 0148+, should always be true if this code is called at all
 
194
    //smooth = parent.smooth;
 
195
 
 
196
    // by default, text turns on smooth for the textures
 
197
    // themselves. but this should be shut off if the hint
 
198
    // for DISABLE_TEXT_SMOOTH is set.
 
199
    texture_smooth = true;
 
200
 
 
201
    width = smooth ? parent.width*SUBXRES : parent.width;
 
202
    height = smooth ? parent.height*SUBYRES : parent.height;
 
203
 
 
204
    width1 = width - 1;
 
205
    height1 = height - 1;
 
206
 
 
207
    if (!interpARGB) {
 
208
      r2 = (int) (vertices[0][R] * 255);
 
209
      g2 = (int) (vertices[0][G] * 255);
 
210
      b2 = (int) (vertices[0][B] * 255);
 
211
      a2 = (int) (vertices[0][A] * 255);
 
212
      a2orig = a2; // save an extra copy
 
213
      rgba = 0xff000000 | (r2 << 16) | (g2 << 8) | b2;
 
214
    }
 
215
 
 
216
    for (int i = 0; i < vertexCount; i++) {
 
217
      r[i] = 0; dr[i] = 0; l[i] = 0; dl[i] = 0;
 
218
    }
 
219
 
 
220
    if (smooth) {
 
221
      for (int i = 0; i < vertexCount; i++) {
 
222
        vertices[i][X] *= SUBXRES;
 
223
        vertices[i][Y] *= SUBYRES;
 
224
      }
 
225
      firstModY = -1;
 
226
    }
 
227
 
 
228
    // find top vertex (y is zero at top, higher downwards)
 
229
    int topi = 0;
 
230
    float ymin = vertices[0][Y];
 
231
    float ymax = vertices[0][Y]; // fry 031001
 
232
    for (int i = 1; i < vertexCount; i++) {
 
233
      if (vertices[i][Y] < ymin) {
 
234
        ymin = vertices[i][Y];
 
235
        topi = i;
 
236
      }
 
237
      if (vertices[i][Y] > ymax) ymax = vertices[i][Y];
 
238
    }
 
239
 
 
240
    // the last row is an exceptional case, because there won't
 
241
    // necessarily be 8 rows of subpixel lines that will force
 
242
    // the final line to render. so instead, the algo keeps track
 
243
    // of the lastY (in subpixel resolution) that will be rendered
 
244
    // and that will force a scanline to happen the same as
 
245
    // every eighth in the other situations
 
246
    //lastY = -1;  // fry 031001
 
247
    lastY = (int) (ymax - 0.5f);  // global to class bc used by other fxns
 
248
 
 
249
    int lefti = topi;             // li, index of left vertex
 
250
    int righti = topi;            // ri, index of right vertex
 
251
    int y = (int) (ymin + 0.5f);  // current scan line
 
252
    int lefty = y - 1;            // lower end of left edge
 
253
    int righty = y - 1;           // lower end of right edge
 
254
 
 
255
    interpX = true;
 
256
 
 
257
    int remaining = vertexCount;
 
258
 
 
259
    // scan in y, activating new edges on left & right
 
260
    // as scan line passes over new vertices
 
261
    while (remaining > 0) {
 
262
      // advance left edge?
 
263
      while ((lefty <= y) && (remaining > 0)) {
 
264
        remaining--;
 
265
        // step ccw down left side
 
266
        int i = (lefti != 0) ? (lefti-1) : (vertexCount-1);
 
267
        incrementalize_y(vertices[lefti], vertices[i], l, dl, y);
 
268
        lefty = (int) (vertices[i][Y] + 0.5f);
 
269
        lefti = i;
 
270
      }
 
271
 
 
272
      // advance right edge?
 
273
      while ((righty <= y) && (remaining > 0)) {
 
274
        remaining--;
 
275
        // step cw down right edge
 
276
        int i = (righti != vertexCount-1) ? (righti + 1) : 0;
 
277
        incrementalize_y(vertices[righti], vertices[i], r, dr, y);
 
278
        righty = (int) (vertices[i][Y] + 0.5f);
 
279
        righti = i;
 
280
      }
 
281
 
 
282
      // do scanlines till end of l or r edge
 
283
      while (y < lefty && y < righty) {
 
284
        // this doesn't work because it's not always set here
 
285
        //if (remaining == 0) {
 
286
        //lastY = (lefty < righty) ? lefty-1 : righty-1;
 
287
        //System.out.println("lastY is " + lastY);
 
288
        //}
 
289
 
 
290
        if ((y >= 0) && (y < height)) {
 
291
          //try {  // hopefully this bug is fixed
 
292
          if (l[X] <= r[X]) scanline(y, l, r);
 
293
          else scanline(y, r, l);
 
294
          //} catch (ArrayIndexOutOfBoundsException e) {
 
295
          //e.printStackTrace();
 
296
          //}
 
297
        }
 
298
        y++;
 
299
        // this increment probably needs to be different
 
300
        // UV and RGB shouldn't be incremented until line is emitted
 
301
        increment(l, dl);
 
302
        increment(r, dr);
 
303
      }
 
304
    }
 
305
    //if (smooth) {
 
306
    //System.out.println("y/lasty/lastmody = " + y + " " + lastY + " " + lastModY);
 
307
    //}
 
308
  }
 
309
 
 
310
 
 
311
  public void unexpand() {
 
312
    if (smooth) {
 
313
      for (int i = 0; i < vertexCount; i++) {
 
314
        vertices[i][X] /= SUBXRES;
 
315
        vertices[i][Y] /= SUBYRES;
 
316
      }
 
317
    }
 
318
  }
 
319
 
 
320
 
 
321
  private void scanline(int y, float l[], float r[]) {
 
322
    //System.out.println("scanline " + y);
 
323
    for (int i = 0; i < vertexCount; i++) {  // should be moved later
 
324
      sp[i] = 0; sdp[i] = 0;
 
325
    }
 
326
 
 
327
    // this rounding doesn't seem to be relevant with smooth
 
328
    int lx = (int) (l[X] + 0.49999f);  // ceil(l[X]-.5);
 
329
    if (lx < 0) lx = 0;
 
330
    int rx = (int) (r[X] - 0.5f);
 
331
    if (rx > width1) rx = width1;
 
332
 
 
333
    if (lx > rx) return;
 
334
 
 
335
    if (smooth) {
 
336
      int mody = MODYRES(y);
 
337
 
 
338
      aaleft[mody] = lx;
 
339
      aaright[mody] = rx;
 
340
 
 
341
      if (firstModY == -1) {
 
342
        firstModY = mody;
 
343
        aaleftmin = lx; aaleftmax = lx;
 
344
        aarightmin = rx; aarightmax = rx;
 
345
 
 
346
      } else {
 
347
        if (aaleftmin > aaleft[mody]) aaleftmin = aaleft[mody];
 
348
        if (aaleftmax < aaleft[mody]) aaleftmax = aaleft[mody];
 
349
        if (aarightmin > aaright[mody]) aarightmin = aaright[mody];
 
350
        if (aarightmax < aaright[mody]) aarightmax = aaright[mody];
 
351
      }
 
352
 
 
353
      lastModY = mody;  // moved up here (before the return) 031001
 
354
      // not the eighth (or lastY) line, so not scanning this time
 
355
      if ((mody != SUBYRES1) && (y != lastY)) return;
 
356
      //lastModY = mody;  // eeK! this was missing
 
357
      //return;
 
358
 
 
359
      //if (y == lastY) {
 
360
      //System.out.println("y is lasty");
 
361
      //}
 
362
      //lastModY = mody;
 
363
      aaleftfull = aaleftmax/SUBXRES + 1;
 
364
      aarightfull = aarightmin/SUBXRES - 1;
 
365
    }
 
366
 
 
367
    // this is the setup, based on lx
 
368
    incrementalize_x(l, r, sp, sdp, lx);
 
369
    //System.out.println(l[V] + " " + r[V] + " " +sp[V] + " " +sdp[V]);
 
370
 
 
371
    // scan in x, generating pixels
 
372
    // using parent.width to get actual pixel index
 
373
    // rather than scaled by smooth factor
 
374
    int offset = smooth ? parent.width * (y / SUBYRES) : parent.width*y;
 
375
 
 
376
    int truelx = 0, truerx = 0;
 
377
    if (smooth) {
 
378
      truelx = lx / SUBXRES;
 
379
      truerx = (rx + SUBXRES1) / SUBXRES;
 
380
 
 
381
      lx = aaleftmin / SUBXRES;
 
382
      rx = (aarightmax + SUBXRES1) / SUBXRES;
 
383
      if (lx < 0) lx = 0;
 
384
      if (rx > parent.width1) rx = parent.width1;
 
385
    }
 
386
 
 
387
//    System.out.println("P3D interp uv " + interpUV + " " +
 
388
//                       vertices[2][U] + " " + vertices[2][V]);
 
389
 
 
390
    interpX = false;
 
391
    int tr, tg, tb, ta;
 
392
    //System.out.println("lx: "+lx + "\nrx: "+rx);
 
393
    for (int x = lx; x <= rx; x++) {
 
394
 
 
395
      // added == because things on same plane weren't replacing each other
 
396
      // makes for strangeness in 3D [ewj: yup!], but totally necessary for 2D
 
397
      //if (noDepthTest || (sp[Z] < zbuffer[offset+x])) {
 
398
      if (noDepthTest || (sp[Z] <= zbuffer[offset+x])) {
 
399
        //if (true) {
 
400
 
 
401
        // map texture based on U, V coords in sp[U] and sp[V]
 
402
        if (interpUV) {
 
403
          int tu = (int)sp[U];
 
404
          int tv = (int)sp[V];
 
405
 
 
406
          if (tu > twidth1) tu = twidth1;
 
407
          if (tv > theight1) tv = theight1;
 
408
          if (tu < 0) tu = 0;
 
409
          if (tv < 0) tv = 0;
 
410
 
 
411
          int txy = tv*twidth + tu;
 
412
          //System.out.println("tu: "+tu+" ; tv: "+tv+" ; txy: "+txy);
 
413
          float[] uv = new float[2];
 
414
          txy = getTextureIndex(x, y*1.0f/SUBYRES, uv);
 
415
          //          txy = getTextureIndex(x* 1.0f/SUBXRES, y*1.0f/SUBYRES, uv);
 
416
 
 
417
          tu = (int)uv[0]; tv = (int)uv[1];
 
418
          //          if (tu > twidth1) tu = twidth1;
 
419
          //          if (tv > theight1) tv = theight1;
 
420
          //          if (tu < 0) tu = 0;
 
421
          //          if (tv < 0) tv = 0;
 
422
          txy = twidth*tv + tu;
 
423
          //          if (EWJORDAN) System.out.println("x/y/txy:"+x + " " + y + " " +txy);
 
424
          //PApplet.println(sp);
 
425
 
 
426
          //smooth = true;
 
427
          if (smooth || texture_smooth) {
 
428
            //if (FRY) System.out.println("sp u v = " + sp[U] + " " + sp[V]);
 
429
            //System.out.println("sp u v = " + sp[U] + " " + sp[V]);
 
430
            // tuf1/tvf1 is the amount of coverage for the adjacent
 
431
            // pixel, which is the decimal percentage.
 
432
            //            int tuf1 = (int) (255f * (sp[U] - (float)tu));
 
433
            //            int tvf1 = (int) (255f * (sp[V] - (float)tv));
 
434
 
 
435
            int tuf1 = (int) (255f * (uv[0] - tu));
 
436
            int tvf1 = (int) (255f * (uv[1] - tv));
 
437
 
 
438
            // the closer sp[U or V] is to the decimal being zero
 
439
            // the more coverage it should get of the original pixel
 
440
            int tuf = 255 - tuf1;
 
441
            int tvf = 255 - tvf1;
 
442
 
 
443
            // this code sucks! filled with bugs and slow as hell!
 
444
            int pixel00 = tpixels[txy];
 
445
            int pixel01 = (tv < theight1) ? tpixels[txy + twidth] : tpixels[txy];
 
446
            int pixel10 = (tu < twidth1)  ? tpixels[txy + 1]      : tpixels[txy];
 
447
            int pixel11 = ((tv < theight1) && (tu < twidth1)) ? tpixels[txy + twidth + 1] : tpixels[txy];
 
448
            //System.out.println("1: "+pixel00);
 
449
            //check
 
450
            int p00, p01, p10, p11;
 
451
            int px0, px1; //, pxy;
 
452
 
 
453
            if (tformat == ALPHA) {
 
454
              px0 = (pixel00*tuf + pixel10*tuf1) >> 8;
 
455
              px1 = (pixel01*tuf + pixel11*tuf1) >> 8;
 
456
              ta = (((px0*tvf + px1*tvf1) >> 8) *
 
457
                    (interpARGB ? ((int) (sp[A]*255)) : a2orig)) >> 8;
 
458
            } else if (tformat == ARGB) {
 
459
              p00 = (pixel00 >> 24) & 0xff;
 
460
              p01 = (pixel01 >> 24) & 0xff;
 
461
              p10 = (pixel10 >> 24) & 0xff;
 
462
              p11 = (pixel11 >> 24) & 0xff;
 
463
 
 
464
              px0 = (p00*tuf + p10*tuf1) >> 8;
 
465
              px1 = (p01*tuf + p11*tuf1) >> 8;
 
466
              ta = (((px0*tvf + px1*tvf1) >> 8) *
 
467
                    (interpARGB ? ((int) (sp[A]*255)) : a2orig)) >> 8;
 
468
            } else {  // RGB image, no alpha
 
469
              //ACCTEX: Getting here when smooth is on
 
470
              ta = interpARGB ? ((int) (sp[A]*255)) : a2orig;
 
471
              //System.out.println("4: "+ta + " " +interpARGB + " " + sp[A] + " " + a2orig);
 
472
              //check
 
473
            }
 
474
 
 
475
            if ((tformat == RGB) || (tformat == ARGB)) {
 
476
              p00 = (pixel00 >> 16) & 0xff;  // red
 
477
              p01 = (pixel01 >> 16) & 0xff;
 
478
              p10 = (pixel10 >> 16) & 0xff;
 
479
              p11 = (pixel11 >> 16) & 0xff;
 
480
 
 
481
              px0 = (p00*tuf + p10*tuf1) >> 8;
 
482
              px1 = (p01*tuf + p11*tuf1) >> 8;
 
483
              tr = (((px0*tvf + px1*tvf1) >> 8) * (interpARGB ? ((int) (sp[R]*255)) : r2)) >> 8;
 
484
 
 
485
              p00 = (pixel00 >> 8) & 0xff;  // green
 
486
              p01 = (pixel01 >> 8) & 0xff;
 
487
              p10 = (pixel10 >> 8) & 0xff;
 
488
              p11 = (pixel11 >> 8) & 0xff;
 
489
 
 
490
              px0 = (p00*tuf + p10*tuf1) >> 8;
 
491
              px1 = (p01*tuf + p11*tuf1) >> 8;
 
492
              tg = (((px0*tvf + px1*tvf1) >> 8) * (interpARGB ? ((int) (sp[G]*255)) : g2)) >> 8;
 
493
 
 
494
 
 
495
              p00 = pixel00 & 0xff;  // blue
 
496
              p01 = pixel01 & 0xff;
 
497
              p10 = pixel10 & 0xff;
 
498
              p11 = pixel11 & 0xff;
 
499
 
 
500
              px0 = (p00*tuf + p10*tuf1) >> 8;
 
501
              px1 = (p01*tuf + p11*tuf1) >> 8;
 
502
              tb = (((px0*tvf + px1*tvf1) >> 8) * (interpARGB ? ((int) (sp[B]*255)) : b2)) >> 8;
 
503
              //System.out.println("5: "+tr + " " + tg + " " +tb);
 
504
              //check
 
505
            } else {  // alpha image, only use current fill color
 
506
              if (interpARGB) {
 
507
                tr = (int) (sp[R] * 255);
 
508
                tg = (int) (sp[G] * 255);
 
509
                tb = (int) (sp[B] * 255);
 
510
              } else {
 
511
                tr = r2;
 
512
                tg = g2;
 
513
                tb = b2;
 
514
              }
 
515
            }
 
516
 
 
517
            // get coverage for pixel if smooth
 
518
            // checks smooth again here because of
 
519
            // hints[SMOOTH_IMAGES] used up above
 
520
            int weight = smooth ? coverage(x) : 255;
 
521
            if (weight != 255) ta = (ta*weight) >> 8;
 
522
            //System.out.println(ta);
 
523
            //System.out.println("8");
 
524
            //check
 
525
          } else {  // no smooth, just get the pixels
 
526
            int tpixel = tpixels[txy];
 
527
            // TODO i doubt splitting these guys really gets us
 
528
            // all that much speed.. is it worth it?
 
529
            if (tformat == ALPHA) {
 
530
              ta = tpixel;
 
531
              if (interpARGB) {
 
532
                tr = (int) (sp[R]*255);
 
533
                tg = (int) (sp[G]*255);
 
534
                tb = (int) (sp[B]*255);
 
535
                if (sp[A] != 1) {
 
536
                  ta = (((int) (sp[A]*255)) * ta) >> 8;
 
537
                }
 
538
              } else {
 
539
                tr = r2;
 
540
                tg = g2;
 
541
                tb = b2;
 
542
                ta = (a2orig * ta) >> 8;
 
543
              }
 
544
 
 
545
            } else {  // RGB or ARGB
 
546
              ta = (tformat == RGB) ? 255 : (tpixel >> 24) & 0xff;
 
547
              if (interpARGB) {
 
548
                tr = (((int) (sp[R]*255)) * ((tpixel >> 16) & 0xff)) >> 8;
 
549
                tg = (((int) (sp[G]*255)) * ((tpixel >> 8) & 0xff)) >> 8;
 
550
                tb = (((int) (sp[B]*255)) * ((tpixel) & 0xff)) >> 8;
 
551
                ta = (((int) (sp[A]*255)) * ta) >> 8;
 
552
              } else {
 
553
                tr = (r2 * ((tpixel >> 16) & 0xff)) >> 8;
 
554
                tg = (g2 * ((tpixel >> 8) & 0xff)) >> 8;
 
555
                tb = (b2 * ((tpixel) & 0xff)) >> 8;
 
556
                ta = (a2orig * ta) >> 8;
 
557
              }
 
558
            }
 
559
          }
 
560
 
 
561
          if ((ta == 254) || (ta == 255)) {  // if (ta & 0xf8) would be good
 
562
            // no need to blend
 
563
            pixels[offset+x] = 0xff000000 | (tr << 16) | (tg << 8) | tb;
 
564
            zbuffer[offset+x] = sp[Z];
 
565
          } else {
 
566
            // blend with pixel on screen
 
567
            int a1 = 255-ta;
 
568
            int r1 = (pixels[offset+x] >> 16) & 0xff;
 
569
            int g1 = (pixels[offset+x] >> 8) & 0xff;
 
570
            int b1 = (pixels[offset+x]) & 0xff;
 
571
 
 
572
 
 
573
            pixels[offset+x] =
 
574
              0xff000000 |
 
575
              (((tr*ta + r1*a1) >> 8) << 16) |
 
576
              ((tg*ta + g1*a1) & 0xff00) |
 
577
              ((tb*ta + b1*a1) >> 8);
 
578
 
 
579
            //System.out.println("17");
 
580
            //check
 
581
            if (ta > ZBUFFER_MIN_COVERAGE) zbuffer[offset+x] = sp[Z];
 
582
          }
 
583
 
 
584
          //System.out.println("18");
 
585
          //check
 
586
        } else {  // no image applied
 
587
          int weight = smooth ? coverage(x) : 255;
 
588
 
 
589
          if (interpARGB) {
 
590
            r2 = (int) (sp[R] * 255);
 
591
            g2 = (int) (sp[G] * 255);
 
592
            b2 = (int) (sp[B] * 255);
 
593
            if (sp[A] != 1) weight = (weight * ((int) (sp[A] * 255))) >> 8;
 
594
            if (weight == 255) {
 
595
              rgba = 0xff000000 | (r2 << 16) | (g2 << 8) | b2;
 
596
            }
 
597
          } else {
 
598
            if (a2orig != 255) weight = (weight * a2orig) >> 8;
 
599
          }
 
600
 
 
601
          if (weight == 255) {
 
602
            // no blend, no aa, just the rgba
 
603
            pixels[offset+x] = rgba;
 
604
            zbuffer[offset+x] = sp[Z];
 
605
 
 
606
          } else {
 
607
            int r1 = (pixels[offset+x] >> 16) & 0xff;
 
608
            int g1 = (pixels[offset+x] >> 8) & 0xff;
 
609
            int b1 = (pixels[offset+x]) & 0xff;
 
610
            a2 = weight;
 
611
 
 
612
            int a1 = 255 - a2;
 
613
            pixels[offset+x] = (0xff000000 |
 
614
                                ((r1*a1 + r2*a2) >> 8) << 16 |
 
615
                                // use & instead of >> and << below
 
616
                                ((g1*a1 + g2*a2) >> 8) << 8 |
 
617
                                ((b1*a1 + b2*a2) >> 8));
 
618
 
 
619
            if (a2 > ZBUFFER_MIN_COVERAGE) zbuffer[offset+x] = sp[Z];
 
620
          }
 
621
        }
 
622
      }
 
623
      // if smooth enabled, don't increment values
 
624
      // for the pixel in the stretch out version
 
625
      // of the scanline used to get smooth edges.
 
626
      if (!smooth || ((x >= truelx) && (x <= truerx))) {
 
627
        //if (!smooth)
 
628
        increment(sp, sdp);
 
629
      }
 
630
    }
 
631
    firstModY = -1;
 
632
    interpX = true;
 
633
  }
 
634
 
 
635
 
 
636
  // x is in screen, not huge 8x coordinates
 
637
  private int coverage(int x) {
 
638
    if ((x >= aaleftfull) && (x <= aarightfull) &&
 
639
        // important since not all SUBYRES lines may have been covered
 
640
        (firstModY == 0) && (lastModY == SUBYRES1)) {
 
641
      return 255;
 
642
    }
 
643
 
 
644
    int pixelLeft = x*SUBXRES;  // huh?
 
645
    int pixelRight = pixelLeft + 8;
 
646
 
 
647
    int amt = 0;
 
648
    for (int i = firstModY; i <= lastModY; i++) {
 
649
      if ((aaleft[i] > pixelRight) || (aaright[i] < pixelLeft)) {
 
650
        continue;
 
651
      }
 
652
      // does this need a +1 ?
 
653
      amt += ((aaright[i] < pixelRight ? aaright[i] : pixelRight) -
 
654
              (aaleft[i] > pixelLeft ? aaleft[i] : pixelLeft));
 
655
    }
 
656
    amt <<= 2;
 
657
    return (amt == 256) ? 255 : amt;
 
658
  }
 
659
 
 
660
 
 
661
  private void incrementalize_y(float p1[], float p2[],
 
662
                                float p[], float dp[], int y) {
 
663
    float delta = p2[Y] - p1[Y];
 
664
    if (delta == 0) delta = 1;
 
665
    float fraction = y + 0.5f - p1[Y];
 
666
 
 
667
    if (interpX) {
 
668
      dp[X] = (p2[X] - p1[X]) / delta;
 
669
      p[X] = p1[X] + dp[X] * fraction;
 
670
    }
 
671
    if (interpZ) {
 
672
      dp[Z] = (p2[Z] - p1[Z]) / delta;
 
673
      p[Z] = p1[Z] + dp[Z] * fraction;
 
674
    }
 
675
 
 
676
    if (interpARGB) {
 
677
      dp[R] = (p2[R] - p1[R]) / delta;
 
678
      dp[G] = (p2[G] - p1[G]) / delta;
 
679
      dp[B] = (p2[B] - p1[B]) / delta;
 
680
      dp[A] = (p2[A] - p1[A]) / delta;
 
681
      p[R] = p1[R] + dp[R] * fraction;
 
682
      p[G] = p1[G] + dp[G] * fraction;
 
683
      p[B] = p1[B] + dp[B] * fraction;
 
684
      p[A] = p1[A] + dp[A] * fraction;
 
685
    }
 
686
 
 
687
    if (interpUV) {
 
688
      dp[U] = (p2[U] - p1[U]) / delta;
 
689
      dp[V] = (p2[V] - p1[V]) / delta;
 
690
 
 
691
      //if (smooth) {
 
692
      //p[U] = p1[U]; //+ dp[U] * fraction;
 
693
      //p[V] = p1[V]; //+ dp[V] * fraction;
 
694
 
 
695
      //} else {
 
696
      p[U] = p1[U] + dp[U] * fraction;
 
697
      p[V] = p1[V] + dp[V] * fraction;
 
698
      //}
 
699
      if (FRY) System.out.println("inc y p[U] p[V] = " + p[U] + " " + p[V]);
 
700
    }
 
701
  }
 
702
 
 
703
  //incrementalize_x(l, r, sp, sdp, lx);
 
704
  private void incrementalize_x(float p1[], float p2[],
 
705
                                float p[], float dp[], int x) {
 
706
    float delta = p2[X] - p1[X];
 
707
    if (delta == 0) delta = 1;
 
708
    float fraction = x + 0.5f - p1[X];
 
709
    if (smooth) {
 
710
      delta /= SUBXRES;
 
711
      fraction /= SUBXRES;
 
712
    }
 
713
 
 
714
    if (interpX) {
 
715
      dp[X] = (p2[X] - p1[X]) / delta;
 
716
      p[X] = p1[X] + dp[X] * fraction;
 
717
    }
 
718
    if (interpZ) {
 
719
      dp[Z] = (p2[Z] - p1[Z]) / delta;
 
720
      p[Z] = p1[Z] + dp[Z] * fraction;
 
721
      //System.out.println(p2[Z]+" " +p1[Z]+" " +dp[Z]);
 
722
    }
 
723
 
 
724
    if (interpARGB) {
 
725
      dp[R] = (p2[R] - p1[R]) / delta;
 
726
      dp[G] = (p2[G] - p1[G]) / delta;
 
727
      dp[B] = (p2[B] - p1[B]) / delta;
 
728
      dp[A] = (p2[A] - p1[A]) / delta;
 
729
      p[R] = p1[R] + dp[R] * fraction;
 
730
      p[G] = p1[G] + dp[G] * fraction;
 
731
      p[B] = p1[B] + dp[B] * fraction;
 
732
      p[A] = p1[A] + dp[A] * fraction;
 
733
    }
 
734
 
 
735
    if (interpUV) {
 
736
      if (FRY) System.out.println("delta, frac = " + delta + ", " + fraction);
 
737
      dp[U] = (p2[U] - p1[U]) / delta;
 
738
      dp[V] = (p2[V] - p1[V]) / delta;
 
739
 
 
740
      //if (smooth) {
 
741
      //p[U] = p1[U];
 
742
      // offset for the damage that will be done by the
 
743
      // 8 consecutive calls to scanline
 
744
      // agh.. this won't work b/c not always 8 calls before render
 
745
      // maybe lastModY - firstModY + 1 instead?
 
746
      if (FRY) System.out.println("before inc x p[V] = " + p[V] + " " + p1[V] + " " + p2[V]);
 
747
      //p[V] = p1[V] - SUBXRES1 * fraction;
 
748
 
 
749
      //} else {
 
750
      p[U] = p1[U] + dp[U] * fraction;
 
751
      p[V] = p1[V] + dp[V] * fraction;
 
752
      //}
 
753
    }
 
754
  }
 
755
 
 
756
  private void increment(float p[], float dp[]) {
 
757
    if (interpX) p[X] += dp[X];
 
758
    if (interpZ) p[Z] += dp[Z];
 
759
 
 
760
    if (interpARGB) {
 
761
      p[R] += dp[R];
 
762
      p[G] += dp[G];
 
763
      p[B] += dp[B];
 
764
      p[A] += dp[A];
 
765
    }
 
766
 
 
767
    if (interpUV) {
 
768
      if (FRY) System.out.println("increment() " + p[V] + " " + dp[V]);
 
769
      p[U] += dp[U];
 
770
      p[V] += dp[V];
 
771
    }
 
772
  }
 
773
 
 
774
 
 
775
  /**
 
776
   * Pass camera-space coordinates for the triangle.
 
777
   * Needed to render if hint(ENABLE_ACCURATE_TEXTURES) enabled.
 
778
   * Generally this will not need to be called manually,
 
779
   * currently called from PGraphics3D.render_triangles()
 
780
   */
 
781
  public void setCamVertices(float x0, float y0, float z0,
 
782
                             float x1, float y1, float z1,
 
783
                             float x2, float y2, float z2) {
 
784
    camX[0] = x0;
 
785
    camX[1] = x1;
 
786
    camX[2] = x2;
 
787
 
 
788
    camY[0] = y0;
 
789
    camY[1] = y1;
 
790
    camY[2] = y2;
 
791
 
 
792
    camZ[0] = z0;
 
793
    camZ[1] = z1;
 
794
    camZ[2] = z2;
 
795
  }
 
796
 
 
797
  public void setVertices(float x0, float y0, float z0,
 
798
                          float x1, float y1, float z1,
 
799
                          float x2, float y2, float z2) {
 
800
    vertices[0][X] = x0;
 
801
    vertices[1][X] = x1;
 
802
    vertices[2][X] = x2;
 
803
 
 
804
    vertices[0][Y] = y0;
 
805
    vertices[1][Y] = y1;
 
806
    vertices[2][Y] = y2;
 
807
 
 
808
    vertices[0][Z] = z0;
 
809
    vertices[1][Z] = z1;
 
810
    vertices[2][Z] = z2;
 
811
  }
 
812
 
 
813
 
 
814
 
 
815
  /**
 
816
   * Precompute a bunch of variables needed to perform
 
817
   * texture mapping.
 
818
   * @return True unless texture mapping is degenerate
 
819
   */
 
820
  boolean precomputeAccurateTexturing() {
 
821
    int o0 = 0;
 
822
    int o1 = 1;
 
823
    int o2 = 2;
 
824
 
 
825
    PMatrix3D myMatrix = new PMatrix3D(vertices[o0][U], vertices[o0][V], 1, 0,
 
826
                                       vertices[o1][U], vertices[o1][V], 1, 0,
 
827
                                       vertices[o2][U], vertices[o2][V], 1, 0,
 
828
                                       0,               0,               0, 1);
 
829
 
 
830
    // A 3x3 inversion would be more efficient here,
 
831
    // given that the fourth r/c are unity
 
832
    boolean invertSuccess = myMatrix.invert();// = myMatrix.invert();
 
833
 
 
834
    // If the matrix inversion had trouble, let the caller know.
 
835
    // Note that this does not catch everything that could go wrong
 
836
    // here, like if the renderer is in ortho() mode (which really
 
837
    // must be caught in PGraphics3D instead of here).
 
838
    if (!invertSuccess) return false;
 
839
 
 
840
    float m00, m01, m02, m10, m11, m12, m20, m21, m22;
 
841
    m00 = myMatrix.m00*camX[o0]+myMatrix.m01*camX[o1]+myMatrix.m02*camX[o2];
 
842
    m01 = myMatrix.m10*camX[o0]+myMatrix.m11*camX[o1]+myMatrix.m12*camX[o2];
 
843
    m02 = myMatrix.m20*camX[o0]+myMatrix.m21*camX[o1]+myMatrix.m22*camX[o2];
 
844
    m10 = myMatrix.m00*camY[o0]+myMatrix.m01*camY[o1]+myMatrix.m02*camY[o2];
 
845
    m11 = myMatrix.m10*camY[o0]+myMatrix.m11*camY[o1]+myMatrix.m12*camY[o2];
 
846
    m12 = myMatrix.m20*camY[o0]+myMatrix.m21*camY[o1]+myMatrix.m22*camY[o2];
 
847
    m20 = -(myMatrix.m00*camZ[o0]+myMatrix.m01*camZ[o1]+myMatrix.m02*camZ[o2]);
 
848
    m21 = -(myMatrix.m10*camZ[o0]+myMatrix.m11*camZ[o1]+myMatrix.m12*camZ[o2]);
 
849
    m22 = -(myMatrix.m20*camZ[o0]+myMatrix.m21*camZ[o1]+myMatrix.m22*camZ[o2]);
 
850
 
 
851
    float px = m02;
 
852
    float py = m12;
 
853
    float pz = m22;
 
854
 
 
855
    float TEX_WIDTH = this.twidth;
 
856
    float TEX_HEIGHT = this.theight;
 
857
 
 
858
    float resultT0x = m00*TEX_WIDTH+m02;
 
859
    float resultT0y = m10*TEX_WIDTH+m12;
 
860
    float resultT0z = m20*TEX_WIDTH+m22;
 
861
    float result0Tx = m01*TEX_HEIGHT+m02;
 
862
    float result0Ty = m11*TEX_HEIGHT+m12;
 
863
    float result0Tz = m21*TEX_HEIGHT+m22;
 
864
    float mx = resultT0x-m02;
 
865
    float my = resultT0y-m12;
 
866
    float mz = resultT0z-m22;
 
867
    float nx = result0Tx-m02;
 
868
    float ny = result0Ty-m12;
 
869
    float nz = result0Tz-m22;
 
870
 
 
871
    //avec = p x n
 
872
    ax = (py*nz-pz*ny)*TEX_WIDTH; //F_TEX_WIDTH/HEIGHT?
 
873
    ay = (pz*nx-px*nz)*TEX_WIDTH;
 
874
    az = (px*ny-py*nx)*TEX_WIDTH;
 
875
    //bvec = m x p
 
876
    bx = (my*pz-mz*py)*TEX_HEIGHT;
 
877
    by = (mz*px-mx*pz)*TEX_HEIGHT;
 
878
    bz = (mx*py-my*px)*TEX_HEIGHT;
 
879
    //cvec = n x m
 
880
    cx = ny*mz-nz*my;
 
881
    cy = nz*mx-nx*mz;
 
882
    cz = nx*my-ny*mx;
 
883
 
 
884
    //System.out.println("a/b/c: "+ax+" " + ay + " " + az + " " + bx + " " + by + " " + bz + " " + cx + " " + cy + " " + cz);
 
885
 
 
886
    nearPlaneWidth = (parent.rightScreen-parent.leftScreen);
 
887
    nearPlaneHeight = (parent.topScreen-parent.bottomScreen);
 
888
    nearPlaneDepth = parent.nearPlane;
 
889
 
 
890
    // one pixel width in nearPlane coordinates
 
891
    xmult = nearPlaneWidth / parent.width;
 
892
    ymult = nearPlaneHeight / parent.height;
 
893
    // Extra scalings to map screen plane units to pixel units
 
894
//    newax = ax*xmult;
 
895
//    newbx = bx*xmult;
 
896
//    newcx = cx*xmult;
 
897
 
 
898
 
 
899
    //          System.out.println("nearplane: "+ nearPlaneWidth + " " + nearPlaneHeight + " " + nearPlaneDepth);
 
900
    //          System.out.println("mults: "+ xmult + " " + ymult);
 
901
    //          System.out.println("news: "+ newax + " " + newbx + " " + newcx);
 
902
    return true;
 
903
  }
 
904
 
 
905
  /**
 
906
   * Get the texture map location based on the current screen
 
907
   * coordinates.  Assumes precomputeAccurateTexturing() has
 
908
   * been called already for this texture mapping.
 
909
   * @param sx
 
910
   * @param sy
 
911
   * @return
 
912
   */
 
913
  private int getTextureIndex(float sx, float sy, float[] uv) {
 
914
    if (EWJORDAN) System.out.println("Getting texel at "+sx + ", "+sy);
 
915
    //System.out.println("Screen: "+ sx + " " + sy);
 
916
    sx = xmult*(sx-(parent.width/2.0f) +.5f);//+.5f)
 
917
    sy = ymult*(sy-(parent.height/2.0f)+.5f);//+.5f)
 
918
    //sx /= SUBXRES;
 
919
    //sy /= SUBYRES;
 
920
    float sz = nearPlaneDepth;
 
921
    float a = sx * ax + sy * ay + sz * az;
 
922
    float b = sx * bx + sy * by + sz * bz;
 
923
    float c = sx * cx + sy * cy + sz * cz;
 
924
    int u = (int)(a / c);
 
925
    int v = (int)(b / c);
 
926
    uv[0] = a / c;
 
927
    uv[1] = b / c;
 
928
    if (uv[0] < 0) {
 
929
      uv[0] = u = 0;
 
930
    }
 
931
    if (uv[1] < 0) {
 
932
      uv[1] = v = 0;
 
933
    }
 
934
    if (uv[0] >= twidth) {
 
935
      uv[0] = twidth-1;
 
936
      u = twidth-1;
 
937
    }
 
938
    if (uv[1] >= theight) {
 
939
      uv[1] = theight-1;
 
940
      v = theight-1;
 
941
    }
 
942
    int result = v*twidth + u;
 
943
    //System.out.println("a/b/c: "+a + " " + b + " " + c);
 
944
    //System.out.println("cx/y/z: "+cx + " " + cy + " " + cz);
 
945
    //if (result < 0) result = 0;
 
946
    //if (result >= timage.pixels.length-2) result = timage.pixels.length - 2;
 
947
    if (EWJORDAN) System.out.println("Got texel "+result);
 
948
    return result;
 
949
  }
 
950
 
 
951
 
 
952
  public void setIntensities(float ar, float ag, float ab, float aa,
 
953
                             float br, float bg, float bb, float ba,
 
954
                             float cr, float cg, float cb, float ca) {
 
955
    vertices[0][R] = ar;
 
956
    vertices[0][G] = ag;
 
957
    vertices[0][B] = ab;
 
958
    vertices[0][A] = aa;
 
959
    vertices[1][R] = br;
 
960
    vertices[1][G] = bg;
 
961
    vertices[1][B] = bb;
 
962
    vertices[1][A] = ba;
 
963
    vertices[2][R] = cr;
 
964
    vertices[2][G] = cg;
 
965
    vertices[2][B] = cb;
 
966
    vertices[2][A] = ca;
 
967
  }
 
968
}