removing P2D and P3D

This commit is contained in:
benfry
2011-06-18 17:08:05 +00:00
parent 7de742dde9
commit 1bf0e22ce8
8 changed files with 8 additions and 13487 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry excluding="processing/core/PSmoothTriangle.java|processing/core/PGraphics3D.java|processing/core/PLine.java|processing/core/PTriangle.java|processing/core/PGraphics2D.java|processing/core/PPolygon.java" kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="output" path="bin"/>
</classpath>
+7 -8
View File
@@ -3,7 +3,7 @@
/*
Part of the Processing project - http://processing.org
Copyright (c) 2004-08 Ben Fry and Casey Reas
Copyright (c) 2004-11 Ben Fry and Casey Reas
Copyright (c) 2001-04 Massachusetts Institute of Technology
This library is free software; you can redistribute it and/or
@@ -118,13 +118,12 @@ public interface PConstants {
// renderers known to processing.core
static final String P2D = "processing.core.PGraphics2D";
static final String P3D = "processing.core.PGraphics3D";
static final String JAVA2D = "processing.core.PGraphicsJava2D";
static final String OPENGL = "processing.opengl.PGraphicsOpenGL";
static final String OPENGL2 = "processing.opengl2.PGraphicsOpenGL2";
static final String PDF = "processing.pdf.PGraphicsPDF";
static final String DXF = "processing.dxf.RawDXF";
static final String P2D = "processing.core.PGraphicsJava2D";
static final String P3D = "processing.opengl.PGraphicsOpenGL";
static final String JAVA2D = "processing.core.PGraphicsJava2D";
static final String OPENGL = "processing.opengl.PGraphicsOpenGL";
static final String PDF = "processing.pdf.PGraphicsPDF";
static final String DXF = "processing.dxf.RawDXF";
// platform IDs for PApplet.platform
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-701
View File
@@ -1,701 +0,0 @@
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2004-08 Ben Fry and Casey Reas
Copyright (c) 2001-04 Massachusetts Institute of Technology
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
*/
package processing.core;
/**
* Z-buffer polygon rendering object used by PGraphics2D.
*/
public class PPolygon implements PConstants {
static final int DEFAULT_SIZE = 64; // this is needed for spheres
float vertices[][] = new float[DEFAULT_SIZE][VERTEX_FIELD_COUNT];
int vertexCount;
float r[] = new float[DEFAULT_SIZE]; // storage used by incrementalize
float dr[] = new float[DEFAULT_SIZE];
float l[] = new float[DEFAULT_SIZE]; // more storage for incrementalize
float dl[] = new float[DEFAULT_SIZE];
float sp[] = new float[DEFAULT_SIZE]; // temporary storage for scanline
float sdp[] = new float[DEFAULT_SIZE];
protected boolean interpX;
protected boolean interpUV; // is this necessary? could just check timage != null
protected boolean interpARGB;
private int rgba;
private int r2, g2, b2, a2, a2orig;
PGraphics parent;
int[] pixels;
// the parent's width/height,
// or if smooth is enabled, parent's w/h scaled
// up by the smooth dimension
int width, height;
int width1, height1;
PImage timage;
int[] tpixels;
int theight, twidth;
int theight1, twidth1;
int tformat;
// for anti-aliasing
static final int SUBXRES = 8;
static final int SUBXRES1 = 7;
static final int SUBYRES = 8;
static final int SUBYRES1 = 7;
static final int MAX_COVERAGE = SUBXRES * SUBYRES;
boolean smooth;
int firstModY;
int lastModY;
int lastY;
int aaleft[] = new int[SUBYRES];
int aaright[] = new int[SUBYRES];
int aaleftmin, aarightmin;
int aaleftmax, aarightmax;
int aaleftfull, aarightfull;
final private int MODYRES(int y) {
return (y & SUBYRES1);
}
public PPolygon(PGraphics iparent) {
parent = iparent;
reset(0);
}
protected void reset(int count) {
vertexCount = count;
interpX = true;
// interpZ = true;
interpUV = false;
interpARGB = true;
timage = null;
}
protected float[] nextVertex() {
if (vertexCount == vertices.length) {
float temp[][] = new float[vertexCount<<1][VERTEX_FIELD_COUNT];
System.arraycopy(vertices, 0, temp, 0, vertexCount);
vertices = temp;
r = new float[vertices.length];
dr = new float[vertices.length];
l = new float[vertices.length];
dl = new float[vertices.length];
sp = new float[vertices.length];
sdp = new float[vertices.length];
}
return vertices[vertexCount++]; // returns v[0], sets vc to 1
}
/**
* Return true if this vertex is redundant. If so, will also
* decrement the vertex count.
*/
/*
public boolean redundantVertex(float x, float y, float z) {
// because vertexCount will be 2 when setting vertex[1]
if (vertexCount < 2) return false;
// vertexCount-1 is the current vertex that would be used
// vertexCount-2 would be the previous feller
if ((Math.abs(vertices[vertexCount-2][MX] - x) < EPSILON) &&
(Math.abs(vertices[vertexCount-2][MY] - y) < EPSILON) &&
(Math.abs(vertices[vertexCount-2][MZ] - z) < EPSILON)) {
vertexCount--;
return true;
}
return false;
}
*/
protected void texture(PImage image) {
this.timage = image;
if (image != null) {
this.tpixels = image.pixels;
this.twidth = image.width;
this.theight = image.height;
this.tformat = image.format;
twidth1 = twidth - 1;
theight1 = theight - 1;
interpUV = true;
} else {
interpUV = false;
}
}
protected void renderPolygon(float[][] v, int count) {
vertices = v;
vertexCount = count;
if (r.length < vertexCount) {
r = new float[vertexCount]; // storage used by incrementalize
dr = new float[vertexCount];
l = new float[vertexCount]; // more storage for incrementalize
dl = new float[vertexCount];
sp = new float[vertexCount]; // temporary storage for scanline
sdp = new float[vertexCount];
}
render();
checkExpand();
}
protected void renderTriangle(float[] v1, float[] v2, float[] v3) {
// Calling code will have already done reset(3).
// Can't do it here otherwise would nuke any texture settings.
vertices[0] = v1;
vertices[1] = v2;
vertices[2] = v3;
render();
checkExpand();
}
protected void checkExpand() {
if (smooth) {
for (int i = 0; i < vertexCount; i++) {
vertices[i][TX] /= SUBXRES;
vertices[i][TY] /= SUBYRES;
}
}
}
protected void render() {
if (vertexCount < 3) return;
// these may have changed due to a resize()
// so they should be refreshed here
pixels = parent.pixels;
//zbuffer = parent.zbuffer;
// noDepthTest = parent.hints[DISABLE_DEPTH_TEST];
smooth = parent.smooth;
// by default, text turns on smooth for the textures
// themselves. but this should be shut off if the hint
// for DISABLE_TEXT_SMOOTH is set.
// texture_smooth = true;
width = smooth ? parent.width*SUBXRES : parent.width;
height = smooth ? parent.height*SUBYRES : parent.height;
width1 = width - 1;
height1 = height - 1;
if (!interpARGB) {
r2 = (int) (vertices[0][R] * 255);
g2 = (int) (vertices[0][G] * 255);
b2 = (int) (vertices[0][B] * 255);
a2 = (int) (vertices[0][A] * 255);
a2orig = a2; // save an extra copy
rgba = 0xff000000 | (r2 << 16) | (g2 << 8) | b2;
}
for (int i = 0; i < vertexCount; i++) {
r[i] = 0; dr[i] = 0; l[i] = 0; dl[i] = 0;
}
/*
// hack to not make polygons fly into the screen
if (parent.hints[DISABLE_FLYING_POO]) {
float nwidth2 = -width * 2;
float nheight2 = -height * 2;
float width2 = width * 2;
float height2 = height * 2;
for (int i = 0; i < vertexCount; i++) {
if ((vertices[i][TX] < nwidth2) ||
(vertices[i][TX] > width2) ||
(vertices[i][TY] < nheight2) ||
(vertices[i][TY] > height2)) {
return; // this is a bad poly
}
}
}
*/
// for (int i = 0; i < 4; i++) {
// System.out.println(vertices[i][R] + " " + vertices[i][G] + " " + vertices[i][B]);
// }
// System.out.println();
if (smooth) {
for (int i = 0; i < vertexCount; i++) {
vertices[i][TX] *= SUBXRES;
vertices[i][TY] *= SUBYRES;
}
firstModY = -1;
}
// find top vertex (y is zero at top, higher downwards)
int topi = 0;
float ymin = vertices[0][TY];
float ymax = vertices[0][TY]; // fry 031001
for (int i = 1; i < vertexCount; i++) {
if (vertices[i][TY] < ymin) {
ymin = vertices[i][TY];
topi = i;
}
if (vertices[i][TY] > ymax) {
ymax = vertices[i][TY];
}
}
// the last row is an exceptional case, because there won't
// necessarily be 8 rows of subpixel lines that will force
// the final line to render. so instead, the algo keeps track
// of the lastY (in subpixel resolution) that will be rendered
// and that will force a scanline to happen the same as
// every eighth in the other situations
//lastY = -1; // fry 031001
lastY = (int) (ymax - 0.5f); // global to class bc used by other fxns
int lefti = topi; // li, index of left vertex
int righti = topi; // ri, index of right vertex
int y = (int) (ymin + 0.5f); // current scan line
int lefty = y - 1; // lower end of left edge
int righty = y - 1; // lower end of right edge
interpX = true;
int remaining = vertexCount;
// scan in y, activating new edges on left & right
// as scan line passes over new vertices
while (remaining > 0) {
// advance left edge?
while ((lefty <= y) && (remaining > 0)) {
remaining--;
// step ccw down left side
int i = (lefti != 0) ? (lefti-1) : (vertexCount-1);
incrementalizeY(vertices[lefti], vertices[i], l, dl, y);
lefty = (int) (vertices[i][TY] + 0.5f);
lefti = i;
}
// advance right edge?
while ((righty <= y) && (remaining > 0)) {
remaining--;
// step cw down right edge
int i = (righti != vertexCount-1) ? (righti + 1) : 0;
incrementalizeY(vertices[righti], vertices[i], r, dr, y);
righty = (int) (vertices[i][TY] + 0.5f);
righti = i;
}
// do scanlines till end of l or r edge
while (y < lefty && y < righty) {
// this doesn't work because it's not always set here
//if (remaining == 0) {
//lastY = (lefty < righty) ? lefty-1 : righty-1;
//System.out.println("lastY is " + lastY);
//}
if ((y >= 0) && (y < height)) {
//try { // hopefully this bug is fixed
if (l[TX] <= r[TX]) scanline(y, l, r);
else scanline(y, r, l);
//} catch (ArrayIndexOutOfBoundsException e) {
//e.printStackTrace();
//}
}
y++;
// this increment probably needs to be different
// UV and RGB shouldn't be incremented until line is emitted
increment(l, dl);
increment(r, dr);
}
}
//if (smooth) {
//System.out.println("y/lasty/lastmody = " + y + " " + lastY + " " + lastModY);
//}
}
private void scanline(int y, float l[], float r[]) {
//System.out.println("scanline " + y);
for (int i = 0; i < vertexCount; i++) { // should be moved later
sp[i] = 0; sdp[i] = 0;
}
// this rounding doesn't seem to be relevant with smooth
int lx = (int) (l[TX] + 0.49999f); // ceil(l[TX]-.5);
if (lx < 0) lx = 0;
int rx = (int) (r[TX] - 0.5f);
if (rx > width1) rx = width1;
if (lx > rx) return;
if (smooth) {
int mody = MODYRES(y);
aaleft[mody] = lx;
aaright[mody] = rx;
if (firstModY == -1) {
firstModY = mody;
aaleftmin = lx; aaleftmax = lx;
aarightmin = rx; aarightmax = rx;
} else {
if (aaleftmin > aaleft[mody]) aaleftmin = aaleft[mody];
if (aaleftmax < aaleft[mody]) aaleftmax = aaleft[mody];
if (aarightmin > aaright[mody]) aarightmin = aaright[mody];
if (aarightmax < aaright[mody]) aarightmax = aaright[mody];
}
lastModY = mody; // moved up here (before the return) 031001
// not the eighth (or lastY) line, so not scanning this time
if ((mody != SUBYRES1) && (y != lastY)) return;
//lastModY = mody; // eeK! this was missing
//return;
//if (y == lastY) {
//System.out.println("y is lasty");
//}
//lastModY = mody;
aaleftfull = aaleftmax/SUBXRES + 1;
aarightfull = aarightmin/SUBXRES - 1;
}
// this is the setup, based on lx
incrementalizeX(l, r, sp, sdp, lx);
// scan in x, generating pixels
// using parent.width to get actual pixel index
// rather than scaled by smooth factor
int offset = smooth ? parent.width * (y / SUBYRES) : parent.width*y;
int truelx = 0, truerx = 0;
if (smooth) {
truelx = lx / SUBXRES;
truerx = (rx + SUBXRES1) / SUBXRES;
lx = aaleftmin / SUBXRES;
rx = (aarightmax + SUBXRES1) / SUBXRES;
if (lx < 0) lx = 0;
if (rx > parent.width1) rx = parent.width1;
}
interpX = false;
int tr, tg, tb, ta;
// System.out.println("P2D interp uv " + interpUV + " " +
// vertices[2][U] + " " + vertices[2][V]);
for (int x = lx; x <= rx; x++) {
// map texture based on U, V coords in sp[U] and sp[V]
if (interpUV) {
int tu = (int) (sp[U] * twidth);
int tv = (int) (sp[V] * theight);
if (tu > twidth1) tu = twidth1;
if (tv > theight1) tv = theight1;
if (tu < 0) tu = 0;
if (tv < 0) tv = 0;
int txy = tv*twidth + tu;
int tuf1 = (int) (255f * (sp[U]*twidth - (float)tu));
int tvf1 = (int) (255f * (sp[V]*theight - (float)tv));
// the closer sp[U or V] is to the decimal being zero
// the more coverage it should get of the original pixel
int tuf = 255 - tuf1;
int tvf = 255 - tvf1;
// this code sucks! filled with bugs and slow as hell!
int pixel00 = tpixels[txy];
int pixel01 = (tv < theight1) ?
tpixels[txy + twidth] : tpixels[txy];
int pixel10 = (tu < twidth1) ?
tpixels[txy + 1] : tpixels[txy];
int pixel11 = ((tv < theight1) && (tu < twidth1)) ?
tpixels[txy + twidth + 1] : tpixels[txy];
int p00, p01, p10, p11;
int px0, px1; //, pxy;
// calculate alpha component (ta)
if (tformat == ALPHA) {
px0 = (pixel00*tuf + pixel10*tuf1) >> 8;
px1 = (pixel01*tuf + pixel11*tuf1) >> 8;
ta = (((px0*tvf + px1*tvf1) >> 8) *
(interpARGB ? ((int) (sp[A]*255)) : a2orig)) >> 8;
} else if (tformat == ARGB) {
p00 = (pixel00 >> 24) & 0xff;
p01 = (pixel01 >> 24) & 0xff;
p10 = (pixel10 >> 24) & 0xff;
p11 = (pixel11 >> 24) & 0xff;
px0 = (p00*tuf + p10*tuf1) >> 8;
px1 = (p01*tuf + p11*tuf1) >> 8;
ta = (((px0*tvf + px1*tvf1) >> 8) *
(interpARGB ? ((int) (sp[A]*255)) : a2orig)) >> 8;
} else { // RGB image, no alpha
ta = interpARGB ? ((int) (sp[A]*255)) : a2orig;
}
// calculate r,g,b components (tr, tg, tb)
if ((tformat == RGB) || (tformat == ARGB)) {
p00 = (pixel00 >> 16) & 0xff; // red
p01 = (pixel01 >> 16) & 0xff;
p10 = (pixel10 >> 16) & 0xff;
p11 = (pixel11 >> 16) & 0xff;
px0 = (p00*tuf + p10*tuf1) >> 8;
px1 = (p01*tuf + p11*tuf1) >> 8;
tr = (((px0*tvf + px1*tvf1) >> 8) *
(interpARGB ? ((int) (sp[R]*255)) : r2)) >> 8;
p00 = (pixel00 >> 8) & 0xff; // green
p01 = (pixel01 >> 8) & 0xff;
p10 = (pixel10 >> 8) & 0xff;
p11 = (pixel11 >> 8) & 0xff;
px0 = (p00*tuf + p10*tuf1) >> 8;
px1 = (p01*tuf + p11*tuf1) >> 8;
tg = (((px0*tvf + px1*tvf1) >> 8) *
(interpARGB ? ((int) (sp[G]*255)) : g2)) >> 8;
p00 = pixel00 & 0xff; // blue
p01 = pixel01 & 0xff;
p10 = pixel10 & 0xff;
p11 = pixel11 & 0xff;
px0 = (p00*tuf + p10*tuf1) >> 8;
px1 = (p01*tuf + p11*tuf1) >> 8;
tb = (((px0*tvf + px1*tvf1) >> 8) *
(interpARGB ? ((int) (sp[B]*255)) : b2)) >> 8;
} else { // alpha image, only use current fill color
if (interpARGB) {
tr = (int) (sp[R] * 255);
tg = (int) (sp[G] * 255);
tb = (int) (sp[B] * 255);
} else {
tr = r2;
tg = g2;
tb = b2;
}
}
int weight = smooth ? coverage(x) : 255;
if (weight != 255) ta = ta*weight >> 8;
if ((ta == 254) || (ta == 255)) { // if (ta & 0xf8) would be good
// no need to blend
pixels[offset+x] = 0xff000000 | (tr << 16) | (tg << 8) | tb;
} else {
// blend with pixel on screen
int a1 = 255-ta;
int r1 = (pixels[offset+x] >> 16) & 0xff;
int g1 = (pixels[offset+x] >> 8) & 0xff;
int b1 = (pixels[offset+x]) & 0xff;
pixels[offset+x] = 0xff000000 |
(((tr*ta + r1*a1) >> 8) << 16) |
((tg*ta + g1*a1) & 0xff00) |
((tb*ta + b1*a1) >> 8);
}
} else { // no image applied
int weight = smooth ? coverage(x) : 255;
if (interpARGB) {
r2 = (int) (sp[R] * 255);
g2 = (int) (sp[G] * 255);
b2 = (int) (sp[B] * 255);
if (sp[A] != 1) weight = (weight * ((int) (sp[A] * 255))) >> 8;
if (weight == 255) {
rgba = 0xff000000 | (r2 << 16) | (g2 << 8) | b2;
}
} else {
if (a2orig != 255) weight = (weight * a2orig) >> 8;
}
if (weight == 255) {
// no blend, no aa, just the rgba
pixels[offset+x] = rgba;
//zbuffer[offset+x] = sp[Z];
} else {
int r1 = (pixels[offset+x] >> 16) & 0xff;
int g1 = (pixels[offset+x] >> 8) & 0xff;
int b1 = (pixels[offset+x]) & 0xff;
a2 = weight;
int a1 = 255 - a2;
pixels[offset+x] = (0xff000000 |
((r1*a1 + r2*a2) >> 8) << 16 |
// use & instead of >> and << below
((g1*a1 + g2*a2) >> 8) << 8 |
((b1*a1 + b2*a2) >> 8));
}
}
// if smooth enabled, don't increment values
// for the pixel in the stretch out version
// of the scanline used to get smooth edges.
if (!smooth || ((x >= truelx) && (x <= truerx))) {
increment(sp, sdp);
}
}
firstModY = -1;
interpX = true;
}
// x is in screen, not huge 8x coordinates
private int coverage(int x) {
if ((x >= aaleftfull) && (x <= aarightfull) &&
// important since not all SUBYRES lines may have been covered
(firstModY == 0) && (lastModY == SUBYRES1)) {
return 255;
}
int pixelLeft = x*SUBXRES; // huh?
int pixelRight = pixelLeft + 8;
int amt = 0;
for (int i = firstModY; i <= lastModY; i++) {
if ((aaleft[i] > pixelRight) || (aaright[i] < pixelLeft)) {
continue;
}
// does this need a +1 ?
amt += ((aaright[i] < pixelRight ? aaright[i] : pixelRight) -
(aaleft[i] > pixelLeft ? aaleft[i] : pixelLeft));
}
amt <<= 2;
return (amt == 256) ? 255 : amt;
}
private void incrementalizeY(float p1[], float p2[],
float p[], float dp[], int y) {
float delta = p2[TY] - p1[TY];
if (delta == 0) delta = 1;
float fraction = y + 0.5f - p1[TY];
if (interpX) {
dp[TX] = (p2[TX] - p1[TX]) / delta;
p[TX] = p1[TX] + dp[TX] * fraction;
}
if (interpARGB) {
dp[R] = (p2[R] - p1[R]) / delta;
dp[G] = (p2[G] - p1[G]) / delta;
dp[B] = (p2[B] - p1[B]) / delta;
dp[A] = (p2[A] - p1[A]) / delta;
p[R] = p1[R] + dp[R] * fraction;
p[G] = p1[G] + dp[G] * fraction;
p[B] = p1[B] + dp[B] * fraction;
p[A] = p1[A] + dp[A] * fraction;
}
if (interpUV) {
dp[U] = (p2[U] - p1[U]) / delta;
dp[V] = (p2[V] - p1[V]) / delta;
p[U] = p1[U] + dp[U] * fraction;
p[V] = p1[V] + dp[V] * fraction;
}
}
private void incrementalizeX(float p1[], float p2[],
float p[], float dp[], int x) {
float delta = p2[TX] - p1[TX];
if (delta == 0) delta = 1;
float fraction = x + 0.5f - p1[TX];
if (smooth) {
delta /= SUBXRES;
fraction /= SUBXRES;
}
if (interpX) {
dp[TX] = (p2[TX] - p1[TX]) / delta;
p[TX] = p1[TX] + dp[TX] * fraction;
}
if (interpARGB) {
dp[R] = (p2[R] - p1[R]) / delta;
dp[G] = (p2[G] - p1[G]) / delta;
dp[B] = (p2[B] - p1[B]) / delta;
dp[A] = (p2[A] - p1[A]) / delta;
p[R] = p1[R] + dp[R] * fraction;
p[G] = p1[G] + dp[G] * fraction;
p[B] = p1[B] + dp[B] * fraction;
p[A] = p1[A] + dp[A] * fraction;
}
if (interpUV) {
dp[U] = (p2[U] - p1[U]) / delta;
dp[V] = (p2[V] - p1[V]) / delta;
p[U] = p1[U] + dp[U] * fraction;
p[V] = p1[V] + dp[V] * fraction;
}
}
private void increment(float p[], float dp[]) {
if (interpX) p[TX] += dp[TX];
if (interpARGB) {
p[R] += dp[R];
p[G] += dp[G];
p[B] += dp[B];
p[A] += dp[A];
}
if (interpUV) {
p[U] += dp[U];
p[V] += dp[V];
}
}
}
@@ -1,970 +0,0 @@
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2004-08 Ben Fry and Casey Reas
Copyright (c) 2001-04 Massachusetts Institute of Technology
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
*/
package processing.core;
/**
* Smoothed triangle renderer for P3D.
*
* Based off of the PPolygon class in old versions of Processing.
* Name and location of this class will change in a future release.
*/
public class PSmoothTriangle implements PConstants {
// really this is "debug" but..
private static final boolean EWJORDAN = false;
private static final boolean FRY = false;
// identical to the constants from PGraphics
static final int X = 0; // transformed xyzw
static final int Y = 1; // formerly SX SY SZ
static final int Z = 2;
static final int R = 3; // actual rgb, after lighting
static final int G = 4; // fill stored here, transform in place
static final int B = 5;
static final int A = 6;
static final int U = 7; // texture
static final int V = 8;
static final int DEFAULT_SIZE = 64; // this is needed for spheres
float vertices[][] = new float[DEFAULT_SIZE][PGraphics.VERTEX_FIELD_COUNT];
int vertexCount;
// after some fiddling, this seems to produce the best results
static final int ZBUFFER_MIN_COVERAGE = 204;
float r[] = new float[DEFAULT_SIZE]; // storage used by incrementalize
float dr[] = new float[DEFAULT_SIZE];
float l[] = new float[DEFAULT_SIZE]; // more storage for incrementalize
float dl[] = new float[DEFAULT_SIZE];
float sp[] = new float[DEFAULT_SIZE]; // temporary storage for scanline
float sdp[] = new float[DEFAULT_SIZE];
// color and xyz are always interpolated
boolean interpX;
boolean interpZ;
boolean interpUV; // is this necessary? could just check timage != null
boolean interpARGB;
int rgba;
int r2, g2, b2, a2, a2orig;
boolean noDepthTest;
boolean updateZBuffer;
PGraphics3D parent;
int pixels[];
float[] zbuffer;
// the parent's width/height,
// or if smooth is enabled, parent's w/h scaled
// up by the smooth dimension
int width, height;
int width1, height1;
PImage timage;
int tpixels[];
int theight, twidth;
int theight1, twidth1;
int tformat;
// temp fix to behave like SMOOTH_IMAGES
// TODO ewjordan: can probably remove this variable
boolean texture_smooth;
// for anti-aliasing
static final int SUBXRES = 8;
static final int SUBXRES1 = 7;
static final int SUBYRES = 8;
static final int SUBYRES1 = 7;
static final int MAX_COVERAGE = SUBXRES * SUBYRES;
boolean smooth;
int firstModY;
int lastModY;
int lastY;
int aaleft[] = new int[SUBYRES];
int aaright[] = new int[SUBYRES];
int aaleftmin, aarightmin;
int aaleftmax, aarightmax;
int aaleftfull, aarightfull;
/* Variables needed for accurate texturing. */
//private PMatrix textureMatrix = new PMatrix3D();
private float[] camX = new float[3];
private float[] camY = new float[3];
private float[] camZ = new float[3];
private float ax,ay,az;
private float bx,by,bz;
private float cx,cy,cz;
private float nearPlaneWidth, nearPlaneHeight, nearPlaneDepth;
//private float newax, newbx, newcx;
private float xmult, ymult;
final private int MODYRES(int y) {
return (y & SUBYRES1);
}
public PSmoothTriangle(PGraphics3D iparent) {
parent = iparent;
reset(0);
}
public void reset(int count) {
vertexCount = count;
interpX = true;
interpZ = true;
interpUV = false;
interpARGB = true;
timage = null;
}
public float[] nextVertex() {
if (vertexCount == vertices.length) {
//parent.message(CHATTER, "re-allocating for " +
// (vertexCount*2) + " vertices");
float temp[][] = new float[vertexCount<<1][PGraphics.VERTEX_FIELD_COUNT];
System.arraycopy(vertices, 0, temp, 0, vertexCount);
vertices = temp;
r = new float[vertices.length];
dr = new float[vertices.length];
l = new float[vertices.length];
dl = new float[vertices.length];
sp = new float[vertices.length];
sdp = new float[vertices.length];
}
return vertices[vertexCount++]; // returns v[0], sets vc to 1
}
public void texture(PImage image) {
this.timage = image;
this.tpixels = image.pixels;
this.twidth = image.width;
this.theight = image.height;
this.tformat = image.format;
twidth1 = twidth - 1;
theight1 = theight - 1;
interpUV = true;
}
public void render() {
if (vertexCount < 3) return;
smooth = true;//TODO
// these may have changed due to a resize()
// so they should be refreshed here
pixels = parent.pixels;
zbuffer = parent.zbuffer;
noDepthTest = parent.hints[DISABLE_DEPTH_TEST];
updateZBuffer = !parent.hints[DISABLE_DEPTH_MASK];
// In 0148+, should always be true if this code is called at all
//smooth = parent.smooth;
// by default, text turns on smooth for the textures
// themselves. but this should be shut off if the hint
// for DISABLE_TEXT_SMOOTH is set.
texture_smooth = true;
width = smooth ? parent.width*SUBXRES : parent.width;
height = smooth ? parent.height*SUBYRES : parent.height;
width1 = width - 1;
height1 = height - 1;
if (!interpARGB) {
r2 = (int) (vertices[0][R] * 255);
g2 = (int) (vertices[0][G] * 255);
b2 = (int) (vertices[0][B] * 255);
a2 = (int) (vertices[0][A] * 255);
a2orig = a2; // save an extra copy
rgba = 0xff000000 | (r2 << 16) | (g2 << 8) | b2;
}
for (int i = 0; i < vertexCount; i++) {
r[i] = 0; dr[i] = 0; l[i] = 0; dl[i] = 0;
}
if (smooth) {
for (int i = 0; i < vertexCount; i++) {
vertices[i][X] *= SUBXRES;
vertices[i][Y] *= SUBYRES;
}
firstModY = -1;
}
// find top vertex (y is zero at top, higher downwards)
int topi = 0;
float ymin = vertices[0][Y];
float ymax = vertices[0][Y]; // fry 031001
for (int i = 1; i < vertexCount; i++) {
if (vertices[i][Y] < ymin) {
ymin = vertices[i][Y];
topi = i;
}
if (vertices[i][Y] > ymax) ymax = vertices[i][Y];
}
// the last row is an exceptional case, because there won't
// necessarily be 8 rows of subpixel lines that will force
// the final line to render. so instead, the algo keeps track
// of the lastY (in subpixel resolution) that will be rendered
// and that will force a scanline to happen the same as
// every eighth in the other situations
//lastY = -1; // fry 031001
lastY = (int) (ymax - 0.5f); // global to class bc used by other fxns
int lefti = topi; // li, index of left vertex
int righti = topi; // ri, index of right vertex
int y = (int) (ymin + 0.5f); // current scan line
int lefty = y - 1; // lower end of left edge
int righty = y - 1; // lower end of right edge
interpX = true;
int remaining = vertexCount;
// scan in y, activating new edges on left & right
// as scan line passes over new vertices
while (remaining > 0) {
// advance left edge?
while ((lefty <= y) && (remaining > 0)) {
remaining--;
// step ccw down left side
int i = (lefti != 0) ? (lefti-1) : (vertexCount-1);
incrementalize_y(vertices[lefti], vertices[i], l, dl, y);
lefty = (int) (vertices[i][Y] + 0.5f);
lefti = i;
}
// advance right edge?
while ((righty <= y) && (remaining > 0)) {
remaining--;
// step cw down right edge
int i = (righti != vertexCount-1) ? (righti + 1) : 0;
incrementalize_y(vertices[righti], vertices[i], r, dr, y);
righty = (int) (vertices[i][Y] + 0.5f);
righti = i;
}
// do scanlines till end of l or r edge
while (y < lefty && y < righty) {
// this doesn't work because it's not always set here
//if (remaining == 0) {
//lastY = (lefty < righty) ? lefty-1 : righty-1;
//System.out.println("lastY is " + lastY);
//}
if ((y >= 0) && (y < height)) {
//try { // hopefully this bug is fixed
if (l[X] <= r[X]) scanline(y, l, r);
else scanline(y, r, l);
//} catch (ArrayIndexOutOfBoundsException e) {
//e.printStackTrace();
//}
}
y++;
// this increment probably needs to be different
// UV and RGB shouldn't be incremented until line is emitted
increment(l, dl);
increment(r, dr);
}
}
//if (smooth) {
//System.out.println("y/lasty/lastmody = " + y + " " + lastY + " " + lastModY);
//}
}
public void unexpand() {
if (smooth) {
for (int i = 0; i < vertexCount; i++) {
vertices[i][X] /= SUBXRES;
vertices[i][Y] /= SUBYRES;
}
}
}
private void scanline(int y, float l[], float r[]) {
//System.out.println("scanline " + y);
for (int i = 0; i < vertexCount; i++) { // should be moved later
sp[i] = 0; sdp[i] = 0;
}
// this rounding doesn't seem to be relevant with smooth
int lx = (int) (l[X] + 0.49999f); // ceil(l[X]-.5);
if (lx < 0) lx = 0;
int rx = (int) (r[X] - 0.5f);
if (rx > width1) rx = width1;
if (lx > rx) return;
if (smooth) {
int mody = MODYRES(y);
aaleft[mody] = lx;
aaright[mody] = rx;
if (firstModY == -1) {
firstModY = mody;
aaleftmin = lx; aaleftmax = lx;
aarightmin = rx; aarightmax = rx;
} else {
if (aaleftmin > aaleft[mody]) aaleftmin = aaleft[mody];
if (aaleftmax < aaleft[mody]) aaleftmax = aaleft[mody];
if (aarightmin > aaright[mody]) aarightmin = aaright[mody];
if (aarightmax < aaright[mody]) aarightmax = aaright[mody];
}
lastModY = mody; // moved up here (before the return) 031001
// not the eighth (or lastY) line, so not scanning this time
if ((mody != SUBYRES1) && (y != lastY)) return;
//lastModY = mody; // eeK! this was missing
//return;
//if (y == lastY) {
//System.out.println("y is lasty");
//}
//lastModY = mody;
aaleftfull = aaleftmax/SUBXRES + 1;
aarightfull = aarightmin/SUBXRES - 1;
}
// this is the setup, based on lx
incrementalize_x(l, r, sp, sdp, lx);
//System.out.println(l[V] + " " + r[V] + " " +sp[V] + " " +sdp[V]);
// scan in x, generating pixels
// using parent.width to get actual pixel index
// rather than scaled by smooth factor
int offset = smooth ? parent.width * (y / SUBYRES) : parent.width*y;
int truelx = 0, truerx = 0;
if (smooth) {
truelx = lx / SUBXRES;
truerx = (rx + SUBXRES1) / SUBXRES;
lx = aaleftmin / SUBXRES;
rx = (aarightmax + SUBXRES1) / SUBXRES;
if (lx < 0) lx = 0;
if (rx > parent.width1) rx = parent.width1;
}
// System.out.println("P3D interp uv " + interpUV + " " +
// vertices[2][U] + " " + vertices[2][V]);
interpX = false;
int tr, tg, tb, ta;
//System.out.println("lx: "+lx + "\nrx: "+rx);
for (int x = lx; x <= rx; x++) {
// added == because things on same plane weren't replacing each other
// makes for strangeness in 3D [ewj: yup!], but totally necessary for 2D
//if (noDepthTest || (sp[Z] < zbuffer[offset+x])) {
if (noDepthTest || (sp[Z] <= zbuffer[offset+x])) {
//if (true) {
// map texture based on U, V coords in sp[U] and sp[V]
if (interpUV) {
int tu = (int)sp[U];
int tv = (int)sp[V];
if (tu > twidth1) tu = twidth1;
if (tv > theight1) tv = theight1;
if (tu < 0) tu = 0;
if (tv < 0) tv = 0;
int txy = tv*twidth + tu;
//System.out.println("tu: "+tu+" ; tv: "+tv+" ; txy: "+txy);
float[] uv = new float[2];
txy = getTextureIndex(x, y*1.0f/SUBYRES, uv);
// txy = getTextureIndex(x* 1.0f/SUBXRES, y*1.0f/SUBYRES, uv);
tu = (int)uv[0]; tv = (int)uv[1];
// if (tu > twidth1) tu = twidth1;
// if (tv > theight1) tv = theight1;
// if (tu < 0) tu = 0;
// if (tv < 0) tv = 0;
txy = twidth*tv + tu;
// if (EWJORDAN) System.out.println("x/y/txy:"+x + " " + y + " " +txy);
//PApplet.println(sp);
//smooth = true;
if (smooth || texture_smooth) {
//if (FRY) System.out.println("sp u v = " + sp[U] + " " + sp[V]);
//System.out.println("sp u v = " + sp[U] + " " + sp[V]);
// tuf1/tvf1 is the amount of coverage for the adjacent
// pixel, which is the decimal percentage.
// int tuf1 = (int) (255f * (sp[U] - (float)tu));
// int tvf1 = (int) (255f * (sp[V] - (float)tv));
int tuf1 = (int) (255f * (uv[0] - tu));
int tvf1 = (int) (255f * (uv[1] - tv));
// the closer sp[U or V] is to the decimal being zero
// the more coverage it should get of the original pixel
int tuf = 255 - tuf1;
int tvf = 255 - tvf1;
// this code sucks! filled with bugs and slow as hell!
int pixel00 = tpixels[txy];
int pixel01 = (tv < theight1) ? tpixels[txy + twidth] : tpixels[txy];
int pixel10 = (tu < twidth1) ? tpixels[txy + 1] : tpixels[txy];
int pixel11 = ((tv < theight1) && (tu < twidth1)) ? tpixels[txy + twidth + 1] : tpixels[txy];
//System.out.println("1: "+pixel00);
//check
int p00, p01, p10, p11;
int px0, px1; //, pxy;
if (tformat == ALPHA) {
px0 = (pixel00*tuf + pixel10*tuf1) >> 8;
px1 = (pixel01*tuf + pixel11*tuf1) >> 8;
ta = (((px0*tvf + px1*tvf1) >> 8) *
(interpARGB ? ((int) (sp[A]*255)) : a2orig)) >> 8;
} else if (tformat == ARGB) {
p00 = (pixel00 >> 24) & 0xff;
p01 = (pixel01 >> 24) & 0xff;
p10 = (pixel10 >> 24) & 0xff;
p11 = (pixel11 >> 24) & 0xff;
px0 = (p00*tuf + p10*tuf1) >> 8;
px1 = (p01*tuf + p11*tuf1) >> 8;
ta = (((px0*tvf + px1*tvf1) >> 8) *
(interpARGB ? ((int) (sp[A]*255)) : a2orig)) >> 8;
} else { // RGB image, no alpha
//ACCTEX: Getting here when smooth is on
ta = interpARGB ? ((int) (sp[A]*255)) : a2orig;
//System.out.println("4: "+ta + " " +interpARGB + " " + sp[A] + " " + a2orig);
//check
}
if ((tformat == RGB) || (tformat == ARGB)) {
p00 = (pixel00 >> 16) & 0xff; // red
p01 = (pixel01 >> 16) & 0xff;
p10 = (pixel10 >> 16) & 0xff;
p11 = (pixel11 >> 16) & 0xff;
px0 = (p00*tuf + p10*tuf1) >> 8;
px1 = (p01*tuf + p11*tuf1) >> 8;
tr = (((px0*tvf + px1*tvf1) >> 8) * (interpARGB ? ((int) (sp[R]*255)) : r2)) >> 8;
p00 = (pixel00 >> 8) & 0xff; // green
p01 = (pixel01 >> 8) & 0xff;
p10 = (pixel10 >> 8) & 0xff;
p11 = (pixel11 >> 8) & 0xff;
px0 = (p00*tuf + p10*tuf1) >> 8;
px1 = (p01*tuf + p11*tuf1) >> 8;
tg = (((px0*tvf + px1*tvf1) >> 8) * (interpARGB ? ((int) (sp[G]*255)) : g2)) >> 8;
p00 = pixel00 & 0xff; // blue
p01 = pixel01 & 0xff;
p10 = pixel10 & 0xff;
p11 = pixel11 & 0xff;
px0 = (p00*tuf + p10*tuf1) >> 8;
px1 = (p01*tuf + p11*tuf1) >> 8;
tb = (((px0*tvf + px1*tvf1) >> 8) * (interpARGB ? ((int) (sp[B]*255)) : b2)) >> 8;
//System.out.println("5: "+tr + " " + tg + " " +tb);
//check
} else { // alpha image, only use current fill color
if (interpARGB) {
tr = (int) (sp[R] * 255);
tg = (int) (sp[G] * 255);
tb = (int) (sp[B] * 255);
} else {
tr = r2;
tg = g2;
tb = b2;
}
}
// get coverage for pixel if smooth
// checks smooth again here because of
// hints[SMOOTH_IMAGES] used up above
int weight = smooth ? coverage(x) : 255;
if (weight != 255) ta = (ta*weight) >> 8;
//System.out.println(ta);
//System.out.println("8");
//check
} else { // no smooth, just get the pixels
int tpixel = tpixels[txy];
// TODO i doubt splitting these guys really gets us
// all that much speed.. is it worth it?
if (tformat == ALPHA) {
ta = tpixel;
if (interpARGB) {
tr = (int) (sp[R]*255);
tg = (int) (sp[G]*255);
tb = (int) (sp[B]*255);
if (sp[A] != 1) {
ta = (((int) (sp[A]*255)) * ta) >> 8;
}
} else {
tr = r2;
tg = g2;
tb = b2;
ta = (a2orig * ta) >> 8;
}
} else { // RGB or ARGB
ta = (tformat == RGB) ? 255 : (tpixel >> 24) & 0xff;
if (interpARGB) {
tr = (((int) (sp[R]*255)) * ((tpixel >> 16) & 0xff)) >> 8;
tg = (((int) (sp[G]*255)) * ((tpixel >> 8) & 0xff)) >> 8;
tb = (((int) (sp[B]*255)) * ((tpixel) & 0xff)) >> 8;
ta = (((int) (sp[A]*255)) * ta) >> 8;
} else {
tr = (r2 * ((tpixel >> 16) & 0xff)) >> 8;
tg = (g2 * ((tpixel >> 8) & 0xff)) >> 8;
tb = (b2 * ((tpixel) & 0xff)) >> 8;
ta = (a2orig * ta) >> 8;
}
}
}
if ((ta == 254) || (ta == 255)) { // if (ta & 0xf8) would be good
// no need to blend
pixels[offset+x] = 0xff000000 | (tr << 16) | (tg << 8) | tb;
if (updateZBuffer) zbuffer[offset+x] = sp[Z];
} else {
// blend with pixel on screen
int a1 = 255-ta;
int r1 = (pixels[offset+x] >> 16) & 0xff;
int g1 = (pixels[offset+x] >> 8) & 0xff;
int b1 = (pixels[offset+x]) & 0xff;
pixels[offset+x] =
0xff000000 |
(((tr*ta + r1*a1) >> 8) << 16) |
((tg*ta + g1*a1) & 0xff00) |
((tb*ta + b1*a1) >> 8);
//System.out.println("17");
//check
if (updateZBuffer && ta > ZBUFFER_MIN_COVERAGE) zbuffer[offset+x] = sp[Z];
}
//System.out.println("18");
//check
} else { // no image applied
int weight = smooth ? coverage(x) : 255;
if (interpARGB) {
r2 = (int) (sp[R] * 255);
g2 = (int) (sp[G] * 255);
b2 = (int) (sp[B] * 255);
if (sp[A] != 1) weight = (weight * ((int) (sp[A] * 255))) >> 8;
if (weight == 255) {
rgba = 0xff000000 | (r2 << 16) | (g2 << 8) | b2;
}
} else {
if (a2orig != 255) weight = (weight * a2orig) >> 8;
}
if (weight == 255) {
// no blend, no aa, just the rgba
pixels[offset+x] = rgba;
if (updateZBuffer) zbuffer[offset+x] = sp[Z];
} else {
int r1 = (pixels[offset+x] >> 16) & 0xff;
int g1 = (pixels[offset+x] >> 8) & 0xff;
int b1 = (pixels[offset+x]) & 0xff;
a2 = weight;
int a1 = 255 - a2;
pixels[offset+x] = (0xff000000 |
((r1*a1 + r2*a2) >> 8) << 16 |
// use & instead of >> and << below
((g1*a1 + g2*a2) >> 8) << 8 |
((b1*a1 + b2*a2) >> 8));
if (updateZBuffer && a2 > ZBUFFER_MIN_COVERAGE) zbuffer[offset+x] = sp[Z];
}
}
}
// if smooth enabled, don't increment values
// for the pixel in the stretch out version
// of the scanline used to get smooth edges.
if (!smooth || ((x >= truelx) && (x <= truerx))) {
//if (!smooth)
increment(sp, sdp);
}
}
firstModY = -1;
interpX = true;
}
// x is in screen, not huge 8x coordinates
private int coverage(int x) {
if ((x >= aaleftfull) && (x <= aarightfull) &&
// important since not all SUBYRES lines may have been covered
(firstModY == 0) && (lastModY == SUBYRES1)) {
return 255;
}
int pixelLeft = x*SUBXRES; // huh?
int pixelRight = pixelLeft + 8;
int amt = 0;
for (int i = firstModY; i <= lastModY; i++) {
if ((aaleft[i] > pixelRight) || (aaright[i] < pixelLeft)) {
continue;
}
// does this need a +1 ?
amt += ((aaright[i] < pixelRight ? aaright[i] : pixelRight) -
(aaleft[i] > pixelLeft ? aaleft[i] : pixelLeft));
}
amt <<= 2;
return (amt == 256) ? 255 : amt;
}
private void incrementalize_y(float p1[], float p2[],
float p[], float dp[], int y) {
float delta = p2[Y] - p1[Y];
if (delta == 0) delta = 1;
float fraction = y + 0.5f - p1[Y];
if (interpX) {
dp[X] = (p2[X] - p1[X]) / delta;
p[X] = p1[X] + dp[X] * fraction;
}
if (interpZ) {
dp[Z] = (p2[Z] - p1[Z]) / delta;
p[Z] = p1[Z] + dp[Z] * fraction;
}
if (interpARGB) {
dp[R] = (p2[R] - p1[R]) / delta;
dp[G] = (p2[G] - p1[G]) / delta;
dp[B] = (p2[B] - p1[B]) / delta;
dp[A] = (p2[A] - p1[A]) / delta;
p[R] = p1[R] + dp[R] * fraction;
p[G] = p1[G] + dp[G] * fraction;
p[B] = p1[B] + dp[B] * fraction;
p[A] = p1[A] + dp[A] * fraction;
}
if (interpUV) {
dp[U] = (p2[U] - p1[U]) / delta;
dp[V] = (p2[V] - p1[V]) / delta;
//if (smooth) {
//p[U] = p1[U]; //+ dp[U] * fraction;
//p[V] = p1[V]; //+ dp[V] * fraction;
//} else {
p[U] = p1[U] + dp[U] * fraction;
p[V] = p1[V] + dp[V] * fraction;
//}
if (FRY) System.out.println("inc y p[U] p[V] = " + p[U] + " " + p[V]);
}
}
//incrementalize_x(l, r, sp, sdp, lx);
private void incrementalize_x(float p1[], float p2[],
float p[], float dp[], int x) {
float delta = p2[X] - p1[X];
if (delta == 0) delta = 1;
float fraction = x + 0.5f - p1[X];
if (smooth) {
delta /= SUBXRES;
fraction /= SUBXRES;
}
if (interpX) {
dp[X] = (p2[X] - p1[X]) / delta;
p[X] = p1[X] + dp[X] * fraction;
}
if (interpZ) {
dp[Z] = (p2[Z] - p1[Z]) / delta;
p[Z] = p1[Z] + dp[Z] * fraction;
//System.out.println(p2[Z]+" " +p1[Z]+" " +dp[Z]);
}
if (interpARGB) {
dp[R] = (p2[R] - p1[R]) / delta;
dp[G] = (p2[G] - p1[G]) / delta;
dp[B] = (p2[B] - p1[B]) / delta;
dp[A] = (p2[A] - p1[A]) / delta;
p[R] = p1[R] + dp[R] * fraction;
p[G] = p1[G] + dp[G] * fraction;
p[B] = p1[B] + dp[B] * fraction;
p[A] = p1[A] + dp[A] * fraction;
}
if (interpUV) {
if (FRY) System.out.println("delta, frac = " + delta + ", " + fraction);
dp[U] = (p2[U] - p1[U]) / delta;
dp[V] = (p2[V] - p1[V]) / delta;
//if (smooth) {
//p[U] = p1[U];
// offset for the damage that will be done by the
// 8 consecutive calls to scanline
// agh.. this won't work b/c not always 8 calls before render
// maybe lastModY - firstModY + 1 instead?
if (FRY) System.out.println("before inc x p[V] = " + p[V] + " " + p1[V] + " " + p2[V]);
//p[V] = p1[V] - SUBXRES1 * fraction;
//} else {
p[U] = p1[U] + dp[U] * fraction;
p[V] = p1[V] + dp[V] * fraction;
//}
}
}
private void increment(float p[], float dp[]) {
if (interpX) p[X] += dp[X];
if (interpZ) p[Z] += dp[Z];
if (interpARGB) {
p[R] += dp[R];
p[G] += dp[G];
p[B] += dp[B];
p[A] += dp[A];
}
if (interpUV) {
if (FRY) System.out.println("increment() " + p[V] + " " + dp[V]);
p[U] += dp[U];
p[V] += dp[V];
}
}
/**
* Pass camera-space coordinates for the triangle.
* Needed to render if hint(ENABLE_ACCURATE_TEXTURES) enabled.
* Generally this will not need to be called manually,
* currently called from PGraphics3D.render_triangles()
*/
public void setCamVertices(float x0, float y0, float z0,
float x1, float y1, float z1,
float x2, float y2, float z2) {
camX[0] = x0;
camX[1] = x1;
camX[2] = x2;
camY[0] = y0;
camY[1] = y1;
camY[2] = y2;
camZ[0] = z0;
camZ[1] = z1;
camZ[2] = z2;
}
public void setVertices(float x0, float y0, float z0,
float x1, float y1, float z1,
float x2, float y2, float z2) {
vertices[0][X] = x0;
vertices[1][X] = x1;
vertices[2][X] = x2;
vertices[0][Y] = y0;
vertices[1][Y] = y1;
vertices[2][Y] = y2;
vertices[0][Z] = z0;
vertices[1][Z] = z1;
vertices[2][Z] = z2;
}
/**
* Precompute a bunch of variables needed to perform
* texture mapping.
* @return True unless texture mapping is degenerate
*/
boolean precomputeAccurateTexturing() {
int o0 = 0;
int o1 = 1;
int o2 = 2;
PMatrix3D myMatrix = new PMatrix3D(vertices[o0][U], vertices[o0][V], 1, 0,
vertices[o1][U], vertices[o1][V], 1, 0,
vertices[o2][U], vertices[o2][V], 1, 0,
0, 0, 0, 1);
// A 3x3 inversion would be more efficient here,
// given that the fourth r/c are unity
boolean invertSuccess = myMatrix.invert();// = myMatrix.invert();
// If the matrix inversion had trouble, let the caller know.
// Note that this does not catch everything that could go wrong
// here, like if the renderer is in ortho() mode (which really
// must be caught in PGraphics3D instead of here).
if (!invertSuccess) return false;
float m00, m01, m02, m10, m11, m12, m20, m21, m22;
m00 = myMatrix.m00*camX[o0]+myMatrix.m01*camX[o1]+myMatrix.m02*camX[o2];
m01 = myMatrix.m10*camX[o0]+myMatrix.m11*camX[o1]+myMatrix.m12*camX[o2];
m02 = myMatrix.m20*camX[o0]+myMatrix.m21*camX[o1]+myMatrix.m22*camX[o2];
m10 = myMatrix.m00*camY[o0]+myMatrix.m01*camY[o1]+myMatrix.m02*camY[o2];
m11 = myMatrix.m10*camY[o0]+myMatrix.m11*camY[o1]+myMatrix.m12*camY[o2];
m12 = myMatrix.m20*camY[o0]+myMatrix.m21*camY[o1]+myMatrix.m22*camY[o2];
m20 = -(myMatrix.m00*camZ[o0]+myMatrix.m01*camZ[o1]+myMatrix.m02*camZ[o2]);
m21 = -(myMatrix.m10*camZ[o0]+myMatrix.m11*camZ[o1]+myMatrix.m12*camZ[o2]);
m22 = -(myMatrix.m20*camZ[o0]+myMatrix.m21*camZ[o1]+myMatrix.m22*camZ[o2]);
float px = m02;
float py = m12;
float pz = m22;
float TEX_WIDTH = this.twidth;
float TEX_HEIGHT = this.theight;
float resultT0x = m00*TEX_WIDTH+m02;
float resultT0y = m10*TEX_WIDTH+m12;
float resultT0z = m20*TEX_WIDTH+m22;
float result0Tx = m01*TEX_HEIGHT+m02;
float result0Ty = m11*TEX_HEIGHT+m12;
float result0Tz = m21*TEX_HEIGHT+m22;
float mx = resultT0x-m02;
float my = resultT0y-m12;
float mz = resultT0z-m22;
float nx = result0Tx-m02;
float ny = result0Ty-m12;
float nz = result0Tz-m22;
//avec = p x n
ax = (py*nz-pz*ny)*TEX_WIDTH; //F_TEX_WIDTH/HEIGHT?
ay = (pz*nx-px*nz)*TEX_WIDTH;
az = (px*ny-py*nx)*TEX_WIDTH;
//bvec = m x p
bx = (my*pz-mz*py)*TEX_HEIGHT;
by = (mz*px-mx*pz)*TEX_HEIGHT;
bz = (mx*py-my*px)*TEX_HEIGHT;
//cvec = n x m
cx = ny*mz-nz*my;
cy = nz*mx-nx*mz;
cz = nx*my-ny*mx;
//System.out.println("a/b/c: "+ax+" " + ay + " " + az + " " + bx + " " + by + " " + bz + " " + cx + " " + cy + " " + cz);
nearPlaneWidth = (parent.rightScreen-parent.leftScreen);
nearPlaneHeight = (parent.topScreen-parent.bottomScreen);
nearPlaneDepth = parent.nearPlane;
// one pixel width in nearPlane coordinates
xmult = nearPlaneWidth / parent.width;
ymult = nearPlaneHeight / parent.height;
// Extra scalings to map screen plane units to pixel units
// newax = ax*xmult;
// newbx = bx*xmult;
// newcx = cx*xmult;
// System.out.println("nearplane: "+ nearPlaneWidth + " " + nearPlaneHeight + " " + nearPlaneDepth);
// System.out.println("mults: "+ xmult + " " + ymult);
// System.out.println("news: "+ newax + " " + newbx + " " + newcx);
return true;
}
/**
* Get the texture map location based on the current screen
* coordinates. Assumes precomputeAccurateTexturing() has
* been called already for this texture mapping.
* @param sx
* @param sy
* @return
*/
private int getTextureIndex(float sx, float sy, float[] uv) {
if (EWJORDAN) System.out.println("Getting texel at "+sx + ", "+sy);
//System.out.println("Screen: "+ sx + " " + sy);
sx = xmult*(sx-(parent.width/2.0f) +.5f);//+.5f)
sy = ymult*(sy-(parent.height/2.0f)+.5f);//+.5f)
//sx /= SUBXRES;
//sy /= SUBYRES;
float sz = nearPlaneDepth;
float a = sx * ax + sy * ay + sz * az;
float b = sx * bx + sy * by + sz * bz;
float c = sx * cx + sy * cy + sz * cz;
int u = (int)(a / c);
int v = (int)(b / c);
uv[0] = a / c;
uv[1] = b / c;
if (uv[0] < 0) {
uv[0] = u = 0;
}
if (uv[1] < 0) {
uv[1] = v = 0;
}
if (uv[0] >= twidth) {
uv[0] = twidth-1;
u = twidth-1;
}
if (uv[1] >= theight) {
uv[1] = theight-1;
v = theight-1;
}
int result = v*twidth + u;
//System.out.println("a/b/c: "+a + " " + b + " " + c);
//System.out.println("cx/y/z: "+cx + " " + cy + " " + cz);
//if (result < 0) result = 0;
//if (result >= timage.pixels.length-2) result = timage.pixels.length - 2;
if (EWJORDAN) System.out.println("Got texel "+result);
return result;
}
public void setIntensities(float ar, float ag, float ab, float aa,
float br, float bg, float bb, float ba,
float cr, float cg, float cb, float ca) {
vertices[0][R] = ar;
vertices[0][G] = ag;
vertices[0][B] = ab;
vertices[0][A] = aa;
vertices[1][R] = br;
vertices[1][G] = bg;
vertices[1][B] = bb;
vertices[1][A] = ba;
vertices[2][R] = cr;
vertices[2][G] = cg;
vertices[2][B] = cb;
vertices[2][A] = ca;
}
}
File diff suppressed because it is too large Load Diff