From 8f9baa43b728a85115c36925d1451365e0d0212d Mon Sep 17 00:00:00 2001 From: codeanticode Date: Wed, 11 Apr 2012 21:27:37 +0000 Subject: [PATCH] Better handling of geometric transformations in PShape3D. --- core/src/processing/core/PGraphics.java | 2 +- core/src/processing/core/PShape.java | 4 +- .../src/processing/opengl/PFramebuffer.java | 6 +- .../processing/opengl/PGraphicsOpenGL.java | 164 ++++- .../src/processing/opengl/PShape3D.java | 627 +++++++----------- 5 files changed, 384 insertions(+), 419 deletions(-) diff --git a/core/src/processing/core/PGraphics.java b/core/src/processing/core/PGraphics.java index 6a0edb6f0..63ea2a701 100644 --- a/core/src/processing/core/PGraphics.java +++ b/core/src/processing/core/PGraphics.java @@ -932,7 +932,7 @@ public class PGraphics extends PImage implements PConstants { if (which > 0) { return hints[which]; } else { - return hints[-which]; + return !hints[-which]; } } diff --git a/core/src/processing/core/PShape.java b/core/src/processing/core/PShape.java index 2c8659fd8..d83166d6d 100644 --- a/core/src/processing/core/PShape.java +++ b/core/src/processing/core/PShape.java @@ -1499,7 +1499,7 @@ public class PShape implements PConstants { if (source instanceof PMatrix2D) { applyMatrix((PMatrix2D) source); } else if (source instanceof PMatrix3D) { - applyMatrix(source); + applyMatrix((PMatrix3D) source); } } @@ -1522,7 +1522,7 @@ public class PShape implements PConstants { } - public void apply(PMatrix3D source) { + public void applyMatrix(PMatrix3D source) { applyMatrix(source.m00, source.m01, source.m02, source.m03, source.m10, source.m11, source.m12, source.m13, source.m20, source.m21, source.m22, source.m23, diff --git a/java/libraries/opengl/src/processing/opengl/PFramebuffer.java b/java/libraries/opengl/src/processing/opengl/PFramebuffer.java index 99bc44fe8..ce518c029 100644 --- a/java/libraries/opengl/src/processing/opengl/PFramebuffer.java +++ b/java/libraries/opengl/src/processing/opengl/PFramebuffer.java @@ -189,10 +189,10 @@ public class PFramebuffer implements PConstants { public void finish() { if (noDepth) { // No need to clear depth buffer because depth testing was disabled. - if (pg.hintEnabled(DISABLE_DEPTH_TEST)) { - pgl.glDisable(PGL.GL_DEPTH_TEST); + if (pg.hintEnabled(ENABLE_DEPTH_TEST)) { + pgl.glEnable(PGL.GL_DEPTH_TEST); } else { - pgl.glEnable(PGL.GL_DEPTH_TEST); + pgl.glDisable(PGL.GL_DEPTH_TEST); } } } diff --git a/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java b/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java index 1f429b244..dc070a5a4 100644 --- a/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java +++ b/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java @@ -342,6 +342,8 @@ public class PGraphicsOpenGL extends PGraphics { // Bezier and Catmull-Rom curves + // TODO: move bezier/curve vertex generation to InGeometry. + protected boolean bezierInited = false; public int bezierDetail = 20; protected PMatrix3D bezierDrawMatrix; @@ -4509,8 +4511,7 @@ public class PGraphicsOpenGL extends PGraphics { protected void backgroundImpl() { - tessGeo.clear(); - texCache.clear(); + flush(); pgl.glDepthMask(true); pgl.glClearColor(0, 0, 0, 0); @@ -4521,7 +4522,7 @@ public class PGraphicsOpenGL extends PGraphics { pgl.glDepthMask(true); } - pgl.glClearColor(backgroundR, backgroundG, backgroundB, 1); + pgl.glClearColor(backgroundR, backgroundG, backgroundB, backgroundA); pgl.glClear(PGL.GL_COLOR_BUFFER_BIT); if (0 < parent.frameCount) { clearColorBuffer = true; @@ -6160,13 +6161,18 @@ public class PGraphicsOpenGL extends PGraphics { public int[] emissive; public float[] shininess; - // TODO: this should probably go in the TessGeometry class + // TODO: this should probably go in the TessGeometry class, or maybe not... public int[][] edges; - // For later, to be used by libraries... - //public float[][] mtexcoords; - //public float[][] attributes; - + // Internally used by the addVertex() methods. + protected int fillColor; + protected int strokeColor; + protected float strokeWeight; + protected int ambientColor; + protected int specularColor; + protected int emissiveColor; + protected float shininessFactor; + public InGeometry(int mode) { renderMode = mode; allocate(); @@ -6260,8 +6266,7 @@ public class PGraphicsOpenGL extends PGraphics { public boolean isFull() { return PGL.MAX_TESS_VERTICES <= vertexCount; } - - + public int addVertex(float x, float y, int fcolor, float u, float v, @@ -6277,6 +6282,17 @@ public class PGraphicsOpenGL extends PGraphics { code); } + public int addVertex(float x, float y, + float u, float v, + int code) { + return addVertex(x, y, + fillColor, + u, v, + strokeColor, strokeWeight, + ambientColor, specularColor, emissiveColor, shininessFactor, + code); + } + public int addVertex(float x, float y, int fcolor, int scolor, float sweight, @@ -6290,7 +6306,16 @@ public class PGraphicsOpenGL extends PGraphics { am, sp, em, shine, code); } - + + public int addVertex(float x, float y, + int code) { + return addVertex(x, y, + fillColor, + strokeColor, strokeWeight, + ambientColor, specularColor, emissiveColor, shininessFactor, + code); + } + public int addVertex(float x, float y, float z, int fcolor, float nx, float ny, float nz, @@ -6332,6 +6357,19 @@ public class PGraphicsOpenGL extends PGraphics { return lastVertex; } + + public int addVertex(float x, float y, float z, + float nx, float ny, float nz, + float u, float v, + int code) { + return addVertex(x, y, z, + fillColor, + nx, ny, nz, + u, v, + strokeColor, strokeWeight, + ambientColor, specularColor, emissiveColor, shininessFactor, + code); + } public int javaToNativeARGB(int color) { if (PGL.BIG_ENDIAN) { @@ -6760,12 +6798,11 @@ public class PGraphicsOpenGL extends PGraphics { } } - // Primitive generation - public void generateEllipse(int ellipseMode, float a, float b, float c, float d, boolean fill, int fillColor, boolean stroke, int strokeColor, float strokeWeight, - int ambient, int specular, int emissive, float shininess) { + int ambientColor, int specularColor, int emissiveColor, + float shininessFactor) { float x = a; float y = b; float w = c; @@ -6795,7 +6832,15 @@ public class PGraphicsOpenGL extends PGraphics { y += h; h = -h; } - + + this.fillColor = fillColor; + this.strokeColor = strokeColor; + this.strokeWeight = strokeWeight; + this.ambientColor = ambientColor; + this.specularColor = specularColor; + this.emissiveColor = emissiveColor; + this.shininessFactor = shininessFactor; + float radiusH = w / 2; float radiusV = h / 2; @@ -6814,10 +6859,7 @@ public class PGraphicsOpenGL extends PGraphics { float inc = (float) PGraphicsOpenGL.SINCOS_LENGTH / accuracy; if (fill) { - addVertex(centerX, centerY, - fillColor, strokeColor, strokeWeight, - ambient, specular, emissive, shininess, - VERTEX); + addVertex(centerX, centerY, VERTEX); } int idx0, pidx, idx; idx0 = pidx = idx = 0; @@ -6825,8 +6867,6 @@ public class PGraphicsOpenGL extends PGraphics { for (int i = 0; i < accuracy; i++) { idx = addVertex(centerX + PGraphicsOpenGL.cosLUT[(int) val] * radiusH, centerY + PGraphicsOpenGL.sinLUT[(int) val] * radiusV, - fillColor, strokeColor, strokeWeight, - ambient, specular, emissive, shininess, VERTEX); val = (val + inc) % PGraphicsOpenGL.SINCOS_LENGTH; @@ -6841,12 +6881,82 @@ public class PGraphicsOpenGL extends PGraphics { // Back to the beginning addVertex(centerX + PGraphicsOpenGL.cosLUT[0] * radiusH, centerY + PGraphicsOpenGL.sinLUT[0] * radiusV, - fillColor, strokeColor, strokeWeight, - ambient, specular, emissive, shininess, VERTEX); if (stroke) addEdge(idx, idx0, false, true); } + public void generateBox(float w, float h, float d, + boolean fill, int fillColor, + boolean stroke, int strokeColor, float strokeWeight, + int ambientColor, int specularColor, int emissiveColor, + float shininessFactor) { + float x1 = -w/2f; float x2 = w/2f; + float y1 = -h/2f; float y2 = h/2f; + float z1 = -d/2f; float z2 = d/2f; + + this.fillColor = fillColor; + this.strokeColor = strokeColor; + this.strokeWeight = strokeWeight; + this.ambientColor = ambientColor; + this.specularColor = specularColor; + this.emissiveColor = emissiveColor; + this.shininessFactor = shininessFactor; + + if (fill || stroke) { + // front face + addVertex(x1, y1, z1, 0, 0, 1, 0, 0, VERTEX); + addVertex(x2, y1, z1, 0, 0, 1, 1, 0, VERTEX); + addVertex(x2, y2, z1, 0, 0, 1, 1, 1, VERTEX); + addVertex(x1, y2, z1, 0, 0, 1, 0, 1, VERTEX); + + // right face + addVertex(x2, y1, z1, 1, 0, 0, 0, 0, VERTEX); + addVertex(x2, y1, z2, 1, 0, 0, 1, 0, VERTEX); + addVertex(x2, y2, z2, 1, 0, 0, 1, 1, VERTEX); + addVertex(x2, y2, z1, 1, 0, 0, 0, 1, VERTEX); + + // back face + addVertex(x2, y1, z2, 0, 0, -1, 0, 0, VERTEX); + addVertex(x1, y1, z2, 0, 0, -1, 1, 0, VERTEX); + addVertex(x1, y2, z2, 0, 0, -1, 1, 1, VERTEX); + addVertex(x2, y2, z2, 0, 0, -1, 0, 1, VERTEX); + + // left face + addVertex(x1, y1, z2, -1, 0, 0, 0, 0, VERTEX); + addVertex(x1, y1, z1, -1, 0, 0, 1, 0, VERTEX); + addVertex(x1, y2, z1, -1, 0, 0, 1, 1, VERTEX); + addVertex(x1, y2, z2, -1, 0, 0, 0, 1, VERTEX);; + + // top face + addVertex(x1, y1, z2, 0, 1, 0, 0, 0, VERTEX); + addVertex(x2, y1, z2, 0, 1, 0, 1, 0, VERTEX); + addVertex(x2, y1, z1, 0, 1, 0, 1, 1, VERTEX); + addVertex(x1, y1, z1, 0, 1, 0, 0, 1, VERTEX); + + // bottom face + addVertex(x1, y2, z1, 0, -1, 0, 0, 0, VERTEX); + addVertex(x2, y2, z1, 0, -1, 0, 1, 0, VERTEX); + addVertex(x2, y2, z2, 0, -1, 0, 1, 1, VERTEX); + addVertex(x1, y2, z2, 0, -1, 0, 0, 1, VERTEX); + } + + if (stroke) { + addEdge(0, 1, true, false); + addEdge(1, 2, false, false); + addEdge(2, 3, false, false); + addEdge(3, 0, false, false); + + addEdge(0, 9, false, false); + addEdge(1, 8, false, false); + addEdge(2, 11, false, false); + addEdge(3, 10, false, false); + + addEdge( 8, 9, false, false); + addEdge( 9, 10, false, false); + addEdge(10, 11, false, false); + addEdge(11, 8, false, true); + } + } } // Holds tessellated data for fill, line and point geometry. @@ -7903,6 +8013,14 @@ public class PGraphicsOpenGL extends PGraphics { return fillVertexCount + lineVertexCount + pointVertexCount; } + public void applyMatrix(PMatrix tr) { + if (tr instanceof PMatrix2D) { + applyMatrix((PMatrix2D) tr); + } else if (tr instanceof PMatrix3D) { + applyMatrix((PMatrix3D) tr); + } + } + public void applyMatrix(PMatrix2D tr) { if (0 < fillVertexCount) { int index; diff --git a/java/libraries/opengl/src/processing/opengl/PShape3D.java b/java/libraries/opengl/src/processing/opengl/PShape3D.java index 20c3f4d0e..e99f60bd0 100644 --- a/java/libraries/opengl/src/processing/opengl/PShape3D.java +++ b/java/libraries/opengl/src/processing/opengl/PShape3D.java @@ -69,11 +69,15 @@ import java.util.Hashtable; * Other formats to consider: * AMF: http://en.wikipedia.org/wiki/Additive_Manufacturing_File_Format * STL: http://en.wikipedia.org/wiki/STL_(file_format) - * OFF: http://en.wikipedia.org/wiki/STL_(file_format) + * OFF: http://people.sc.fsu.edu/~jburkardt/data/off/off.html(file_format) * DXF: http://en.wikipedia.org/wiki/AutoCAD_DXF */ - public class PShape3D extends PShape { + static protected final int TRANSLATE = 0; + static protected final int ROTATE = 1; + static protected final int SCALE = 2; + static protected final int MATRIX = 3; + protected PGraphicsOpenGL pg; protected PGL pgl; protected PGL.Context context; // The context that created this shape. @@ -244,6 +248,15 @@ public class PShape3D extends PShape { protected int ellipseMode; protected int shapeMode; protected int imageMode; + + // ........................................................ + + // Geometric transformations + + protected PMatrix transform; + protected boolean cacheTransformations; + + public PShape3D(PApplet parent, int family) { pg = (PGraphicsOpenGL)parent.g; @@ -318,6 +331,13 @@ public class PShape3D extends PShape { normalZ = 1; normalMode = NORMAL_MODE_AUTO; + + cacheTransformations = pg.hintEnabled(ENABLE_TRANSFORM_CACHE); + + if (family == GROUP) { + // GROUP shapes are always marked as ended. + shapeEnded = true; + } } @@ -343,7 +363,9 @@ public class PShape3D extends PShape { child.updateRoot(root); root.tessellated = false; tessellated = false; - ((PShape3D)child).tessellated = false; + if (!cacheTransformations && ((PShape3D)child).hasMatrix()) { + setChildHasMatrix(true); + } } else { PGraphics.showWarning("Cannot add child shape to non-group shape."); } @@ -1333,6 +1355,9 @@ public class PShape3D extends PShape { // Geometric transformations + //------------------------------------------------------------------------------ + + // TODO: Remove center, add function to get center from point... public void center(float cx, float cy) { if (shapeEnded) { updateTesselation(); @@ -1347,7 +1372,7 @@ public class PShape3D extends PShape { float tx = cx - center.x; float ty = cy - center.y; - childHasMatrix(); + setChildHasMatrix(true); applyMatrix = true; super.translate(tx, ty); } else { @@ -1381,7 +1406,7 @@ public class PShape3D extends PShape { float ty = cy - center0.y; float tz = cz - center0.z; - childHasMatrix(); + setChildHasMatrix(true); applyMatrix = true; super.translate(tx, ty, tz); } else { @@ -1409,306 +1434,49 @@ public class PShape3D extends PShape { } return count; } + //------------------------------------------------------------------------------ + public void translate(float tx, float ty) { - if (shapeEnded) { - updateTesselation(); - - if (family == GROUP) { - childHasMatrix(); - applyMatrix = true; - super.translate(tx, ty); - } else { - checkMatrix(2); - matrix.reset(); - matrix.translate(tx, ty); - tess.applyMatrix((PMatrix2D) matrix); - - modified(); - if (0 < tess.fillVertexCount) { - modifiedFillVertices = true; - modifiedFillNormals = true; - } - if (0 < tess.lineVertexCount) { - modifiedLineVertices = true; - modifiedLineAttributes = true; - } - if (0 < tess.pointVertexCount) { - modifiedPointVertices = true; - modifiedPointNormals = true; - } - - // So the transformation is not applied again when drawing - applyMatrix = false; - } - } + transform(TRANSLATE, tx, ty); } public void translate(float tx, float ty, float tz) { - if (shapeEnded) { - updateTesselation(); - - if (family == GROUP) { - childHasMatrix(); - applyMatrix = true; - super.translate(tx, ty, tz); - } else { - checkMatrix(3); - matrix.reset(); - matrix.translate(tx, ty, tz); - tess.applyMatrix((PMatrix3D) matrix); - - modified(); - if (0 < tess.fillVertexCount) { - modifiedFillVertices = true; - modifiedFillNormals = true; - } - if (0 < tess.lineVertexCount) { - modifiedLineVertices = true; - modifiedLineAttributes = true; - } - if (0 < tess.pointVertexCount) { - modifiedPointVertices = true; - modifiedPointNormals = true; - } - - // So the transformation is not applied again when drawing - applyMatrix = false; - } - } + transform(TRANSLATE, tx, ty, tz); } public void rotate(float angle) { - if (shapeEnded) { - updateTesselation(); - - if (family == GROUP) { - childHasMatrix(); - applyMatrix = true; - super.rotate(angle); - } else { - checkMatrix(2); - matrix.reset(); - matrix.rotate(angle); - tess.applyMatrix((PMatrix2D) matrix); - - modified(); - if (0 < tess.fillVertexCount) { - modifiedFillVertices = true; - modifiedFillNormals = true; - } - if (0 < tess.lineVertexCount) { - modifiedLineVertices = true; - modifiedLineAttributes = true; - } - if (0 < tess.pointVertexCount) { - modifiedPointVertices = true; - modifiedPointNormals = true; - } - - // So the transformation is not applied again when drawing - applyMatrix = false; - } - } + transform(ROTATE, angle); } public void rotate(float angle, float v0, float v1, float v2) { - if (shapeEnded) { - updateTesselation(); - - if (family == GROUP) { - childHasMatrix(); - applyMatrix = true; - super.rotate(angle, v0, v1, v2); - } else { - checkMatrix(3); - matrix.reset(); - matrix.rotate(angle, v0, v1, v2); - tess.applyMatrix((PMatrix3D) matrix); - - modified(); - if (0 < tess.fillVertexCount) { - modifiedFillVertices = true; - modifiedFillNormals = true; - } - if (0 < tess.lineVertexCount) { - modifiedLineVertices = true; - modifiedLineAttributes = true; - } - if (0 < tess.pointVertexCount) { - modifiedPointVertices = true; - modifiedPointNormals = true; - } - - // So the transformation is not applied again when drawing - applyMatrix = false; - } - } + transform(ROTATE, v0, v1, v2); } public void scale(float s) { - if (shapeEnded) { - updateTesselation(); - - if (family == GROUP) { - childHasMatrix(); - applyMatrix = true; - super.scale(s); - } else { - checkMatrix(2); - matrix.reset(); - matrix.scale(s); - tess.applyMatrix((PMatrix2D) matrix); - - modified(); - if (0 < tess.fillVertexCount) { - modifiedFillVertices = true; - modifiedFillNormals = true; - } - if (0 < tess.lineVertexCount) { - modifiedLineVertices = true; - modifiedLineAttributes = true; - } - if (0 < tess.pointVertexCount) { - modifiedPointVertices = true; - modifiedPointNormals = true; - } - - // So the transformation is not applied again when drawing - applyMatrix = false; - } - } + transform(SCALE, s, s); } public void scale(float x, float y) { - if (shapeEnded) { - updateTesselation(); - - if (family == GROUP) { - childHasMatrix(); - applyMatrix = true; - super.scale(x, y); - } else { - checkMatrix(2); - matrix.reset(); - matrix.scale(x, y); - tess.applyMatrix((PMatrix2D) matrix); - - modified(); - if (0 < tess.fillVertexCount) { - modifiedFillVertices = true; - modifiedFillNormals = true; - } - if (0 < tess.lineVertexCount) { - modifiedLineVertices = true; - modifiedLineAttributes = true; - } - if (0 < tess.pointVertexCount) { - modifiedPointVertices = true; - modifiedPointNormals = true; - } - - // So the transformation is not applied again when drawing - applyMatrix = false; - } - } + transform(SCALE, x, y); } public void scale(float x, float y, float z) { - if (shapeEnded) { - updateTesselation(); - - if (family == GROUP) { - childHasMatrix(); - applyMatrix = true; - super.scale(x, y, z); - } else { - checkMatrix(3); - matrix.reset(); - matrix.scale(x, y, z); - tess.applyMatrix((PMatrix3D) matrix); - - modified(); - if (0 < tess.fillVertexCount) { - modifiedFillVertices = true; - modifiedFillNormals = true; - } - if (0 < tess.lineVertexCount) { - modifiedLineVertices = true; - modifiedLineAttributes = true; - } - if (0 < tess.pointVertexCount) { - modifiedPointVertices = true; - modifiedPointNormals = true; - } - - // So the transformation is not applied again when drawing - applyMatrix = false; - } - } + transform(SCALE, x, y, z); } - - - public void applyMatrix(PMatrix source) { - super.applyMatrix(source); - } - - - public void applyMatrix(PMatrix2D source) { - super.applyMatrix(source); - } public void applyMatrix(float n00, float n01, float n02, float n10, float n11, float n12) { - if (shapeEnded) { - updateTesselation(); - - if (family == GROUP) { - childHasMatrix(); - applyMatrix = true; - super.applyMatrix(n00, n01, n02, - n10, n11, n12); - } else { - checkMatrix(2); - matrix.reset(); - matrix.apply(n00, n01, n02, - n10, n11, n12); - tess.applyMatrix((PMatrix2D) matrix); - - modified(); - if (0 < tess.fillVertexCount) { - modifiedFillVertices = true; - modifiedFillNormals = true; - } - if (0 < tess.lineVertexCount) { - modifiedLineVertices = true; - modifiedLineAttributes = true; - } - if (0 < tess.pointVertexCount) { - modifiedPointVertices = true; - modifiedPointNormals = true; - } - - // So the transformation is not applied again when drawing - applyMatrix = false; - } - } - } - - - public void apply(PMatrix3D source) { - applyMatrix(source.m00, source.m01, source.m02, source.m03, - source.m10, source.m11, source.m12, source.m13, - source.m20, source.m21, source.m22, source.m23, - source.m30, source.m31, source.m32, source.m33); + transform(MATRIX, n00, n01, n02, + n10, n11, n12); } @@ -1716,65 +1484,194 @@ public class PShape3D extends PShape { float n10, float n11, float n12, float n13, float n20, float n21, float n22, float n23, float n30, float n31, float n32, float n33) { - if (shapeEnded) { - updateTesselation(); - - if (family == GROUP) { - childHasMatrix(); - applyMatrix = true; - super.applyMatrix(n00, n01, n02, n03, - n10, n11, n12, n13, - n20, n21, n22, n23, - n30, n31, n32, n33); - } else { - checkMatrix(3); - matrix.reset(); - matrix.apply(n00, n01, n02, n03, - n10, n11, n12, n13, - n20, n21, n22, n23, - n30, n31, n32, n33); - tess.applyMatrix((PMatrix3D) matrix); - - modified(); - if (0 < tess.fillVertexCount) { - modifiedFillVertices = true; - modifiedFillNormals = true; - } - if (0 < tess.lineVertexCount) { - modifiedLineVertices = true; - modifiedLineAttributes = true; - } - if (0 < tess.pointVertexCount) { - modifiedPointVertices = true; - modifiedPointNormals = true; - } - - // So the transformation is not applied again when drawing - applyMatrix = false; - } - } + transform(MATRIX, n00, n01, n02, n03, + n10, n11, n12, n13, + n20, n21, n22, n23, + n30, n31, n32, n33); } public void resetMatrix() { - // TODO - // What to do in the case of geometry shapes? - // In order to properly reset the transformation, - // we need to have the last matrix applied, calculate - // the inverse and apply on the tess object... - //checkMatrix(2); - //matrix.reset(); - } - - - protected void childHasMatrix() { - childHasMatrix = true; - if (parent != null) { - ((PShape3D)parent).childHasMatrix(); + if (!cacheTransformations && parent != null && hasMatrix()) { + ((PShape3D)parent).setChildHasMatrix(false); + } + + if (shapeEnded) { + updateTesselation(); + + if (family == GROUP) { + for (int i = 0; i < childCount; i++) { + PShape3D child = (PShape3D) children[i]; + child.resetMatrix(); + } + if (matrix != null) { + matrix.reset(); + applyMatrix = false; + } + } else { + if (cacheTransformations) { + boolean res = matrix.invert(); + if (res) { + applyMatrix(matrix); + matrix.reset(); + } else { + PGraphics.showWarning("The transformation matrix cannot be inverted"); + } + } else { + if (hasMatrix()) { + matrix.reset(); + applyMatrix = false; + } + } + } } } + protected void transform(int type, float... args) { + int dimensions; + if (type == ROTATE) { + dimensions = args.length == 1 ? 2 : 3; + } else if (type == MATRIX) { + dimensions = args.length == 6 ? 2 : 3; + } else { + dimensions = args.length; + } + transformImpl(type, dimensions, args); + } + + + protected void transformImpl(int type, int ncoords, float... args) { + if (shapeEnded) { + updateTesselation(); + + if (family == GROUP) { + if (cacheTransformations) { + // The transformation will be passed down to the child shapes + // which will in turn apply it to the tessellated vertices, + // so effectively becoming "cached" into the geometry itself. + for (int i = 0; i < childCount; i++) { + PShape3D child = (PShape3D) children[i]; + child.transformImpl(type, ncoords, args); + } + } else { + checkMatrix(ncoords); + calcTransform(type, ncoords, args); + applyMatrix = true; + } + } else { + checkMatrix(ncoords); + if (cacheTransformations) { + calcTransform(type, ncoords, args); + applyTransform(ncoords); + + // Setting the applyMatrix variable to false so + // that the transformation is not applied again + // in the draw() method. + applyMatrix = false; + + // TODO: check the vertex cache stuff... + modified(); + if (0 < tess.fillVertexCount) { + modifiedFillVertices = true; + modifiedFillNormals = true; + } + if (0 < tess.lineVertexCount) { + modifiedLineVertices = true; + modifiedLineAttributes = true; + } + if (0 < tess.pointVertexCount) { + modifiedPointVertices = true; + modifiedPointNormals = true; + } + } else { + // The transformation will be applied in draw(). + calcTransform(type, ncoords, args); + applyMatrix = true; + } + } + + if (!cacheTransformations && parent != null && hasMatrix()) { + // Making sure that the parent shapes (if any) know that + // this shape has a transformation matrix to be applied + // in draw(). + ((PShape3D)parent).setChildHasMatrix(true); + } + } + } + + + protected void calcTransform(int type, int dimensions, float... args) { + if (transform == null) { + if (dimensions == 2) { + transform = new PMatrix2D(); + } else { + transform = new PMatrix3D(); + } + } else { + transform.reset(); + } + + switch (type) { + case TRANSLATE: + if (dimensions == 3) { + transform.translate(args[0], args[1], args[2]); + } else { + transform.translate(args[0], args[1]); + } + break; + case ROTATE: + if (dimensions == 3) { + transform.rotate(args[0], args[1], args[2], args[3]); + } else { + transform.rotate(args[0]); + } + break; + case SCALE: + if (dimensions == 3) { + transform.scale(args[0], args[1], args[2]); + } else { + transform.scale(args[0], args[1]); + } + break; + case MATRIX: + if (dimensions == 3) { + transform.set(args[ 0], args[ 1], args[ 2], args[ 3], + args[ 4], args[ 5], args[ 6], args[ 7], + args[ 8], args[ 9], args[10], args[11], + args[12], args[13], args[14], args[15]); + } else { + transform.set(args[0], args[1], args[2], + args[3], args[4], args[5]); + } + break; + } + matrix.apply(transform); + } + + + protected void applyTransform(int dimensions) { + if (dimensions == 3) { + tess.applyMatrix((PMatrix3D) transform); + } else { + tess.applyMatrix((PMatrix2D) transform); + } + } + + + protected void setChildHasMatrix(boolean value) { + childHasMatrix = value; + if (parent != null) { + ((PShape3D)parent).setChildHasMatrix(value); + } + } + + + protected boolean hasMatrix() { + return matrix != null || childHasMatrix; + } + + /////////////////////////////////////////////////////////// // @@ -2466,12 +2363,7 @@ public class PShape3D extends PShape { child.tessellate(); } } else { - if (shapeEnded) { - if (tessellated) { - in.clearEdges(); - tess.clear(); - } - + if (shapeEnded && !tessellated) { tessellator.setInGeometry(in); tessellator.setTessGeometry(tess); tessellator.setFill(fill || texture != null); @@ -2534,8 +2426,9 @@ public class PShape3D extends PShape { // equivalent to use POLYGON with fill disabled. } - // Tessellated arrays are trimmed since they are expanded by doubling their old size, - // which might lead to arrays larger than the vertex counts. + // Tessellated arrays are trimmed since they are expanded + // by doubling their old size, which might lead to arrays + // larger than the vertex counts. tess.trim(); if (texture != null && parent != null) { @@ -2583,7 +2476,8 @@ public class PShape3D extends PShape { in.generateEllipse(ellipseMode, a, b, c, d, fill, fillColor, stroke, strokeColor, strokeWeight, - ambientColor, specularColor, emissiveColor, shininess); + ambientColor, specularColor, emissiveColor, + shininess); tessellator.tessellateTriangleFan(); } @@ -2595,7 +2489,6 @@ public class PShape3D extends PShape { protected void tessellateBox() { - // TODO: move to InGeometry float w, h, d; if (params.length == 1) { w = h = d = params[0]; @@ -2605,57 +2498,13 @@ public class PShape3D extends PShape { d = params[2]; } - //in.generateBox(w, h, d); - + in.generateBox(w, h, d, + fill, fillColor, + stroke, strokeColor, strokeWeight, + ambientColor, specularColor, emissiveColor, + shininess); - float x1 = -w/2f; float x2 = w/2f; - float y1 = -h/2f; float y2 = h/2f; - float z1 = -d/2f; float z2 = d/2f; - - // front - normal(0, 0, 1); - vertex(x1, y1, z1, 0, 0); - vertex(x2, y1, z1, 1, 0); - vertex(x2, y2, z1, 1, 1); - vertex(x1, y2, z1, 0, 1); - - // right - normal(1, 0, 0); - vertex(x2, y1, z1, 0, 0); - vertex(x2, y1, z2, 1, 0); - vertex(x2, y2, z2, 1, 1); - vertex(x2, y2, z1, 0, 1); - - // back - normal(0, 0, -1); - vertex(x2, y1, z2, 0, 0); - vertex(x1, y1, z2, 1, 0); - vertex(x1, y2, z2, 1, 1); - vertex(x2, y2, z2, 0, 1); - - // left - normal(-1, 0, 0); - vertex(x1, y1, z2, 0, 0); - vertex(x1, y1, z1, 1, 0); - vertex(x1, y2, z1, 1, 1); - vertex(x1, y2, z2, 0, 1); - - // top - normal(0, 1, 0); - vertex(x1, y1, z2, 0, 0); - vertex(x2, y1, z2, 1, 0); - vertex(x2, y1, z1, 1, 1); - vertex(x1, y1, z1, 0, 1); - - // bottom - normal(0, -1, 0); - vertex(x1, y2, z1, 0, 0); - vertex(x2, y2, z1, 1, 0); - vertex(x2, y2, z2, 1, 1); - vertex(x1, y2, z2, 0, 1); - - if (stroke) in.addQuadsEdges(); - tessellator.tessellateQuads(); + tessellator.tessellateQuads(); } @@ -3738,18 +3587,16 @@ public class PShape3D extends PShape { public void draw(PGraphics g) { - if (visible) { - + if (visible) { updateTesselation(); updateGeometry(); - if (matrix != null && applyMatrix) { + if (applyMatrix && matrix != null) { g.pushMatrix(); g.applyMatrix(matrix); } - if (family == GROUP) { - + if (family == GROUP) { boolean matrixBelow = childHasMatrix; boolean diffTexBelow = textures != null && 1 < textures.size(); @@ -3780,7 +3627,7 @@ public class PShape3D extends PShape { render(texture); } - if (matrix != null && applyMatrix) { + if (applyMatrix && matrix != null) { g.popMatrix(); } }