1
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
4
Part of the Processing project - http://processing.org
6
Copyright (c) 2004-08 Ben Fry and Casey Reas
7
Copyright (c) 2001-04 Massachusetts Institute of Technology
9
This library is free software; you can redistribute it and/or
10
modify it under the terms of the GNU Lesser General Public
11
License as published by the Free Software Foundation; either
12
version 2.1 of the License, or (at your option) any later version.
14
This library is distributed in the hope that it will be useful,
15
but WITHOUT ANY WARRANTY; without even the implied warranty of
16
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
Lesser General Public License for more details.
19
You should have received a copy of the GNU Lesser General
20
Public License along with this library; if not, write to the
21
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
22
Boston, MA 02111-1307 USA
25
package processing.core;
29
* Smoothed triangle renderer for P3D.
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.
34
public class PSmoothTriangle implements PConstants {
36
// really this is "debug" but..
37
private static final boolean EWJORDAN = false;
38
private static final boolean FRY = false;
40
// identical to the constants from PGraphics
42
static final int X = 0; // transformed xyzw
43
static final int Y = 1; // formerly SX SY SZ
44
static final int Z = 2;
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;
51
static final int U = 7; // texture
52
static final int V = 8;
54
static final int DEFAULT_SIZE = 64; // this is needed for spheres
55
float vertices[][] = new float[DEFAULT_SIZE][PGraphics.VERTEX_FIELD_COUNT];
59
// after some fiddling, this seems to produce the best results
60
static final int ZBUFFER_MIN_COVERAGE = 204;
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];
69
// color and xyz are always interpolated
72
boolean interpUV; // is this necessary? could just check timage != null
76
int r2, g2, b2, a2, a2orig;
84
// the parent's width/height,
85
// or if smooth is enabled, parent's w/h scaled
86
// up by the smooth dimension
93
int theight1, twidth1;
96
// temp fix to behave like SMOOTH_IMAGES
97
// TODO ewjordan: can probably remove this variable
98
boolean texture_smooth;
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;
111
int aaleft[] = new int[SUBYRES];
112
int aaright[] = new int[SUBYRES];
113
int aaleftmin, aarightmin;
114
int aaleftmax, aarightmax;
115
int aaleftfull, aarightfull;
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;
130
final private int MODYRES(int y) {
131
return (y & SUBYRES1);
135
public PSmoothTriangle(PGraphics3D iparent) {
141
public void reset(int count) {
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);
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];
166
return vertices[vertexCount++]; // returns v[0], sets vc to 1
170
public void texture(PImage image) {
172
this.tpixels = image.pixels;
173
this.twidth = image.width;
174
this.theight = image.height;
175
this.tformat = image.format;
177
twidth1 = twidth - 1;
178
theight1 = theight - 1;
182
public void render() {
183
if (vertexCount < 3) return;
186
// these may have changed due to a resize()
187
// so they should be refreshed here
188
pixels = parent.pixels;
189
zbuffer = parent.zbuffer;
191
noDepthTest = false;//parent.hints[DISABLE_DEPTH_TEST];
193
// In 0148+, should always be true if this code is called at all
194
//smooth = parent.smooth;
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;
201
width = smooth ? parent.width*SUBXRES : parent.width;
202
height = smooth ? parent.height*SUBYRES : parent.height;
205
height1 = height - 1;
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;
216
for (int i = 0; i < vertexCount; i++) {
217
r[i] = 0; dr[i] = 0; l[i] = 0; dl[i] = 0;
221
for (int i = 0; i < vertexCount; i++) {
222
vertices[i][X] *= SUBXRES;
223
vertices[i][Y] *= SUBYRES;
228
// find top vertex (y is zero at top, higher downwards)
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];
237
if (vertices[i][Y] > ymax) ymax = vertices[i][Y];
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
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
257
int remaining = vertexCount;
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)) {
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);
272
// advance right edge?
273
while ((righty <= y) && (remaining > 0)) {
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);
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);
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();
299
// this increment probably needs to be different
300
// UV and RGB shouldn't be incremented until line is emitted
306
//System.out.println("y/lasty/lastmody = " + y + " " + lastY + " " + lastModY);
311
public void unexpand() {
313
for (int i = 0; i < vertexCount; i++) {
314
vertices[i][X] /= SUBXRES;
315
vertices[i][Y] /= SUBYRES;
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;
327
// this rounding doesn't seem to be relevant with smooth
328
int lx = (int) (l[X] + 0.49999f); // ceil(l[X]-.5);
330
int rx = (int) (r[X] - 0.5f);
331
if (rx > width1) rx = width1;
336
int mody = MODYRES(y);
341
if (firstModY == -1) {
343
aaleftmin = lx; aaleftmax = lx;
344
aarightmin = rx; aarightmax = rx;
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];
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
360
//System.out.println("y is lasty");
363
aaleftfull = aaleftmax/SUBXRES + 1;
364
aarightfull = aarightmin/SUBXRES - 1;
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]);
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;
376
int truelx = 0, truerx = 0;
378
truelx = lx / SUBXRES;
379
truerx = (rx + SUBXRES1) / SUBXRES;
381
lx = aaleftmin / SUBXRES;
382
rx = (aarightmax + SUBXRES1) / SUBXRES;
384
if (rx > parent.width1) rx = parent.width1;
387
// System.out.println("P3D interp uv " + interpUV + " " +
388
// vertices[2][U] + " " + vertices[2][V]);
392
//System.out.println("lx: "+lx + "\nrx: "+rx);
393
for (int x = lx; x <= rx; x++) {
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])) {
401
// map texture based on U, V coords in sp[U] and sp[V]
406
if (tu > twidth1) tu = twidth1;
407
if (tv > theight1) tv = theight1;
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);
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);
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));
435
int tuf1 = (int) (255f * (uv[0] - tu));
436
int tvf1 = (int) (255f * (uv[1] - tv));
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;
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);
450
int p00, p01, p10, p11;
451
int px0, px1; //, pxy;
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;
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);
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;
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;
485
p00 = (pixel00 >> 8) & 0xff; // green
486
p01 = (pixel01 >> 8) & 0xff;
487
p10 = (pixel10 >> 8) & 0xff;
488
p11 = (pixel11 >> 8) & 0xff;
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;
495
p00 = pixel00 & 0xff; // blue
496
p01 = pixel01 & 0xff;
497
p10 = pixel10 & 0xff;
498
p11 = pixel11 & 0xff;
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);
505
} else { // alpha image, only use current fill color
507
tr = (int) (sp[R] * 255);
508
tg = (int) (sp[G] * 255);
509
tb = (int) (sp[B] * 255);
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");
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) {
532
tr = (int) (sp[R]*255);
533
tg = (int) (sp[G]*255);
534
tb = (int) (sp[B]*255);
536
ta = (((int) (sp[A]*255)) * ta) >> 8;
542
ta = (a2orig * ta) >> 8;
545
} else { // RGB or ARGB
546
ta = (tformat == RGB) ? 255 : (tpixel >> 24) & 0xff;
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;
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;
561
if ((ta == 254) || (ta == 255)) { // if (ta & 0xf8) would be good
563
pixels[offset+x] = 0xff000000 | (tr << 16) | (tg << 8) | tb;
564
zbuffer[offset+x] = sp[Z];
566
// blend with pixel on screen
568
int r1 = (pixels[offset+x] >> 16) & 0xff;
569
int g1 = (pixels[offset+x] >> 8) & 0xff;
570
int b1 = (pixels[offset+x]) & 0xff;
575
(((tr*ta + r1*a1) >> 8) << 16) |
576
((tg*ta + g1*a1) & 0xff00) |
577
((tb*ta + b1*a1) >> 8);
579
//System.out.println("17");
581
if (ta > ZBUFFER_MIN_COVERAGE) zbuffer[offset+x] = sp[Z];
584
//System.out.println("18");
586
} else { // no image applied
587
int weight = smooth ? coverage(x) : 255;
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;
595
rgba = 0xff000000 | (r2 << 16) | (g2 << 8) | b2;
598
if (a2orig != 255) weight = (weight * a2orig) >> 8;
602
// no blend, no aa, just the rgba
603
pixels[offset+x] = rgba;
604
zbuffer[offset+x] = sp[Z];
607
int r1 = (pixels[offset+x] >> 16) & 0xff;
608
int g1 = (pixels[offset+x] >> 8) & 0xff;
609
int b1 = (pixels[offset+x]) & 0xff;
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));
619
if (a2 > ZBUFFER_MIN_COVERAGE) zbuffer[offset+x] = sp[Z];
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))) {
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)) {
644
int pixelLeft = x*SUBXRES; // huh?
645
int pixelRight = pixelLeft + 8;
648
for (int i = firstModY; i <= lastModY; i++) {
649
if ((aaleft[i] > pixelRight) || (aaright[i] < pixelLeft)) {
652
// does this need a +1 ?
653
amt += ((aaright[i] < pixelRight ? aaright[i] : pixelRight) -
654
(aaleft[i] > pixelLeft ? aaleft[i] : pixelLeft));
657
return (amt == 256) ? 255 : amt;
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];
668
dp[X] = (p2[X] - p1[X]) / delta;
669
p[X] = p1[X] + dp[X] * fraction;
672
dp[Z] = (p2[Z] - p1[Z]) / delta;
673
p[Z] = p1[Z] + dp[Z] * fraction;
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;
688
dp[U] = (p2[U] - p1[U]) / delta;
689
dp[V] = (p2[V] - p1[V]) / delta;
692
//p[U] = p1[U]; //+ dp[U] * fraction;
693
//p[V] = p1[V]; //+ dp[V] * fraction;
696
p[U] = p1[U] + dp[U] * fraction;
697
p[V] = p1[V] + dp[V] * fraction;
699
if (FRY) System.out.println("inc y p[U] p[V] = " + p[U] + " " + p[V]);
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];
715
dp[X] = (p2[X] - p1[X]) / delta;
716
p[X] = p1[X] + dp[X] * fraction;
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]);
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;
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;
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;
750
p[U] = p1[U] + dp[U] * fraction;
751
p[V] = p1[V] + dp[V] * fraction;
756
private void increment(float p[], float dp[]) {
757
if (interpX) p[X] += dp[X];
758
if (interpZ) p[Z] += dp[Z];
768
if (FRY) System.out.println("increment() " + p[V] + " " + dp[V]);
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()
781
public void setCamVertices(float x0, float y0, float z0,
782
float x1, float y1, float z1,
783
float x2, float y2, float z2) {
797
public void setVertices(float x0, float y0, float z0,
798
float x1, float y1, float z1,
799
float x2, float y2, float z2) {
816
* Precompute a bunch of variables needed to perform
818
* @return True unless texture mapping is degenerate
820
boolean precomputeAccurateTexturing() {
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,
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();
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;
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]);
855
float TEX_WIDTH = this.twidth;
856
float TEX_HEIGHT = this.theight;
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;
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;
876
bx = (my*pz-mz*py)*TEX_HEIGHT;
877
by = (mz*px-mx*pz)*TEX_HEIGHT;
878
bz = (mx*py-my*px)*TEX_HEIGHT;
884
//System.out.println("a/b/c: "+ax+" " + ay + " " + az + " " + bx + " " + by + " " + bz + " " + cx + " " + cy + " " + cz);
886
nearPlaneWidth = (parent.rightScreen-parent.leftScreen);
887
nearPlaneHeight = (parent.topScreen-parent.bottomScreen);
888
nearPlaneDepth = parent.nearPlane;
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
899
// System.out.println("nearplane: "+ nearPlaneWidth + " " + nearPlaneHeight + " " + nearPlaneDepth);
900
// System.out.println("mults: "+ xmult + " " + ymult);
901
// System.out.println("news: "+ newax + " " + newbx + " " + newcx);
906
* Get the texture map location based on the current screen
907
* coordinates. Assumes precomputeAccurateTexturing() has
908
* been called already for this texture mapping.
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)
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);
934
if (uv[0] >= twidth) {
938
if (uv[1] >= theight) {
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);
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) {