cleaning up curve/bezier drawing, vertex() functions, and separation of

PGraphics, P2D, and P3D.
This commit is contained in:
benfry
2008-09-30 22:47:24 +00:00
parent 9cf73a9be2
commit 456d6db4a0
8 changed files with 794 additions and 742 deletions
+30 -16
View File
@@ -27,25 +27,26 @@ style(PStyle s)
//
setParent()
setPrimary()
setPath()
setSize(int w, int h)
allocate()
public void setParent(PApplet parent)
public void setPrimary(boolean primary)
public void setPath(String path)
public void setSize(int iwidth, int iheight)
protected void allocate()
canDraw()
beginDraw()
endDraw()
flush()
public boolean canDraw()
public void beginDraw()
public void endDraw()
public void flush()
checkSettings()
defaultSettings()
reapplySettings()
protected void checkSettings()
protected void defaultSettings()
protected void reapplySettings()
hint()
public void hint(int which)
public void beginShape()
public void beginShape(int kind)
public void edge(boolean e)
public void normal(float nx, float ny, float nz)
public void textureMode(int mode)
public void texture(PImage image)
@@ -53,17 +54,30 @@ style(PStyle s)
public void vertex(float x, float y, float z)
public void vertex(float x, float y, float u, float v)
public void vertex(float x, float y, float z, float u, float v)
protected void vertexTexture(float u, float v);
public void breakShape()
public void endShape()
public void endShape(int mode)
protected void bezierVertexCheck();
public void bezierVertex(float x2, float y2,
float x3, float y3,
float x4, float y4)
public void bezierVertex(float x2, float y2, float z2,
float x3, float y3, float z3,
float x4, float y4, float z4)
protected void curveVertexCheck();
public void curveVertex(float x, float y)
public void curveVertex(float x, float y, float z)
public void breakShape()
public void endShape()
public void endShape(int mode)
protected void curveVertexSegment(float x1, float y1,
float x2, float y2,
float x3, float y3,
float x4, float y4)
protected void curveVertexSegment(float x1, float y1, float z1,
float x2, float y2, float z2,
float x3, float y3, float z3,
float x4, float y4, float z4)
public void point(float x, float y)
public void point(float x, float y, float z)
+30 -18
View File
@@ -6661,6 +6661,12 @@ public class PApplet extends Applet
// public functions for processing.core
public void flush() {
if (recorder != null) recorder.flush();
g.flush();
}
public void hint(int which) {
if (recorder != null) recorder.hint(which);
g.hint(which);
@@ -6679,6 +6685,12 @@ public class PApplet extends Applet
}
public void edge(boolean e) {
if (recorder != null) recorder.edge(e);
g.edge(e);
}
public void normal(float nx, float ny, float nz) {
if (recorder != null) recorder.normal(nx, ny, nz);
g.normal(nx, ny, nz);
@@ -6721,6 +6733,24 @@ public class PApplet extends Applet
}
public void breakShape() {
if (recorder != null) recorder.breakShape();
g.breakShape();
}
public void endShape() {
if (recorder != null) recorder.endShape();
g.endShape();
}
public void endShape(int mode) {
if (recorder != null) recorder.endShape(mode);
g.endShape(mode);
}
public void bezierVertex(float x2, float y2,
float x3, float y3,
float x4, float y4) {
@@ -6749,24 +6779,6 @@ public class PApplet extends Applet
}
public void breakShape() {
if (recorder != null) recorder.breakShape();
g.breakShape();
}
public void endShape() {
if (recorder != null) recorder.endShape();
g.endShape();
}
public void endShape(int mode) {
if (recorder != null) recorder.endShape(mode);
g.endShape(mode);
}
public void style(PStyle s) {
if (recorder != null) recorder.style(s);
g.style(s);
+370 -319
View File
@@ -374,7 +374,6 @@ public class PGraphics extends PImage implements PConstants {
static final int MATRIX_STACK_DEPTH = 32;
// ........................................................
/**
@@ -442,9 +441,8 @@ public class PGraphics extends PImage implements PConstants {
// spline vertices
static final int DEFAULT_SPLINE_VERTICES = 128;
protected float splineVertices[][];
protected int splineVertexCount;
protected float curveVertices[][];
protected int curveVertexCount;
// ........................................................
@@ -492,92 +490,32 @@ public class PGraphics extends PImage implements PConstants {
protected int[] textBreakStop;
//////////////////////////////////////////////////////////////
// VARIABLES FOR 3D (used to prevent the need for a subclass)
/** The modelview matrix. */
public PMatrix3D modelview;
/** Inverse modelview matrix, used for lighting. */
protected PMatrix3D modelviewInv;
/**
* The camera matrix, the modelview will be set to this on beginDraw.
*/
public PMatrix3D camera;
/** Inverse camera matrix */
protected PMatrix3D cameraInv;
static final String ERROR_PUSHMATRIX_OVERFLOW =
"Too many calls to pushMatrix().";
static final String ERROR_PUSHMATRIX_UNDERFLOW =
"Too many calls to popMatrix(), and not enough to pushMatrix().";
// ........................................................
/** Camera field of view. */
public float cameraFOV;
/** Position of the camera. */
public float cameraX, cameraY, cameraZ;
public float cameraNear, cameraFar;
/** Aspect ratio of camera's view. */
public float cameraAspect;
/** Current projection matrix. */
public PMatrix3D projection;
public boolean edge;
// ........................................................
/** The depth buffer. */
public float[] zbuffer;
/// normal calculated per triangle
static protected final int NORMAL_MODE_AUTO = 0;
/// one normal manually specified per shape
static protected final int NORMAL_MODE_SHAPE = 1;
/// normals specified for each shape vertex
static protected final int NORMAL_MODE_VERTEX = 2;
// ........................................................
/// Current mode for normals, one of AUTO, SHAPE, or VERTEX
protected int normalMode;
/**
* Maximum lights by default is 8, which is arbitrary for this renderer,
* but is the minimum defined by OpenGL
*/
public static final int MAX_LIGHTS = 8;
/// Keep track of how many calls to normal, to determine the mode.
protected int normalCount;
public int lightCount = 0;
/** Light types */
public int[] lightType;
/** Light positions */
public float[][] lightPosition;
/** Light direction (normalized vector) */
public float[][] lightNormal;
/** Light falloff */
public float[] lightFalloffConstant;
public float[] lightFalloffLinear;
public float[] lightFalloffQuadratic;
/** Light spot angle */
public float[] lightSpotAngle;
/** Cosine of light spot angle */
public float[] lightSpotAngleCos;
/** Light spot concentration */
public float[] lightSpotConcentration;
/** Diffuse colors for lights.
* For an ambient light, this will hold the ambient color.
* Internally these are stored as numbers between 0 and 1. */
public float[][] lightDiffuse;
/** Specular colors for lights.
Internally these are stored as numbers between 0 and 1. */
public float[][] lightSpecular;
/** Current specular color for lighting */
public float[] currentLightSpecular;
/** Current light falloff */
public float currentLightFalloffConstant;
public float currentLightFalloffLinear;
public float currentLightFalloffQuadratic;
/** Current normal vector. */
public float normalX, normalY, normalZ;
// ........................................................
@@ -600,25 +538,6 @@ public class PGraphics extends PImage implements PConstants {
/** Current image being used as a texture */
public PImage textureImage;
// ........................................................
/// normal calculated per triangle
static protected final int NORMAL_MODE_AUTO = 0;
/// one normal manually specified per shape
static protected final int NORMAL_MODE_SHAPE = 1;
/// normals specified for each shape vertex
static protected final int NORMAL_MODE_VERTEX = 2;
/// Current mode for normals, one of AUTO, SHAPE, or VERTEX
protected int normalMode;
/// Keep track of how many calls to normal, to determine the mode.
protected int normalCount;
/** Current normal vector. */
public float normalX, normalY, normalZ;
// ........................................................
// [toxi031031] new & faster sphere code w/ support flexibile resolutions
@@ -684,9 +603,9 @@ public class PGraphics extends PImage implements PConstants {
* event thread (EDT), causing a nasty crash as it collides with the
* animation thread.
*/
public void setSize(int iwidth, int iheight) { // ignore
width = iwidth;
height = iheight;
public void setSize(int w, int h) { // ignore
width = w;
height = h;
width1 = width - 1;
height1 = height - 1;
@@ -705,22 +624,6 @@ public class PGraphics extends PImage implements PConstants {
// FRAME
/**
* Returns true if this is a 2D renderer.
*/
public boolean is2D() {
return false;
}
/**
* Returns true if this is a 3D renderer (rather than using instanceof).
*/
public boolean is3D() {
return false;
}
/**
* Some renderers have requirements re: when they are ready to draw.
*/
@@ -749,7 +652,7 @@ public class PGraphics extends PImage implements PConstants {
}
protected void flush() {
public void flush() {
// no-op, mostly for P3D to write sorted stuff
}
@@ -944,10 +847,53 @@ public class PGraphics extends PImage implements PConstants {
* that's how things are implemented.
*/
public void beginShape(int kind) {
shape = kind;
}
public void edge(boolean e) {
this.edge = edge;
}
/**
* Sets the current normal vector. Only applies with 3D rendering
* and inside a beginShape/endShape block.
* <P/>
* This is for drawing three dimensional shapes and surfaces,
* allowing you to specify a vector perpendicular to the surface
* of the shape, which determines how lighting affects it.
* <P/>
* For the most part, PGraphics3D will attempt to automatically
* assign normals to shapes, but since that's imperfect,
* this is a better option when you want more control.
* <P/>
* For people familiar with OpenGL, this function is basically
* identical to glNormal3f().
*/
public void normal(float nx, float ny, float nz) {
normalX = nx;
normalY = ny;
normalZ = nz;
// if drawing a shape and the normal hasn't been set yet,
// then we need to set the normals for each vertex so far
if (shape != 0) {
if (normalMode == NORMAL_MODE_AUTO) {
// either they set the normals, or they don't [0149]
// for (int i = vertex_start; i < vertexCount; i++) {
// vertices[i][NX] = normalX;
// vertices[i][NY] = normalY;
// vertices[i][NZ] = normalZ;
// }
// One normal per begin/end shape
normalMode = NORMAL_MODE_SHAPE;
} else if (normalMode == NORMAL_MODE_SHAPE) {
// a separate normal for each vertex
normalMode = NORMAL_MODE_VERTEX;
}
}
}
@@ -970,150 +916,26 @@ public class PGraphics extends PImage implements PConstants {
textureImage = image;
}
/**
* Set (U, V) coords for the next vertex in the current shape.
* This is ugly as its own function, and will (almost?) always be
* coincident with a call to vertex. As of beta, this was moved to
* the protected method you see here, and called from an optional
* param of and overloaded vertex().
* <p/>
* The parameters depend on the current textureMode. When using
* textureMode(IMAGE), the coordinates will be relative to the size
* of the image texture, when used with textureMode(NORMAL),
* they'll be in the range 0..1.
* <p/>
* Used by both PGraphics2D (for images) and PGraphics3D.
*/
protected void textureVertex(float u, float v) {
if (textureImage == null) {
throw new RuntimeException("need to set an image with texture() " +
"before using u and v coordinates");
protected void vertexCheck() {
if (vertexCount == vertices.length) {
float temp[][] = new float[vertexCount << 1][VERTEX_FIELD_COUNT];
System.arraycopy(vertices, 0, temp, 0, vertexCount);
vertices = temp;
}
if (textureMode == IMAGE) {
u /= (float) textureImage.width;
v /= (float) textureImage.height;
}
textureU = u;
textureV = v;
if (textureU < 0) textureU = 0;
else if (textureU > 1) textureU = 1;
if (textureV < 0) textureV = 0;
else if (textureV > 1) textureV = 1;
}
// eventually need to push a "default" setup down to this class
public void vertex(float x, float y) {
}
float[] vertex = vertices[vertexCount];
public void vertex(float x, float y, float z) {
}
public void vertex(float x, float y, float u, float v) {
}
public void vertex(float x, float y, float z, float u, float v) {
}
public void bezierVertex(float x2, float y2,
float x3, float y3,
float x4, float y4) {
if (shape != POLYGON || vertexCount == 0) {
throw new RuntimeException("beginShape() and vertex() " +
"must be used before bezierVertex()");
}
PMatrix3D dm = bezierDrawMatrix;
float[] prev = vertices[vertexCount-1];
float x1 = prev[X];
float y1 = prev[Y];
float xplot1 = dm.m10*x1 + dm.m11*x2 + dm.m12*x3 + dm.m13*x4;
float xplot2 = dm.m20*x1 + dm.m21*x2 + dm.m22*x3 + dm.m23*x4;
float xplot3 = dm.m30*x1 + dm.m31*x2 + dm.m32*x3 + dm.m33*x4;
float yplot1 = dm.m10*y1 + dm.m11*y2 + dm.m12*y3 + dm.m13*y4;
float yplot2 = dm.m20*y1 + dm.m21*y2 + dm.m22*y3 + dm.m23*y4;
float yplot3 = dm.m30*y1 + dm.m31*y2 + dm.m32*y3 + dm.m33*y4;
for (int j = 0; j < bezierDetail; j++) {
x1 += xplot1; xplot1 += xplot2; xplot2 += xplot3;
y1 += yplot1; yplot1 += yplot2; yplot2 += yplot3;
vertex(x1, y1);
}
}
public void bezierVertex(float x2, float y2, float z2,
float x3, float y3, float z3,
float x4, float y4, float z4) {
if (shape != POLYGON || vertexCount == 0) {
throw new RuntimeException("beginShape() and vertex() " +
"must be used before bezierVertex()");
}
PMatrix3D dm = bezierDrawMatrix;
float[] prev = vertices[vertexCount-1];
float x1 = prev[X];
float y1 = prev[Y];
float z1 = prev[Z];
float xplot1 = dm.m10*x1 + dm.m11*x2 + dm.m12*x3 + dm.m13*x4;
float xplot2 = dm.m20*x1 + dm.m21*x2 + dm.m22*x3 + dm.m23*x4;
float xplot3 = dm.m30*x1 + dm.m31*x2 + dm.m32*x3 + dm.m33*x4;
float yplot1 = dm.m10*y1 + dm.m11*y2 + dm.m12*y3 + dm.m13*y4;
float yplot2 = dm.m20*y1 + dm.m21*y2 + dm.m22*y3 + dm.m23*y4;
float yplot3 = dm.m30*y1 + dm.m31*y2 + dm.m32*y3 + dm.m33*y4;
float zplot1 = dm.m10*z1 + dm.m11*z2 + dm.m12*z3 + dm.m13*z4;
float zplot2 = dm.m20*z1 + dm.m21*z2 + dm.m22*z3 + dm.m23*z4;
float zplot3 = dm.m30*z1 + dm.m31*z2 + dm.m32*z3 + dm.m33*z4;
for (int j = 0; j < bezierDetail; j++) {
x1 += xplot1; xplot1 += xplot2; xplot2 += xplot3;
y1 += yplot1; yplot1 += yplot2; yplot2 += yplot3;
z1 += zplot1; zplot1 += zplot2; zplot2 += zplot3;
vertex(x1, y1, z1);
}
}
protected void curveVertexCheck() {
if (shape != POLYGON) {
throw new RuntimeException("You must use beginShape() or " +
"beginShape(POLYGON) before curveVertex()");
}
// to improve processing applet load times, don't allocate
// space for the vertex data until actual use
if (splineVertices == null) {
splineVertices = new float[DEFAULT_SPLINE_VERTICES][VERTEX_FIELD_COUNT];
}
if (splineVertexCount == splineVertices.length) {
splineVertices = (float[][]) PApplet.expand(splineVertices);
}
curveInitCheck();
}
public void curveVertex(float x, float y) {
curveVertexCheck();
float[] vertex = splineVertices[splineVertexCount];
curveVertexCount = 0;
vertex[X] = x;
vertex[Y] = y;
vertex[EDGE] = edge ? 1 : 0;
if (fill) {
vertex[R] = fillR;
vertex[G] = fillG;
@@ -1133,36 +955,76 @@ public class PGraphics extends PImage implements PConstants {
vertex[U] = textureU;
vertex[V] = textureV;
}
splineVertexCount++;
// draw a segment if there are enough points
if (splineVertexCount > 3) {
curveVertexSegment(splineVertices[splineVertexCount-4][X],
splineVertices[splineVertexCount-4][Y],
splineVertices[splineVertexCount-3][X],
splineVertices[splineVertexCount-3][Y],
splineVertices[splineVertexCount-2][X],
splineVertices[splineVertexCount-2][Y],
splineVertices[splineVertexCount-1][X],
splineVertices[splineVertexCount-1][Y]);
}
vertexCount++;
}
public void curveVertex(float x, float y, float z) {
curveVertexCheck();
float[] vertex = splineVertices[splineVertexCount];
public void vertex(float x, float y, float z) {
float[] vertex = vertices[vertexCount];
// only do this if we're using an irregular (POLYGON) shape that
// will go through the triangulator. otherwise it'll do thinks like
// disappear in mathematically odd ways
// http://dev.processing.org/bugs/show_bug.cgi?id=444
if (shape == POLYGON) {
if (vertexCount > 0) {
float pvertex[] = vertices[vertexCount-1];
if ((Math.abs(pvertex[X] - x) < EPSILON) &&
(Math.abs(pvertex[Y] - y) < EPSILON) &&
(Math.abs(pvertex[Z] - z) < EPSILON)) {
// this vertex is identical, don't add it,
// because it will anger the triangulator
return;
}
}
}
// User called vertex(), so that invalidates anything queued up for curve
// vertices. If this is internally called by curveVertexSegment,
// then curveVertexCount will be saved and restored.
curveVertexCount = 0;
vertex[X] = x;
vertex[Y] = y;
vertex[Z] = z;
vertex[EDGE] = edge ? 1 : 0;
if (fill) {
vertex[R] = fillR;
vertex[G] = fillG;
vertex[B] = fillB;
vertex[A] = fillA;
if (textureImage != null) {
if (tint) {
vertex[R] = tintR;
vertex[G] = tintG;
vertex[B] = tintB;
vertex[A] = tintA;
} else {
vertex[R] = 1;
vertex[G] = 1;
vertex[B] = 1;
vertex[A] = 1;
}
} else {
vertex[R] = fillR;
vertex[G] = fillG;
vertex[B] = fillB;
vertex[A] = fillA;
}
vertex[AR] = ambientR;
vertex[AG] = ambientG;
vertex[AB] = ambientB;
vertex[SPR] = specularR;
vertex[SPG] = specularG;
vertex[SPB] = specularB;
//vertex[SPA] = specularA;
vertex[SHINE] = shininess;
vertex[ER] = emissiveR;
vertex[EG] = emissiveG;
vertex[EB] = emissiveB;
}
if (stroke) {
@@ -1182,26 +1044,230 @@ public class PGraphics extends PImage implements PConstants {
vertex[NY] = normalY;
vertex[NZ] = normalZ;
splineVertexCount++;
vertex[BEEN_LIT] = 0;
vertexCount++;
}
// draw a segment if there are enough points
if (splineVertexCount > 3) {
curveVertexSegment(splineVertices[splineVertexCount-4][X],
splineVertices[splineVertexCount-4][Y],
splineVertices[splineVertexCount-4][Z],
splineVertices[splineVertexCount-3][X],
splineVertices[splineVertexCount-3][Y],
splineVertices[splineVertexCount-3][Z],
splineVertices[splineVertexCount-2][X],
splineVertices[splineVertexCount-2][Y],
splineVertices[splineVertexCount-2][Z],
splineVertices[splineVertexCount-1][X],
splineVertices[splineVertexCount-1][Y],
splineVertices[splineVertexCount-1][Z]);
public void vertex(float x, float y, float u, float v) {
vertexTexture(u, v);
vertex(x, y);
}
public void vertex(float x, float y, float z, float u, float v) {
vertexTexture(u, v);
vertex(x, y, z);
}
/**
* Internal method to copy all style information for the given vertex.
* Can be overridden by subclasses to handle only properties pertinent to
* that renderer. (e.g. no need to copy the emissive color in P2D)
*/
// protected void vertexStyle() {
// }
/**
* Set (U, V) coords for the next vertex in the current shape.
* This is ugly as its own function, and will (almost?) always be
* coincident with a call to vertex. As of beta, this was moved to
* the protected method you see here, and called from an optional
* param of and overloaded vertex().
* <p/>
* The parameters depend on the current textureMode. When using
* textureMode(IMAGE), the coordinates will be relative to the size
* of the image texture, when used with textureMode(NORMAL),
* they'll be in the range 0..1.
* <p/>
* Used by both PGraphics2D (for images) and PGraphics3D.
*/
protected void vertexTexture(float u, float v) {
if (textureImage == null) {
throw new RuntimeException("need to set an image with texture() " +
"before using u and v coordinates");
}
if (textureMode == IMAGE) {
u /= (float) textureImage.width;
v /= (float) textureImage.height;
}
textureU = u;
textureV = v;
if (textureU < 0) textureU = 0;
else if (textureU > 1) textureU = 1;
if (textureV < 0) textureV = 0;
else if (textureV > 1) textureV = 1;
}
/** This feature is in testing, do not use or rely upon its implementation */
public void breakShape() {
}
public void endShape() {
endShape(OPEN);
}
public void endShape(int mode) {
}
//////////////////////////////////////////////////////////////
// CURVE/BEZIER VERTEX HANDLING
protected void bezierVertexCheck() {
if (shape == 0 || shape != POLYGON) {
throw new RuntimeException("beginShape() or beginShape(POLYGON) " +
"must be used before bezierVertex()");
}
if (vertexCount == 0) {
throw new RuntimeException("vertex() must be used at least once" +
"before bezierVertex()");
}
}
public void bezierVertex(float x2, float y2,
float x3, float y3,
float x4, float y4) {
bezierVertexCheck();
PMatrix3D draw = bezierDrawMatrix;
float[] prev = vertices[vertexCount-1];
float x1 = prev[X];
float y1 = prev[Y];
float xplot1 = draw.m10*x1 + draw.m11*x2 + draw.m12*x3 + draw.m13*x4;
float xplot2 = draw.m20*x1 + draw.m21*x2 + draw.m22*x3 + draw.m23*x4;
float xplot3 = draw.m30*x1 + draw.m31*x2 + draw.m32*x3 + draw.m33*x4;
float yplot1 = draw.m10*y1 + draw.m11*y2 + draw.m12*y3 + draw.m13*y4;
float yplot2 = draw.m20*y1 + draw.m21*y2 + draw.m22*y3 + draw.m23*y4;
float yplot3 = draw.m30*y1 + draw.m31*y2 + draw.m32*y3 + draw.m33*y4;
for (int j = 0; j < bezierDetail; j++) {
x1 += xplot1; xplot1 += xplot2; xplot2 += xplot3;
y1 += yplot1; yplot1 += yplot2; yplot2 += yplot3;
vertex(x1, y1);
}
}
public void bezierVertex(float x2, float y2, float z2,
float x3, float y3, float z3,
float x4, float y4, float z4) {
bezierVertexCheck();
PMatrix3D draw = bezierDrawMatrix;
float[] prev = vertices[vertexCount-1];
float x1 = prev[X];
float y1 = prev[Y];
float z1 = prev[Z];
float xplot1 = draw.m10*x1 + draw.m11*x2 + draw.m12*x3 + draw.m13*x4;
float xplot2 = draw.m20*x1 + draw.m21*x2 + draw.m22*x3 + draw.m23*x4;
float xplot3 = draw.m30*x1 + draw.m31*x2 + draw.m32*x3 + draw.m33*x4;
float yplot1 = draw.m10*y1 + draw.m11*y2 + draw.m12*y3 + draw.m13*y4;
float yplot2 = draw.m20*y1 + draw.m21*y2 + draw.m22*y3 + draw.m23*y4;
float yplot3 = draw.m30*y1 + draw.m31*y2 + draw.m32*y3 + draw.m33*y4;
float zplot1 = draw.m10*z1 + draw.m11*z2 + draw.m12*z3 + draw.m13*z4;
float zplot2 = draw.m20*z1 + draw.m21*z2 + draw.m22*z3 + draw.m23*z4;
float zplot3 = draw.m30*z1 + draw.m31*z2 + draw.m32*z3 + draw.m33*z4;
for (int j = 0; j < bezierDetail; j++) {
x1 += xplot1; xplot1 += xplot2; xplot2 += xplot3;
y1 += yplot1; yplot1 += yplot2; yplot2 += yplot3;
z1 += zplot1; zplot1 += zplot2; zplot2 += zplot3;
vertex(x1, y1, z1);
}
}
/**
* Perform initialization specific to curveVertex(), and handle standard
* error modes. Can be overridden by subclasses that need the flexibility.
*/
protected void curveVertexCheck() {
if (shape != POLYGON) {
throw new RuntimeException("You must use beginShape() or " +
"beginShape(POLYGON) before curveVertex()");
}
// to improve code init time, allocate on first use.
if (curveVertices == null) {
curveVertices = new float[128][3];
}
if (curveVertexCount == curveVertices.length) {
curveVertices = (float[][]) PApplet.expand(curveVertices);
}
curveInitCheck();
}
public void curveVertex(float x, float y) {
curveVertexCheck();
float[] vertex = curveVertices[curveVertexCount];
vertex[X] = x;
vertex[Y] = y;
curveVertexCount++;
// draw a segment if there are enough points
if (curveVertexCount > 3) {
curveVertexSegment(curveVertices[curveVertexCount-4][X],
curveVertices[curveVertexCount-4][Y],
curveVertices[curveVertexCount-3][X],
curveVertices[curveVertexCount-3][Y],
curveVertices[curveVertexCount-2][X],
curveVertices[curveVertexCount-2][Y],
curveVertices[curveVertexCount-1][X],
curveVertices[curveVertexCount-1][Y]);
}
}
public void curveVertex(float x, float y, float z) {
curveVertexCheck();
float[] vertex = curveVertices[curveVertexCount];
vertex[X] = x;
vertex[Y] = y;
vertex[Z] = z;
curveVertexCount++;
// draw a segment if there are enough points
if (curveVertexCount > 3) {
curveVertexSegment(curveVertices[curveVertexCount-4][X],
curveVertices[curveVertexCount-4][Y],
curveVertices[curveVertexCount-4][Z],
curveVertices[curveVertexCount-3][X],
curveVertices[curveVertexCount-3][Y],
curveVertices[curveVertexCount-3][Z],
curveVertices[curveVertexCount-2][X],
curveVertices[curveVertexCount-2][Y],
curveVertices[curveVertexCount-2][Z],
curveVertices[curveVertexCount-1][X],
curveVertices[curveVertexCount-1][Y],
curveVertices[curveVertexCount-1][Z]);
}
}
/**
* Handle emitting a specific segment of Catmull-Rom curve. This can be
* overridden by subclasses that need more efficient rendering options.
*/
protected void curveVertexSegment(float x1, float y1,
float x2, float y2,
float x3, float y3,
@@ -1220,7 +1286,7 @@ public class PGraphics extends PImage implements PConstants {
float yplot3 = draw.m30*y1 + draw.m31*y2 + draw.m32*y3 + draw.m33*y4;
// vertex() will reset splineVertexCount, so save it
int savedCount = splineVertexCount;
int savedCount = curveVertexCount;
vertex(x0, y0);
for (int j = 0; j < curveDetail; j++) {
@@ -1228,10 +1294,14 @@ public class PGraphics extends PImage implements PConstants {
y0 += yplot1; yplot1 += yplot2; yplot2 += yplot3;
vertex(x0, y0);
}
splineVertexCount = savedCount;
curveVertexCount = savedCount;
}
/**
* Handle emitting a specific segment of Catmull-Rom curve. This can be
* overridden by subclasses that need more efficient rendering options.
*/
protected void curveVertexSegment(float x1, float y1, float z1,
float x2, float y2, float z2,
float x3, float y3, float z3,
@@ -1251,7 +1321,7 @@ public class PGraphics extends PImage implements PConstants {
float yplot3 = draw.m30*y1 + draw.m31*y2 + draw.m32*y3 + draw.m33*y4;
// vertex() will reset splineVertexCount, so save it
int savedCount = splineVertexCount;
int savedCount = curveVertexCount;
float zplot1 = draw.m10*z1 + draw.m11*z2 + draw.m12*z3 + draw.m13*z4;
float zplot2 = draw.m20*z1 + draw.m21*z2 + draw.m22*z3 + draw.m23*z4;
@@ -1264,21 +1334,7 @@ public class PGraphics extends PImage implements PConstants {
z0 += zplot1; zplot1 += zplot2; zplot2 += zplot3;
vertex(x0, y0, z0);
}
splineVertexCount = savedCount;
}
/** This feature is in testing, do not use or rely upon its implementation */
public void breakShape() {
}
public void endShape() {
endShape(OPEN);
}
public void endShape(int mode) {
curveVertexCount = savedCount;
}
@@ -3112,12 +3168,6 @@ public class PGraphics extends PImage implements PConstants {
// TRANSFORMATION MATRIX
static final String ERROR_PUSHMATRIX_OVERFLOW =
"Too many calls to pushMatrix().";
static final String ERROR_PUSHMATRIX_UNDERFLOW =
"Too many calls to popMatrix(), and not enough to pushMatrix().";
/**
* Push a copy of the current transformation matrix onto the stack.
*/
@@ -4148,9 +4198,10 @@ public class PGraphics extends PImage implements PConstants {
static protected void depthErrorXYZ(String method) {
showError(method + "(x, y, z) can only be used with a renderer that " +
showError(method + "() with x, y, and z coordinates " +
"can only be used with a renderer that " +
"supports 3D, such as P3D or OPENGL. " +
"Use " + method + "(x, y) instead.");
"Use a version without a z-coordinate instead.");
}
+9 -49
View File
@@ -30,9 +30,10 @@ import java.util.Arrays;
/**
* Subclass of PGraphics that handles fast 2D rendering,
* more commonly referred to as P2D. This class uses no Java2D
* and will run with Java 1.1.
* Subclass of PGraphics that handles fast 2D rendering using a
* MemoryImageSource. The renderer found in this class is not as accurate as
* PGraphicsJava2D, but offers certain speed tradeoffs, particular when
* messing with the pixels array, or displaying image or video data.
*/
public class PGraphics2D extends PGraphics {
@@ -51,9 +52,9 @@ public class PGraphics2D extends PGraphics {
boolean strokeChanged = true;
boolean fillChanged = true;
static final int CVERTEX_ALLOC = 128;
float cvertex[][] = new float[CVERTEX_ALLOC][VERTEX_FIELD_COUNT];
int cvertexIndex;
// static final int CVERTEX_ALLOC = 128;
// float cvertex[][] = new float[CVERTEX_ALLOC][VERTEX_FIELD_COUNT];
// int cvertexIndex;
float[][] matrixStack = new float[MATRIX_STACK_DEPTH][6];
int matrixStackDepth;
@@ -142,7 +143,7 @@ public class PGraphics2D extends PGraphics {
public void beginShape(int kind) {
shape = kind;
vertexCount = 0;
splineVertexCount = 0;
curveVertexCount = 0;
polygon.reset(0);
fpolygon.reset(4);
@@ -152,46 +153,8 @@ public class PGraphics2D extends PGraphics {
}
// PGraphics will throw a depthError
//public void normal(float nx, float ny, float nz)
// PGraphics will handle setting these
//public void textureMode(int mode)
//public void texture(PImage image)
//protected void textureVertex(float u, float v)
public void vertex(float x, float y) {
float vertex[] = polygon.nextVertex();
cvertexIndex = 0; // reset curves to start
vertex[X] = x;
vertex[Y] = y;
if (fill) {
vertex[R] = fillR;
vertex[G] = fillG;
vertex[B] = fillB;
vertex[A] = fillA;
}
if (stroke) {
vertex[SR] = strokeR;
vertex[SG] = strokeG;
vertex[SB] = strokeB;
vertex[SA] = strokeA;
vertex[SW] = strokeWeight;
}
if (textureImage != null) {
vertex[U] = textureU;
vertex[V] = textureV;
}
}
public void vertex(float x, float y, float u, float v) {
textureVertex(u, v);
vertexTexture(u, v);
vertex(x, y);
}
@@ -1185,14 +1148,12 @@ public class PGraphics2D extends PGraphics {
private void thin_pointAt(int x, int y, float z, int color) {
int index = y*width+x; // offset values are pre-calced in constructor
pixels[index] = color;
zbuffer[index] = z;
}
// expects offset/index in pixelbuffer array instead of x/y coords
// used by optimized parts of thin_flat_line() [toxi]
private void thin_pointAtIndex(int offset, float z, int color) {
pixels[offset] = color;
zbuffer[offset] = z;
}
// points are inherently flat, but always tangent
@@ -1621,7 +1582,6 @@ public class PGraphics2D extends PGraphics {
a2 * ( color & 0xff)) >> 8));
*/
}
zbuffer[index] = z;
}
+252 -262
View File
@@ -41,6 +41,93 @@ import java.util.*;
*/
public class PGraphics3D extends PGraphics {
/** The depth buffer. */
public float[] zbuffer;
/** The modelview matrix. */
public PMatrix3D modelview;
/** Inverse modelview matrix, used for lighting. */
protected PMatrix3D modelviewInv;
/**
* The camera matrix, the modelview will be set to this on beginDraw.
*/
public PMatrix3D camera;
/** Inverse camera matrix */
protected PMatrix3D cameraInv;
// ........................................................
/** Camera field of view. */
public float cameraFOV;
/** Position of the camera. */
public float cameraX, cameraY, cameraZ;
public float cameraNear, cameraFar;
/** Aspect ratio of camera's view. */
public float cameraAspect;
/** Current projection matrix. */
public PMatrix3D projection;
//////////////////////////////////////////////////////////////
/**
* Maximum lights by default is 8, which is arbitrary for this renderer,
* but is the minimum defined by OpenGL
*/
public static final int MAX_LIGHTS = 8;
public int lightCount = 0;
/** Light types */
public int[] lightType;
/** Light positions */
public float[][] lightPosition;
/** Light direction (normalized vector) */
public float[][] lightNormal;
/** Light falloff */
public float[] lightFalloffConstant;
public float[] lightFalloffLinear;
public float[] lightFalloffQuadratic;
/** Light spot angle */
public float[] lightSpotAngle;
/** Cosine of light spot angle */
public float[] lightSpotAngleCos;
/** Light spot concentration */
public float[] lightSpotConcentration;
/** Diffuse colors for lights.
* For an ambient light, this will hold the ambient color.
* Internally these are stored as numbers between 0 and 1. */
public float[][] lightDiffuse;
/** Specular colors for lights.
Internally these are stored as numbers between 0 and 1. */
public float[][] lightSpecular;
/** Current specular color for lighting */
public float[] currentLightSpecular;
/** Current light falloff */
public float currentLightFalloffConstant;
public float currentLightFalloffLinear;
public float currentLightFalloffQuadratic;
//////////////////////////////////////////////////////////////
static public final int TRI_DIFFUSE_R = 0;
static public final int TRI_DIFFUSE_G = 1;
static public final int TRI_DIFFUSE_B = 2;
@@ -71,8 +158,8 @@ public class PGraphics3D extends PGraphics {
protected float[] tempLightingContribution = new float[LIGHT_COLOR_COUNT];
protected float[] worldNormal = new float[4];
/// Used in light_triangle(). Allocated here once to avoid re-allocating
protected float[] norm = new float[3];
/// Used in lightTriangle(). Allocated here once to avoid re-allocating
protected PVector lightTriangleNorm = new PVector();
// ........................................................
@@ -108,15 +195,15 @@ public class PGraphics3D extends PGraphics {
// ........................................................
// pos of first vertex of current shape in vertices array
protected int vertex_start;
protected int shapeFirst;
// i think vertex_end is actually the last vertex in the current shape
// and is separate from vertexCount for occasions where drawing happens
// on endDraw() with all the triangles being depth sorted
protected int vertex_end;
protected int shapeLast;
// vertices may be added during clipping against the near plane.
protected int vertex_end_including_clip_verts;
protected int shapeLastPlusClipped;
// used for sorting points when triangulating a polygon
// warning - maximum number of vertices for a polygon is DEFAULT_VERTICES
@@ -124,6 +211,9 @@ public class PGraphics3D extends PGraphics {
// ........................................................
// this is done to keep track of start/stop information for lines in the
// line array, so that lines can be shown as a single path, rather than just
// individual segments. (currently not in use)
protected int pathCount;
protected int pathOffset[] = new int[64];
protected int pathLength[] = new int[64];
@@ -131,16 +221,16 @@ public class PGraphics3D extends PGraphics {
// ........................................................
// line & triangle fields (note that these overlap)
static protected final int INDEX = 0; // shape index
static protected final int VERTEX1 = 1;
static protected final int VERTEX2 = 2;
static protected final int VERTEX3 = 3; // (triangles only)
static protected final int TEXTURE_INDEX = 4; // (triangles only)
static protected final int STROKE_MODE = 3; // (lines only)
static protected final int STROKE_WEIGHT = 4; // (lines only)
// static protected final int INDEX = 0; // shape index
static protected final int VERTEX1 = 0;
static protected final int VERTEX2 = 1;
static protected final int VERTEX3 = 2; // (triangles only)
static protected final int TEXTURE_INDEX = 3; // (triangles only)
static protected final int STROKE_MODE = 2; // (lines only)
static protected final int STROKE_WEIGHT = 3; // (lines only)
static protected final int LINE_FIELD_COUNT = 5;
static protected final int TRIANGLE_FIELD_COUNT = 5;
static protected final int LINE_FIELD_COUNT = 4;
static protected final int TRIANGLE_FIELD_COUNT = 4;
// lines
static final int DEFAULT_LINES = 512;
@@ -158,7 +248,7 @@ public class PGraphics3D extends PGraphics {
protected int triangleCount; // total number of triangles
// cheap picking someday
public int shape_index;
//public int shape_index;
// ........................................................
@@ -178,6 +268,15 @@ public class PGraphics3D extends PGraphics {
public PGraphics3D() { }
//public void setParent(PApplet parent)
//public void setPrimary(boolean primary)
//public void setPath(String path)
/**
* Called in repsonse to a resize event, handles setting the
* new width and height internally, as well as re-allocating
@@ -282,6 +381,9 @@ public class PGraphics3D extends PGraphics {
}
//public boolean canDraw()
public void beginDraw() {
// insideResizeWait();
// insideDraw = true;
@@ -314,7 +416,7 @@ public class PGraphics3D extends PGraphics {
triangleCount = 0;
if (triangle != null) triangle.reset(); // necessary?
vertex_start = 0;
shapeFirst = 0;
//vertex_end = 0;
// reset textures
@@ -354,7 +456,7 @@ public class PGraphics3D extends PGraphics {
/**
* Emit any sorted geometry that's been collected on this frame.
*/
protected void flush() {
public void flush() {
if (triangleCount > 0) {
if (hints[ENABLE_DEPTH_SORT]) {
sortTriangles();
@@ -375,7 +477,10 @@ public class PGraphics3D extends PGraphics {
}
public void defaultSettings() {
//protected void checkSettings()
protected void defaultSettings() {
super.defaultSettings();
manipulatingCamera = false;
@@ -393,6 +498,9 @@ public class PGraphics3D extends PGraphics {
}
//protected void reapplySettings()
public void hint(int which) {
if (which == DISABLE_DEPTH_SORT) {
flush();
@@ -404,19 +512,22 @@ public class PGraphics3D extends PGraphics {
//////////////////////////////////////////////////////////////
//public void beginShape()
public void beginShape(int kind) {
shape = kind;
shape_index = shape_index + 1;
if (shape_index == -1) {
shape_index = 0;
}
// shape_index = shape_index + 1;
// if (shape_index == -1) {
// shape_index = 0;
// }
if (hints[ENABLE_DEPTH_SORT]) {
// continue with previous vertex, line and triangle count
// all shapes are rendered at endDraw();
vertex_start = vertexCount;
vertex_end = 0;
shapeFirst = vertexCount;
shapeLast = 0;
} else {
// reset vertex, line and triangle information
@@ -430,56 +541,18 @@ public class PGraphics3D extends PGraphics {
}
textureImage = null;
splineVertexCount = 0;
curveVertexCount = 0;
normalMode = NORMAL_MODE_AUTO;
normalCount = 0;
}
/**
* Sets the current normal vector.
* <P/>
* This is for drawing three dimensional shapes and surfaces,
* allowing you to specify a vector perpendicular to the surface
* of the shape, which determines how lighting affects it.
* <P/>
* For the most part, PGraphics3D will attempt to automatically
* assign normals to shapes, but since that's imperfect,
* this is a better option when you want more control.
* <P/>
* For people familiar with OpenGL, this function is basically
* identical to glNormal3f().
* <P/>
* Only applies inside a beginShape/endShape block.
*/
public void normal(float nx, float ny, float nz) {
normalX = nx;
normalY = ny;
normalZ = nz;
// if drawing a shape and the normal hasn't been set yet,
// then we need to set the normals for each vertex so far
if (shape != 0) {
if (normalCount == 0) {
for (int i = vertex_start; i < vertexCount; i++) {
vertices[i][NX] = normalX;
vertices[i][NY] = normalY;
vertices[i][NZ] = normalZ;
}
}
normalCount++;
if (normalCount == 1) {
// One normal per begin/end shape
normalMode = NORMAL_MODE_SHAPE;
} else {
// a separate normal for each vertex
normalMode = NORMAL_MODE_VERTEX;
}
}
}
//public void normal(float nx, float ny, float nz)
//public void textureMode(int mode)
public void texture(PImage image) {
textureImage = image;
@@ -494,128 +567,29 @@ public class PGraphics3D extends PGraphics {
public void vertex(float x, float y) {
setup_vertex(x, y, 0);
// override to properly pick up all 3D settings
vertex(x, y, 0);
}
//public void vertex(float x, float y, float z)
public void vertex(float x, float y, float u, float v) {
textureVertex(u, v);
setup_vertex(x, y, 0);
// override to properly pick up all 3D settings
vertex(x, y, 0, u, v);
}
public void vertex(float x, float y, float z) {
setup_vertex(x, y, z);
}
public void vertex(float x, float y, float z,
float u, float v) {
textureVertex(u, v);
setup_vertex(x, y, z);
}
protected void setup_vertex(float x, float y, float z) {
if (vertexCount == vertices.length) {
float temp[][] = new float[vertexCount << 1][VERTEX_FIELD_COUNT];
System.arraycopy(vertices, 0, temp, 0, vertexCount);
vertices = temp;
int temp2[] = new int[vertexCount << 1];
System.arraycopy(vertex_order, 0, temp2, 0, vertexCount);
vertex_order = temp2;
//System.out.println("allocating more vertices " + vertices.length);
}
float vertex[] = vertices[vertexCount];
// only do this if we're using an irregular (POLYGON) shape that
// will go through the triangulator. otherwise it'll do thinks like
// disappear in mathematically odd ways
// http://dev.processing.org/bugs/show_bug.cgi?id=444
if (shape == POLYGON) {
if (vertexCount > 0) {
float pvertex[] = vertices[vertexCount-1];
if ((abs(pvertex[X] - x) < EPSILON) &&
(abs(pvertex[Y] - y) < EPSILON) &&
(abs(pvertex[Z] - z) < EPSILON)) {
// this vertex is identical, don't add it,
// because it will anger the triangulator
return;
}
}
}
// user called vertex(), so that invalidates anything queued
// up for curve vertices. if this is internally called by
// spline_segment, then splineVertexCount will be saved and restored.
splineVertexCount = 0;
vertex[X] = x;
vertex[Y] = y;
vertex[Z] = z;
if (fill) {
if (textureImage != null) {
if (tint) {
vertex[R] = tintR;
vertex[G] = tintG;
vertex[B] = tintB;
vertex[A] = tintA;
} else {
vertex[R] = 1;
vertex[G] = 1;
vertex[B] = 1;
vertex[A] = 1;
}
} else {
vertex[R] = fillR;
vertex[G] = fillG;
vertex[B] = fillB;
vertex[A] = fillA;
}
vertex[AR] = ambientR;
vertex[AG] = ambientG;
vertex[AB] = ambientB;
vertex[SPR] = specularR;
vertex[SPG] = specularG;
vertex[SPB] = specularB;
//vertex[SPA] = specularA;
vertex[SHINE] = shininess;
vertex[ER] = emissiveR;
vertex[EG] = emissiveG;
vertex[EB] = emissiveB;
}
if (stroke) {
vertex[SR] = strokeR;
vertex[SG] = strokeG;
vertex[SB] = strokeB;
vertex[SA] = strokeA;
vertex[SW] = strokeWeight;
}
if (textureImage != null) {
vertex[U] = textureU;
vertex[V] = textureV;
}
vertex[NX] = normalX;
vertex[NY] = normalY;
vertex[NZ] = normalZ;
vertex[BEEN_LIT] = 0;
vertexCount++;
}
//public void vertex(float x, float y, float z, float u, float v)
//public void endShape()
public void endShape(int mode) {
vertex_end = vertexCount;
vertex_end_including_clip_verts = vertex_end;
shapeLast = vertexCount;
shapeLastPlusClipped = shapeLast;
// don't try to draw if there are no vertices
// (fixes a bug in LINE_LOOP that re-adds a nonexistent vertex)
@@ -630,7 +604,7 @@ public class PGraphics3D extends PGraphics {
// It is necessary to do this now because we will be clipping them on
// add_triangle.
for (int i = vertex_start; i < vertex_end; i++) {
for (int i = shapeFirst; i < shapeLast; i++) {
float vertex[] = vertices[i];
vertex[VX] =
@@ -667,8 +641,8 @@ public class PGraphics3D extends PGraphics {
case POINTS:
{
stop = vertex_end;
for (int i = vertex_start; i < stop; i++) {
stop = shapeLast;
for (int i = shapeFirst; i < stop; i++) {
add_path(); // total overkill for points
add_line(i, i);
}
@@ -681,13 +655,13 @@ public class PGraphics3D extends PGraphics {
{
// store index of first vertex
int first = lineCount;
stop = vertex_end - 1;
stop = shapeLast - 1;
increment = (shape == LINES) ? 2 : 1;
// for LINE_STRIP and LINE_LOOP, make this all one path
if (shape != LINES) add_path();
for (int i = vertex_start; i < stop; i+=increment) {
for (int i = shapeFirst; i < stop; i+=increment) {
// for LINES, make a new path for each segment
if (shape == LINES) add_path();
add_line(i, i+1);
@@ -703,7 +677,7 @@ public class PGraphics3D extends PGraphics {
case TRIANGLES:
{
for (int i = vertex_start; i < vertex_end-2; i += 3) {
for (int i = shapeFirst; i < shapeLast-2; i += 3) {
add_path();
//counter = i - vertex_start;
add_line(i+0, i+1);
@@ -716,17 +690,17 @@ public class PGraphics3D extends PGraphics {
case TRIANGLE_STRIP:
{
// first draw all vertices as a line strip
stop = vertex_end-1;
stop = shapeLast-1;
add_path();
for (int i = vertex_start; i < stop; i++) {
for (int i = shapeFirst; i < stop; i++) {
//counter = i - vertex_start;
add_line(i, i+1);
}
// then draw from vertex (n) to (n+2)
stop = vertex_end-2;
for (int i = vertex_start; i < stop; i++) {
stop = shapeLast-2;
for (int i = shapeFirst; i < stop; i++) {
add_path();
add_line(i, i+2);
}
@@ -737,24 +711,24 @@ public class PGraphics3D extends PGraphics {
{
// this just draws a series of line segments
// from the center to each exterior point
for (int i = vertex_start + 1; i < vertex_end; i++) {
for (int i = shapeFirst + 1; i < shapeLast; i++) {
add_path();
add_line(vertex_start, i);
add_line(shapeFirst, i);
}
// then a single line loop around the outside.
add_path();
for (int i = vertex_start + 1; i < vertex_end-1; i++) {
for (int i = shapeFirst + 1; i < shapeLast-1; i++) {
add_line(i, i+1);
}
// closing the loop
add_line(vertex_end-1, vertex_start + 1);
add_line(shapeLast-1, shapeFirst + 1);
}
break;
case QUADS:
{
for (int i = vertex_start; i < vertex_end; i += 4) {
for (int i = shapeFirst; i < shapeLast; i += 4) {
add_path();
//counter = i - vertex_start;
add_line(i+0, i+1);
@@ -767,7 +741,7 @@ public class PGraphics3D extends PGraphics {
case QUAD_STRIP:
{
for (int i = vertex_start; i < vertex_end - 3; i += 2) {
for (int i = shapeFirst; i < shapeLast - 3; i += 2) {
add_path();
add_line(i+0, i+2);
add_line(i+2, i+3);
@@ -802,16 +776,16 @@ public class PGraphics3D extends PGraphics {
{
// store index of first vertex
//int first = lineCount;
stop = vertex_end - 1;
stop = shapeLast - 1;
add_path();
for (int i = vertex_start; i < stop; i++) {
for (int i = shapeFirst; i < stop; i++) {
add_line(i, i+1);
//System.out.println("adding line " + i);
}
if (mode == CLOSE) {
// draw the last line connecting back to the first point in poly
add_line(stop, vertex_start); //lines[first][VERTEX1]);
add_line(stop, shapeFirst); //lines[first][VERTEX1]);
}
}
break;
@@ -825,9 +799,9 @@ public class PGraphics3D extends PGraphics {
switch (shape) {
case TRIANGLE_FAN:
{
stop = vertex_end - 1;
for (int i = vertex_start + 1; i < stop; i++) {
add_triangle(vertex_start, i, i+1);
stop = shapeLast - 1;
for (int i = shapeFirst + 1; i < stop; i++) {
add_triangle(shapeFirst, i, i+1);
}
}
break;
@@ -835,9 +809,9 @@ public class PGraphics3D extends PGraphics {
case TRIANGLES:
case TRIANGLE_STRIP:
{
stop = vertex_end - 2;
stop = shapeLast - 2;
increment = (shape == TRIANGLES) ? 3 : 1;
for (int i = vertex_start; i < stop; i += increment) {
for (int i = shapeFirst; i < stop; i += increment) {
// have to switch between clockwise/counter-clockwise
// otherwise the feller is backwards and renderer won't draw
if ((i % 2) == 0) {
@@ -853,7 +827,7 @@ public class PGraphics3D extends PGraphics {
{
stop = vertexCount-3;
for (int i = vertex_start; i < stop; i += 4) {
for (int i = shapeFirst; i < stop; i += 4) {
// first triangle
add_triangle(i, i+1, i+2);
// second triangle
@@ -866,7 +840,7 @@ public class PGraphics3D extends PGraphics {
{
stop = vertexCount-3;
for (int i = vertex_start; i < stop; i += 2) {
for (int i = shapeFirst; i < stop; i += 2) {
// first triangle
add_triangle(i+0, i+2, i+1);
// second triangle
@@ -901,7 +875,7 @@ public class PGraphics3D extends PGraphics {
// POINTS FROM CAMERA SPACE (VX, VY, VZ) TO SCREEN SPACE (X, Y, Z)
// this appears to be wasted time with the opengl renderer
for (int i = vertex_start; i < vertex_end_including_clip_verts; i++) {
for (int i = shapeFirst; i < shapeLastPlusClipped; i++) {
float vx[] = vertices[i];
float ox =
@@ -1020,7 +994,7 @@ public class PGraphics3D extends PGraphics {
}
lines[lineCount][VERTEX1] = a;
lines[lineCount][VERTEX2] = b;
lines[lineCount][INDEX] = -1;
// lines[lineCount][INDEX] = -1;
lines[lineCount][STROKE_MODE] = strokeCap | strokeJoin;
lines[lineCount][STROKE_WEIGHT] = (int) (strokeWeight + 0.5f); // hmm
@@ -1161,7 +1135,7 @@ public class PGraphics3D extends PGraphics {
pa * va[Y] + pb * vb[Y],
pa * va[Z] + pb * vb[Z]);
int irv = vertexCount - 1;
vertex_end_including_clip_verts++;
shapeLastPlusClipped++;
float[] rv = vertices[irv];
@@ -1234,7 +1208,7 @@ public class PGraphics3D extends PGraphics {
triangles[triangleCount][TEXTURE_INDEX] = textureIndex;
}
triangles[triangleCount][INDEX] = shape_index;
// triangles[triangleCount][INDEX] = shape_index;
triangleCount++;
}
@@ -1309,7 +1283,7 @@ public class PGraphics3D extends PGraphics {
float b[] = vertices[triangles[i][VERTEX2]];
float c[] = vertices[triangles[i][VERTEX3]];
int tex = triangles[i][TEXTURE_INDEX];
int index = triangles[i][INDEX];
// int index = triangles[i][INDEX];
// ewjordan: hack to 'fix' accuracy issues when drawing in 2d
// see also render_lines() where similar hack is employed
@@ -1366,7 +1340,7 @@ public class PGraphics3D extends PGraphics {
c[VX], c[VY], c[VZ]);
}
triangle.setIndex(index);
// triangle.setIndex(index);
triangle.render();
//System.out.println(i + " " + a[Z] + " " + b[Z] + " " + c[Z]);
@@ -1428,7 +1402,7 @@ public class PGraphics3D extends PGraphics {
for (int i = 0; i < lineCount; i ++) {
float a[] = vertices[lines[i][VERTEX1]];
float b[] = vertices[lines[i][VERTEX2]];
int index = lines[i][INDEX];
// int index = lines[i][INDEX];
// 2D hack added by ewjordan 6/13/07
// Offset coordinates by a little bit if drawing 2D graphics.
@@ -1499,7 +1473,7 @@ public class PGraphics3D extends PGraphics {
}
*/
line.setIndex(index);
// line.setIndex(index);
line.draw();
}
@@ -1518,6 +1492,13 @@ public class PGraphics3D extends PGraphics {
* bit of code from the web.
*/
private void triangulate_polygon() {
if (vertex_order.length != vertices.length) {
int[] temp = new int[vertices.length];
// since vertex_start may not be zero, might need to keep old stuff around
PApplet.arraycopy(vertex_order, temp, vertexCount);
vertex_order = temp;
}
// this clipping algorithm only works in 2D, so in cases where a
// polygon is drawn perpendicular to the z-axis, the area will be zero,
// and triangulation will fail. as such, when the area calculates to
@@ -1549,7 +1530,7 @@ public class PGraphics3D extends PGraphics {
// first we check if the polygon goes clockwise or counterclockwise
float area = 0;
for (int p = vertex_end - 1, q = vertex_start; q < vertex_end; p = q++) {
for (int p = shapeLast - 1, q = shapeFirst; q < shapeLast; p = q++) {
area += (vertices[q][d1] * vertices[p][d2] -
vertices[p][d1] * vertices[q][d2]);
}
@@ -1561,8 +1542,8 @@ public class PGraphics3D extends PGraphics {
boolean foundValidX = false;
boolean foundValidY = false;
for (int i = vertex_start; i < vertex_end; i++) {
for (int j = i; j < vertex_end; j++){
for (int i = shapeFirst; i < shapeLast; i++) {
for (int j = i; j < shapeLast; j++){
if ( vertices[i][X] != vertices[j][X] ) foundValidX = true;
if ( vertices[i][Y] != vertices[j][Y] ) foundValidY = true;
}
@@ -1581,7 +1562,7 @@ public class PGraphics3D extends PGraphics {
}
// re-calculate the area, with what should be good values
for (int p = vertex_end - 1, q = vertex_start; q < vertex_end; p = q++) {
for (int p = shapeLast - 1, q = shapeFirst; q < shapeLast; p = q++) {
area += (vertices[q][d1] * vertices[p][d2] -
vertices[p][d1] * vertices[q][d2]);
}
@@ -1590,30 +1571,30 @@ public class PGraphics3D extends PGraphics {
// don't allow polygons to come back and meet themselves,
// otherwise it will anger the triangulator
// http://dev.processing.org/bugs/show_bug.cgi?id=97
float vfirst[] = vertices[vertex_start];
float vlast[] = vertices[vertex_end-1];
float vfirst[] = vertices[shapeFirst];
float vlast[] = vertices[shapeLast-1];
if ((abs(vfirst[X] - vlast[X]) < EPSILON) &&
(abs(vfirst[Y] - vlast[Y]) < EPSILON) &&
(abs(vfirst[Z] - vlast[Z]) < EPSILON)) {
vertex_end--;
shapeLast--;
}
// then sort the vertices so they are always in a counterclockwise order
int j = 0;
if (area > 0) {
for (int i = vertex_start; i < vertex_end; i++) {
j = i - vertex_start;
for (int i = shapeFirst; i < shapeLast; i++) {
j = i - shapeFirst;
vertex_order[j] = i;
}
} else {
for (int i = vertex_start; i < vertex_end; i++) {
j = i - vertex_start;
vertex_order[j] = (vertex_end - 1) - j;
for (int i = shapeFirst; i < shapeLast; i++) {
j = i - shapeFirst;
vertex_order[j] = (shapeLast - 1) - j;
}
}
// remove vc-2 Vertices, creating 1 triangle every time
int vc = vertex_end - vertex_start;
int vc = shapeLast - shapeFirst;
int count = 2*vc; // complex polygon detection
for (int m = 0, v = vc - 1; vc > 2; ) {
@@ -2053,15 +2034,12 @@ public class PGraphics3D extends PGraphics {
vertices[vIndex2][VZ] - vertices[vIndex][VZ],
vertices[vIndex3][VX] - vertices[vIndex][VX],
vertices[vIndex3][VY] - vertices[vIndex][VY],
vertices[vIndex3][VZ] - vertices[vIndex][VZ], norm);
float nmag = mag(norm[X], norm[Y], norm[Z]);
if (nmag != 0 && nmag != 1) {
norm[X] /= nmag; norm[Y] /= nmag; norm[Z] /= nmag;
}
vertices[vIndex][NX] = norm[X];
vertices[vIndex][NY] = norm[Y];
vertices[vIndex][NZ] = norm[Z];
vertices[vIndex3][VZ] - vertices[vIndex][VZ], lightTriangleNorm);
lightTriangleNorm.normalize();
vertices[vIndex][NX] = lightTriangleNorm.x;
vertices[vIndex][NY] = lightTriangleNorm.y;
vertices[vIndex][NZ] = lightTriangleNorm.z;
// The true at the end says the normal is already in world coordinates
calc_lighting_contribution(vIndex, tempLightingContribution, true);
@@ -2077,25 +2055,25 @@ public class PGraphics3D extends PGraphics {
else {
if (normalMode == NORMAL_MODE_SHAPE) {
vIndex = triangles[triIndex][VERTEX1];
vertices[vIndex][NX] = vertices[vertex_start][NX];
vertices[vIndex][NY] = vertices[vertex_start][NY];
vertices[vIndex][NZ] = vertices[vertex_start][NZ];
vertices[vIndex][NX] = vertices[shapeFirst][NX];
vertices[vIndex][NY] = vertices[shapeFirst][NY];
vertices[vIndex][NZ] = vertices[shapeFirst][NZ];
calc_lighting_contribution(vIndex, tempLightingContribution);
copy_vertex_color_to_triangle(triIndex, vIndex, 0,
tempLightingContribution);
vIndex = triangles[triIndex][VERTEX2];
vertices[vIndex][NX] = vertices[vertex_start][NX];
vertices[vIndex][NY] = vertices[vertex_start][NY];
vertices[vIndex][NZ] = vertices[vertex_start][NZ];
vertices[vIndex][NX] = vertices[shapeFirst][NX];
vertices[vIndex][NY] = vertices[shapeFirst][NY];
vertices[vIndex][NZ] = vertices[shapeFirst][NZ];
calc_lighting_contribution(vIndex, tempLightingContribution);
copy_vertex_color_to_triangle(triIndex, vIndex, 1,
tempLightingContribution);
vIndex = triangles[triIndex][VERTEX3];
vertices[vIndex][NX] = vertices[vertex_start][NX];
vertices[vIndex][NY] = vertices[vertex_start][NY];
vertices[vIndex][NZ] = vertices[vertex_start][NZ];
vertices[vIndex][NX] = vertices[shapeFirst][NX];
vertices[vIndex][NY] = vertices[shapeFirst][NY];
vertices[vIndex][NZ] = vertices[shapeFirst][NZ];
calc_lighting_contribution(vIndex, tempLightingContribution);
copy_vertex_color_to_triangle(triIndex, vIndex, 2,
tempLightingContribution);
@@ -2124,30 +2102,31 @@ public class PGraphics3D extends PGraphics {
vertices[vIndex2][VZ] - vertices[vIndex][VZ],
vertices[vIndex3][VX] - vertices[vIndex][VX],
vertices[vIndex3][VY] - vertices[vIndex][VY],
vertices[vIndex3][VZ] - vertices[vIndex][VZ], norm);
float nmag = mag(norm[X], norm[Y], norm[Z]);
if (nmag != 0 && nmag != 1) {
norm[X] /= nmag; norm[Y] /= nmag; norm[Z] /= nmag;
}
vertices[vIndex][NX] = norm[X];
vertices[vIndex][NY] = norm[Y];
vertices[vIndex][NZ] = norm[Z];
vertices[vIndex3][VZ] - vertices[vIndex][VZ], lightTriangleNorm);
// float nmag = mag(norm[X], norm[Y], norm[Z]);
// if (nmag != 0 && nmag != 1) {
// norm[X] /= nmag; norm[Y] /= nmag; norm[Z] /= nmag;
// }
lightTriangleNorm.normalize();
vertices[vIndex][NX] = lightTriangleNorm.x;
vertices[vIndex][NY] = lightTriangleNorm.y;
vertices[vIndex][NZ] = lightTriangleNorm.z;
// The true at the end says the normal is already in world coordinates
calc_lighting_contribution(vIndex, tempLightingContribution, true);
copy_vertex_color_to_triangle(triIndex, vIndex, 0,
tempLightingContribution);
vertices[vIndex2][NX] = norm[X];
vertices[vIndex2][NY] = norm[Y];
vertices[vIndex2][NZ] = norm[Z];
vertices[vIndex2][NX] = lightTriangleNorm.x;
vertices[vIndex2][NY] = lightTriangleNorm.y;
vertices[vIndex2][NZ] = lightTriangleNorm.z;
// The true at the end says the normal is already in world coordinates
calc_lighting_contribution(vIndex2, tempLightingContribution, true);
copy_vertex_color_to_triangle(triIndex, vIndex2, 1,
tempLightingContribution);
vertices[vIndex3][NX] = norm[X];
vertices[vIndex3][NY] = norm[Y];
vertices[vIndex3][NZ] = norm[Z];
vertices[vIndex3][NX] = lightTriangleNorm.x;
vertices[vIndex3][NY] = lightTriangleNorm.y;
vertices[vIndex3][NZ] = lightTriangleNorm.z;
// The true at the end says the normal is already in world coordinates
calc_lighting_contribution(vIndex3, tempLightingContribution, true);
copy_vertex_color_to_triangle(triIndex, vIndex3, 2,
@@ -2162,7 +2141,7 @@ public class PGraphics3D extends PGraphics {
// normal specified for this shape, go ahead and apply the same lighting
// contribution to every vertex in this shape (one lighting calc!)
if (!lightingDependsOnVertexPosition && normalMode == NORMAL_MODE_SHAPE) {
calc_lighting_contribution(vertex_start, tempLightingContribution);
calc_lighting_contribution(shapeFirst, tempLightingContribution);
for (int tri = 0; tri < triangleCount; tri++) {
light_triangle(tri, tempLightingContribution);
}
@@ -3878,6 +3857,7 @@ public class PGraphics3D extends PGraphics {
}
/*
private final void cross(float a0, float a1, float a2,
float b0, float b1, float b2,
float[] out) {
@@ -3885,6 +3865,16 @@ public class PGraphics3D extends PGraphics {
out[1] = a2*b0 - a0*b2;
out[2] = a0*b1 - a1*b0;
}
*/
private final void cross(float a0, float a1, float a2,
float b0, float b1, float b2,
PVector out) {
out.x = a1*b2 - a2*b1;
out.y = a2*b0 - a0*b2;
out.z = a0*b1 - a1*b0;
}
/*
+86 -43
View File
@@ -52,6 +52,15 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
public Graphics2D g2;
GeneralPath gpath;
/// break the shape at the next vertex (next vertex() call is a moveto())
boolean breakShape;
/// coordinates for internal curve calculation
float[] curveCoordX = new float[4];
float[] curveCoordY = new float[4];
float[] curveDrawX = new float[4];
float[] curveDrawY = new float[4];
int transformCount;
AffineTransform transformStack[] =
new AffineTransform[MATRIX_STACK_DEPTH];
@@ -160,7 +169,7 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
//super.beginShape(kind);
shape = kind;
vertexCount = 0;
splineVertexCount = 0;
curveVertexCount = 0;
// set gpath to null, because when mixing curves and straight
// lines, vertexCount will be set back to zero, so vertexCount == 1
@@ -182,7 +191,7 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
public void vertex(float x, float y) {
splineVertexCount = 0;
curveVertexCount = 0;
//float vertex[];
if (vertexCount == vertices.length) {
@@ -303,13 +312,13 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
}
public void vertex(float x, float y, float u, float v) {
variationError("vertex(x, y, u, v)");
public void vertex(float x, float y, float z) {
depthErrorXYZ("vertex");
}
public void vertex(float x, float y, float z) {
depthErrorXYZ("vertex");
public void vertex(float x, float y, float u, float v) {
variationError("vertex(x, y, u, v)");
}
@@ -321,26 +330,60 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
public void bezierVertex(float x1, float y1,
float x2, float y2,
float x3, float y3) {
if (gpath == null) {
throw new RuntimeException("Must call vertex() at least once " +
"before using bezierVertex()");
}
if (shape == POLYGON) {
gpath.curveTo(x1, y1, x2, y2, x3, y3);
} else {
throw new RuntimeException("bezierVertex() can only be used with " +
"LINE_STRIP, LINE_LOOP, or POLYGON");
}
bezierVertexCheck();
gpath.curveTo(x1, y1, x2, y2, x3, y3);
}
float curveCoordX[] = new float[4];
float curveCoordY[] = new float[4];
float curveDrawX[] = new float[4];
float curveDrawY[] = new float[4];
public void bezierVertex(float x2, float y2, float z2,
float x3, float y3, float z3,
float x4, float y4, float z4) {
depthErrorXYZ("bezierVertex");
}
protected void curveVertexCheck() {
super.curveVertexCheck();
curveCoordX = new float[4];
curveCoordY = new float[4];
curveDrawX = new float[4];
curveDrawY = new float[4];
}
protected void curveVertexSegment(float x1, float y1,
float x2, float y2,
float x3, float y3,
float x4, float y4) {
curveCoordX[0] = x1;
curveCoordY[0] = y1;
curveCoordX[1] = x2;
curveCoordY[1] = y2;
curveCoordX[2] = x3;
curveCoordY[2] = y3;
curveCoordX[3] = x4;
curveCoordY[3] = y4;
curveToBezierMatrix.mult(curveCoordX, curveDrawX);
curveToBezierMatrix.mult(curveCoordY, curveDrawY);
// since the paths are continuous,
// only the first point needs the actual moveto
if (gpath == null) {
gpath = new GeneralPath();
gpath.moveTo(curveDrawX[0], curveDrawY[0]);
}
gpath.curveTo(curveDrawX[1], curveDrawY[1],
curveDrawX[2], curveDrawY[2],
curveDrawX[3], curveDrawY[3]);
}
/*
public void curveVertex(float x, float y) {
if (shape != POLYGON) {
throw new RuntimeException("curveVertex() can only be used with " +
@@ -350,32 +393,32 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
curveInitCheck();
vertexCount = 0;
if (splineVertices == null) {
splineVertices = new float[DEFAULT_SPLINE_VERTICES][VERTEX_FIELD_COUNT];
if (curveVertices == null) {
curveVertices = new float[DEFAULT_SPLINE_VERTICES][VERTEX_FIELD_COUNT];
}
// if more than 128 points, shift everything back to the beginning
if (splineVertexCount == DEFAULT_SPLINE_VERTICES) {
System.arraycopy(splineVertices[DEFAULT_SPLINE_VERTICES - 3], 0,
splineVertices[0], 0, VERTEX_FIELD_COUNT);
System.arraycopy(splineVertices[DEFAULT_SPLINE_VERTICES - 2], 0,
splineVertices[1], 0, VERTEX_FIELD_COUNT);
System.arraycopy(splineVertices[DEFAULT_SPLINE_VERTICES - 1], 0,
splineVertices[2], 0, VERTEX_FIELD_COUNT);
splineVertexCount = 3;
if (curveVertexCount == DEFAULT_SPLINE_VERTICES) {
System.arraycopy(curveVertices[DEFAULT_SPLINE_VERTICES - 3], 0,
curveVertices[0], 0, VERTEX_FIELD_COUNT);
System.arraycopy(curveVertices[DEFAULT_SPLINE_VERTICES - 2], 0,
curveVertices[1], 0, VERTEX_FIELD_COUNT);
System.arraycopy(curveVertices[DEFAULT_SPLINE_VERTICES - 1], 0,
curveVertices[2], 0, VERTEX_FIELD_COUNT);
curveVertexCount = 3;
}
// this new guy will be the fourth point (or higher),
// which means it's time to draw segments of the curve
if (splineVertexCount >= 3) {
curveCoordX[0] = splineVertices[splineVertexCount-3][X];
curveCoordY[0] = splineVertices[splineVertexCount-3][Y];
if (curveVertexCount >= 3) {
curveCoordX[0] = curveVertices[curveVertexCount-3][X];
curveCoordY[0] = curveVertices[curveVertexCount-3][Y];
curveCoordX[1] = splineVertices[splineVertexCount-2][X];
curveCoordY[1] = splineVertices[splineVertexCount-2][Y];
curveCoordX[1] = curveVertices[curveVertexCount-2][X];
curveCoordY[1] = curveVertices[curveVertexCount-2][Y];
curveCoordX[2] = splineVertices[splineVertexCount-1][X];
curveCoordY[2] = splineVertices[splineVertexCount-1][Y];
curveCoordX[2] = curveVertices[curveVertexCount-1][X];
curveCoordY[2] = curveVertices[curveVertexCount-1][Y];
curveCoordX[3] = x;
curveCoordY[3] = y;
@@ -396,10 +439,11 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
}
// add the current point to the list
splineVertices[splineVertexCount][X] = x;
splineVertices[splineVertexCount][Y] = y;
splineVertexCount++;
curveVertices[curveVertexCount][X] = x;
curveVertices[curveVertexCount][Y] = y;
curveVertexCount++;
}
*/
public void curveVertex(float x, float y, float z) {
@@ -407,7 +451,6 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
}
boolean breakShape;
public void breakShape() {
breakShape = true;
}
+3 -1
View File
@@ -125,7 +125,9 @@ public class PLine implements PConstants
m_pixels = parent.pixels;
//m_stencil = parent.stencil;
m_zbuffer = parent.zbuffer;
if (parent instanceof PGraphics3D) {
m_zbuffer = ((PGraphics3D) parent).zbuffer;
}
// other things to reset
+14 -34
View File
@@ -389,47 +389,27 @@ public final class PMatrix3D implements PMatrix /*, PConstants*/ {
/**
* Multiply a three or four element vector against this matrix.
* If out is null or not length four, a new float array will be returned.
* The values for vec and out can be the same (though that's less efficient).
* Multiply a three or four element vector against this matrix. If out is
* null or not length 3 or 4, a new float array (length 3) will be returned.
*/
public float[] mult(float[] source, float[] target) {
if (target == null || target.length < 3) {
target = new float[3];
}
if (source == target) {
throw new RuntimeException("The source and target vectors used in " +
"PMatrix3D.mult() cannot be identical.");
}
if (target.length == 3) {
if (source == target) {
float tmpx = m00*source[0] + m01*source[1] + m02*source[2] + m03;
float tmpy = m10*source[0] + m11*source[1] + m12*source[2] + m13;
float tmpz = m20*source[0] + m21*source[1] + m22*source[2] + m23;
target[0] = tmpx;
target[1] = tmpy;
target[2] = tmpz;
} else {
target[0] = m00*source[0] + m01*source[1] + m02*source[2] + m03;
target[1] = m10*source[0] + m11*source[1] + m12*source[2] + m13;
target[2] = m20*source[0] + m21*source[1] + m22*source[2] + m23;
}
target[0] = m00*source[0] + m01*source[1] + m02*source[2] + m03;
target[1] = m10*source[0] + m11*source[1] + m12*source[2] + m13;
target[2] = m20*source[0] + m21*source[1] + m22*source[2] + m23;
} else if (target.length > 3) {
if (source == target) {
float tmpx = m00*source[0] + m01*source[1] + m02*source[2] + m03*source[3];
float tmpy = m10*source[0] + m11*source[1] + m12*source[2] + m13*source[3];
float tmpz = m20*source[0] + m21*source[1] + m22*source[2] + m23*source[3];
float tmpw = m30*source[0] + m31*source[1] + m32*source[2] + m33*source[3];
target[0] = tmpx;
target[1] = tmpy;
target[2] = tmpz;
target[3] = tmpw;
} else {
target[0] = m00*source[0] + m01*source[1] + m02*source[2] + m03*source[3];
target[1] = m10*source[0] + m11*source[1] + m12*source[2] + m13*source[3];
target[2] = m20*source[0] + m21*source[1] + m22*source[2] + m23*source[3];
target[3] = m30*source[0] + m31*source[1] + m32*source[2] + m33*source[3];
}
target[0] = m00*source[0] + m01*source[1] + m02*source[2] + m03*source[3];
target[1] = m10*source[0] + m11*source[1] + m12*source[2] + m13*source[3];
target[2] = m20*source[0] + m21*source[1] + m22*source[2] + m23*source[3];
target[3] = m30*source[0] + m31*source[1] + m32*source[2] + m33*source[3];
}
return target;
}