diff --git a/core/src/processing/core/PShape.java b/core/src/processing/core/PShape.java index 2ddcd4b44..3ba31654f 100644 --- a/core/src/processing/core/PShape.java +++ b/core/src/processing/core/PShape.java @@ -732,6 +732,119 @@ public class PShape implements PConstants { } } + + + + + public PShape copy(PGraphics g) { + PShape res = null; + if (family == GROUP) { + res = g.createShape(GROUP); + copyGroup(g, res); + } else if (family == PRIMITIVE) { + res = g.createShape(kind, params); + copyPrimitive(res); + } else if (family == GEOMETRY) { + res = g.createShape(kind); + copyGeometry(res); + } else if (family == PATH) { + res = g.createShape(PATH); + copyPath(res); + } + return res; + } + + + protected void copyGroup(PGraphics g, PShape s) { + if (matrix != null) { + s.applyMatrix(matrix); + } + copyStyles(s); + copyImage(s); + for (int i = 0; i < childCount; i++) { + PShape c = children[i].copy(g); + s.addChild(c); + } + } + + + protected void copyPrimitive(PShape s) { + if (matrix != null) { + s.applyMatrix(matrix); + } + copyStyles(s); + copyImage(s); + } + + protected void copyGeometry(PShape s) { + if (matrix != null) { + s.applyMatrix(matrix); + } + copyStyles(s); + copyImage(s); + + if (style) { + for (int i = 0; i < vertexCount; i++) { + float[] vert = vertices[i]; +// s.ambient(vert[AR] * 255, vert[AG] * 255, vert[AB] * 255); +// s.specular(vert[SPR] * 255, vert[SPG] * 255, vert[SPB] * 255); +// s.emissive(vert[ER] * 255, vert[EG] * 255, vert[EB] * 255); +// s.shininess(vert[SHINE]); + + s.normal(vert[NX], vert[NY], vert[NZ]); + s.vertex(vert[X], vert[Y], vert[Z], vert[U], vert[V]); + } + } else { + for (int i = 0; i < vertexCount; i++) { + float[] vert = vertices[i]; + if (vert[PGraphics.Z] == 0) { + s.vertex(vert[X], vert[Y]); + } else { + s.vertex(vert[X], vert[Y], vert[Z]); + } + } + } + + s.end(); + } + + protected void copyPath(PShape s) { + if (matrix != null) { + s.applyMatrix(matrix); + } + copyStyles(s); + copyImage(s); + s.close = close; + s.setPath(vertexCount, vertices, vertexCodeCount, vertexCodes); + + } + + protected void copyStyles(PShape s) { + if (stroke) { + s.stroke = true; + s.strokeColor = strokeColor; + s.strokeWeight = strokeWeight; + s.strokeCap = strokeCap; + s.strokeJoin = strokeJoin; + } else { + s.stroke = false; + } + + if (fill) { + s.fill = true; + s.fillColor = fillColor; + } else { + s.fill = false; + } + } + + protected void copyImage(PShape s) { + if (image != null) { + s.texture(image); + } + } + + /** * Called by the following (the shape() command adds the g) @@ -1017,8 +1130,8 @@ public class PShape implements PConstants { } g.endShape(close ? CLOSE : OPEN); } - - + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . @@ -1228,42 +1341,27 @@ public class PShape implements PConstants { } - public void setPath(float[][] coords) { - setPath(coords, null); + public void setPath(int vcount, float[][] verts) { + setPath(vcount, verts, 0, null); } - public void setPath(float[][] coords, int[] codes) { - if (coords == null || coords.length == 0) return; - - if (codes == null || codes.length == 0) { - vertexCodeCount = 0; - } else { - if (codes.length != coords.length) { - PGraphics.showWarning("Wrong number of vertex codes"); - return; - } - vertexCodeCount = codes.length; - } + public void setPath(int vcount, float[][] verts, int ccount, int[] codes) { + if (verts == null || verts.length < vcount) return; + if (0 < ccount && (codes == null || codes.length < ccount)) return; - int ncoords = coords[0].length; - - if (vertices == null || - vertices.length != coords.length || - vertices[0].length != ncoords) { - vertices = new float[coords.length][ncoords]; - } - - for (int i = 0; i < coords.length; i++) { - PApplet.arrayCopy(coords[i], vertices[i]); - } - + int ndim = verts[0].length; + vertexCount = vcount; + vertices = new float[vertexCount][ndim]; + for (int i = 0; i < vertexCount; i++) { + PApplet.arrayCopy(verts[i], vertices[i]); + } + + vertexCodeCount = ccount; if (0 < vertexCodeCount) { - if (vertexCodes == null || vertexCodes.length != vertexCodeCount) { - vertexCodes = new int[vertexCodeCount]; - } - PApplet.arrayCopy(codes, vertexCodes); - } + vertexCodes = new int[vertexCodeCount]; + PApplet.arrayCopy(codes, vertexCodes, vertexCodeCount); + } } diff --git a/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java b/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java index 2a19e061f..283236250 100644 --- a/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java +++ b/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java @@ -1950,6 +1950,8 @@ public class PGraphicsOpenGL extends PGraphics { PShape3D shape = null; if (type == PShape.GROUP) { shape = new PShape3D(parent, PShape.GROUP); + } else if (type == PShape.PATH) { + shape = new PShape3D(parent, PShape.PATH); } else if (type == POINTS) { shape = new PShape3D(parent, PShape.GEOMETRY); shape.setKind(POINTS); diff --git a/java/libraries/opengl/src/processing/opengl/PShape3D.java b/java/libraries/opengl/src/processing/opengl/PShape3D.java index 8b7f896a3..b68788eea 100644 --- a/java/libraries/opengl/src/processing/opengl/PShape3D.java +++ b/java/libraries/opengl/src/processing/opengl/PShape3D.java @@ -474,7 +474,7 @@ public class PShape3D extends PShape { PVector max = new PVector(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY); if (shapeEnded) { getVertexMin(min); - getVertexMin(max); + getVertexMax(max); } width = max.x - min.x; return width; @@ -486,7 +486,7 @@ public class PShape3D extends PShape { PVector max = new PVector(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY); if (shapeEnded) { getVertexMin(min); - getVertexMin(max); + getVertexMax(max); } width = max.y - min.y; return height; @@ -498,7 +498,7 @@ public class PShape3D extends PShape { PVector max = new PVector(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY); if (shapeEnded) { getVertexMin(min); - getVertexMin(max); + getVertexMax(max); } width = max.z - min.z; return depth; @@ -532,7 +532,14 @@ public class PShape3D extends PShape { if (haveLines) tessGeo.getLineVertexMin(min, firstLineVertex, lastLineVertex); if (havePoints) tessGeo.getPointVertexMin(min, firstPointVertex, lastPointVertex); } else { - inGeo.getVertexMin(min); + if (family == GEOMETRY) { + inGeo.getVertexMin(min); + } else if (family == PRIMITIVE) { + + + } else if (family == PATH) { + + } } } } @@ -550,7 +557,14 @@ public class PShape3D extends PShape { if (haveLines) tessGeo.getLineVertexMax(max, firstLineVertex, lastLineVertex); if (havePoints) tessGeo.getPointVertexMax(max, firstPointVertex, lastPointVertex); } else { - inGeo.getVertexMax(max); + if (family == GEOMETRY) { + inGeo.getVertexMax(max); + } else if (family == PRIMITIVE) { + + + } else if (family == PATH) { + + } } } } @@ -568,7 +582,13 @@ public class PShape3D extends PShape { if (haveLines) count += tessGeo.getLineVertexSum(sum, firstLineVertex, lastLineVertex); if (havePoints) count += tessGeo.getPointVertexSum(sum, firstPointVertex, lastPointVertex); } else { - count += inGeo.getVertexSum(sum); + if (family == GEOMETRY) { + count += inGeo.getVertexSum(sum); + } else if (family == PRIMITIVE) { + + } else if (family == PATH) { + + } } } return count; @@ -844,29 +864,13 @@ public class PShape3D extends PShape { } - public void setPath(float[][] coords) { - setPath(coords, null, OPEN); - } - - - public void setPath(float[][] coords, int mode) { - setPath(coords, null, mode); - } - - - public void setPath(float[][] coords, int[] codes) { - setPath(coords, codes, OPEN); - } - - - public void setPath(float[][] coords, int[] codes, int mode) { + public void setPath(int vcount, float[][] verts, int ccount, int[] codes) { if (family != PATH) { PGraphics.showWarning("Vertex coordinates and codes can only be set to PATH shapes"); return; } - super.setPath(coords, codes); - isClosed = mode == CLOSE; + super.setPath(vcount, verts, ccount, codes); root.tessellated = false; tessellated = false; shapeEnded = true; @@ -1047,7 +1051,7 @@ public class PShape3D extends PShape { protected void updateFillColor() { if (shapeEnded && tessellated && haveFill && texture == null) { Arrays.fill(inGeo.colors, 0, inGeo.vertexCount, PGL.javaToNativeARGB(fillColor)); - Arrays.fill(tessGeo.fillColors, firstFillVertex, lastFillVertex, PGL.javaToNativeARGB(fillColor)); + Arrays.fill(tessGeo.fillColors, firstFillVertex, lastFillVertex + 1, PGL.javaToNativeARGB(fillColor)); root.setModifiedFillColors(firstFillVertex, lastFillVertex); } } @@ -1161,11 +1165,11 @@ public class PShape3D extends PShape { if (shapeEnded && tessellated && (haveLines || havePoints)) { Arrays.fill(inGeo.scolors, 0, inGeo.vertexCount, PGL.javaToNativeARGB(strokeColor)); if (haveLines) { - Arrays.fill(tessGeo.lineColors, firstLineVertex, lastLineVertex, PGL.javaToNativeARGB(strokeColor)); + Arrays.fill(tessGeo.lineColors, firstLineVertex, lastLineVertex + 1, PGL.javaToNativeARGB(strokeColor)); root.setModifiedLineColors(firstLineVertex, lastLineVertex); } if (havePoints) { - Arrays.fill(tessGeo.pointColors, firstPointVertex, lastPointVertex, PGL.javaToNativeARGB(strokeColor)); + Arrays.fill(tessGeo.pointColors, firstPointVertex, lastPointVertex + 1, PGL.javaToNativeARGB(strokeColor)); root.setModifiedPointColors(firstPointVertex, lastPointVertex); } } @@ -1279,7 +1283,7 @@ public class PShape3D extends PShape { protected void updateTintColor() { if (shapeEnded && tessellated && haveFill && texture != null) { Arrays.fill(inGeo.colors, 0, inGeo.vertexCount, PGL.javaToNativeARGB(tintColor)); - Arrays.fill(tessGeo.fillColors, firstFillVertex, lastFillVertex, PGL.javaToNativeARGB(tintColor)); + Arrays.fill(tessGeo.fillColors, firstFillVertex, lastFillVertex + 1, PGL.javaToNativeARGB(tintColor)); root.setModifiedFillColors(firstFillVertex, lastFillVertex); } } @@ -1338,7 +1342,7 @@ public class PShape3D extends PShape { protected void updateAmbientColor() { if (shapeEnded && tessellated && haveFill) { Arrays.fill(inGeo.ambient, 0, inGeo.vertexCount, PGL.javaToNativeARGB(ambientColor)); - Arrays.fill(tessGeo.fillAmbient, firstFillVertex, lastFillVertex, PGL.javaToNativeARGB(ambientColor)); + Arrays.fill(tessGeo.fillAmbient, firstFillVertex, lastFillVertex = 1, PGL.javaToNativeARGB(ambientColor)); root.setModifiedFillAmbient(firstFillVertex, lastFillVertex); } } @@ -1397,7 +1401,7 @@ public class PShape3D extends PShape { protected void updateSpecularColor() { if (shapeEnded && tessellated && haveFill) { Arrays.fill(inGeo.specular, 0, inGeo.vertexCount, PGL.javaToNativeARGB(specularColor)); - Arrays.fill(tessGeo.fillSpecular, firstFillVertex, lastFillVertex, PGL.javaToNativeARGB(specularColor)); + Arrays.fill(tessGeo.fillSpecular, firstFillVertex, lastFillVertex + 1, PGL.javaToNativeARGB(specularColor)); root.setModifiedFillSpecular(firstFillVertex, lastFillVertex); } } @@ -1456,7 +1460,7 @@ public class PShape3D extends PShape { protected void updateEmissiveColor() { if (shapeEnded && tessellated && 0 < tessGeo.fillVertexCount) { Arrays.fill(inGeo.emissive, 0, inGeo.vertexCount, PGL.javaToNativeARGB(emissiveColor)); - Arrays.fill(tessGeo.fillEmissive, firstFillVertex, lastFillVertex, PGL.javaToNativeARGB(emissiveColor)); + Arrays.fill(tessGeo.fillEmissive, firstFillVertex, lastFillVertex + 1, PGL.javaToNativeARGB(emissiveColor)); root.setModifiedFillEmissive(firstFillVertex, lastFillVertex); } } @@ -1483,7 +1487,7 @@ public class PShape3D extends PShape { protected void updateShininessFactor() { if (shapeEnded && tessellated && haveFill) { Arrays.fill(inGeo.shininess, 0, inGeo.vertexCount, shininess); - Arrays.fill(tessGeo.fillShininess, firstFillVertex, lastFillVertex, shininess); + Arrays.fill(tessGeo.fillShininess, firstFillVertex, lastFillVertex + 1, shininess); root.setModifiedFillShininess(firstFillVertex, lastFillVertex); } } @@ -2403,7 +2407,7 @@ public class PShape3D extends PShape { return tess; } - + /////////////////////////////////////////////////////////// @@ -2740,6 +2744,7 @@ public class PShape3D extends PShape { rounded = true; } + rectMode = CORNER; inGeo.setMaterial(fillColor, strokeColor, strokeWeight, ambientColor, specularColor, emissiveColor, shininess); inGeo.setNormal(normalX, normalY, normalZ); @@ -2766,7 +2771,8 @@ public class PShape3D extends PShape { c = params[2]; d = params[3]; } - + + ellipseMode = CORNER; inGeo.setMaterial(fillColor, strokeColor, strokeWeight, ambientColor, specularColor, emissiveColor, shininess); inGeo.setNormal(normalX, normalY, normalZ); @@ -2788,6 +2794,7 @@ public class PShape3D extends PShape { stop = params[5]; } + ellipseMode = CORNER; inGeo.setMaterial(fillColor, strokeColor, strokeWeight, ambientColor, specularColor, emissiveColor, shininess); inGeo.setNormal(normalX, normalY, normalZ); @@ -2855,6 +2862,7 @@ public class PShape3D extends PShape { int code = VERTEX; if (vertices[0].length == 2) { // tessellating a 2D path + for (int j = 0; j < vertexCodeCount; j++) { switch (vertexCodes[j]) { @@ -2865,22 +2873,22 @@ public class PShape3D extends PShape { case QUAD_BEZIER_VERTEX: inGeo.addQuadraticVertex(vertices[index+0][X], vertices[index+0][Y], 0, - vertices[index+1][X], vertices[index+1][Y], 0, - fill, stroke, bezierDetail, code); + vertices[index+1][X], vertices[index+1][Y], 0, + fill, stroke, bezierDetail, code); index += 2; break; case BEZIER_VERTEX: inGeo.addBezierVertex(vertices[index+0][X], vertices[index+0][Y], 0, - vertices[index+1][X], vertices[index+1][Y], 0, - vertices[index+2][X], vertices[index+2][Y], 0, - fill, stroke, bezierDetail, code); + vertices[index+1][X], vertices[index+1][Y], 0, + vertices[index+2][X], vertices[index+2][Y], 0, + fill, stroke, bezierDetail, code); index += 3; break; case CURVE_VERTEX: inGeo.addCurveVertex(vertices[index][X], vertices[index][Y], 0, - fill, stroke, curveDetail, code); + fill, stroke, curveDetail, code); index++; case BREAK: @@ -2902,23 +2910,23 @@ public class PShape3D extends PShape { case QUAD_BEZIER_VERTEX: inGeo.addQuadraticVertex(vertices[index+0][X], vertices[index+0][Y], vertices[index+0][Z], - vertices[index+1][X], vertices[index+1][Y], vertices[index+0][Z], - fill, stroke, bezierDetail, code); + vertices[index+1][X], vertices[index+1][Y], vertices[index+0][Z], + fill, stroke, bezierDetail, code); index += 2; break; case BEZIER_VERTEX: inGeo.addBezierVertex(vertices[index+0][X], vertices[index+0][Y], vertices[index+0][Z], - vertices[index+1][X], vertices[index+1][Y], vertices[index+1][Z], - vertices[index+2][X], vertices[index+2][Y], vertices[index+2][Z], - fill, stroke, bezierDetail, code); + vertices[index+1][X], vertices[index+1][Y], vertices[index+1][Z], + vertices[index+2][X], vertices[index+2][Y], vertices[index+2][Z], + fill, stroke, bezierDetail, code); index += 3; break; case CURVE_VERTEX: inGeo.addCurveVertex(vertices[index][X], vertices[index][Y], vertices[index][Z], - fill, stroke, curveDetail, code); + fill, stroke, curveDetail, code); index++; case BREAK: @@ -3882,6 +3890,43 @@ public class PShape3D extends PShape { } + /////////////////////////////////////////////////////////// + + // + + // Style handling + + + // Applies the styles of g. + protected void styles(PGraphics g) { + if (stroke) { + stroke(g.strokeColor); + strokeWeight(g.strokeWeight); + + // These two don't to nothing probably: + strokeCap(g.strokeCap); + strokeJoin(g.strokeJoin); + } else { + noStroke(); + } + + if (fill) { + fill(g.fillColor); + } else { + noFill(); + } + + ambient(g.ambientColor); + specular(g.specularColor); + emissive(g.emissiveColor); + shininess(g.shininess); + + // What about other style parameters, such as rectMode, etc? + // These should force a tessellation update, same as stroke + // cap and weight... right? + } + + /////////////////////////////////////////////////////////// // @@ -3896,25 +3941,23 @@ public class PShape3D extends PShape { public void draw(PGraphics g) { if (visible) { + pre(g); + updateTessellation(); updateGeometry(); - + if (family == GROUP) { - if (textures != null && 1 < textures.size()) { - // Some child shape below this group has a non-null matrix - // transformation assigned to it, so the group cannot - // be drawn in a single render call. - // Or, some child shapes below this group use different + if ((textures != null && 1 < textures.size()) || + pg.hintEnabled(ENABLE_ACCURATE_2D)) { + // Some child shapes below this group use different // texture maps, so they cannot rendered in a single call - // either. + // either. + // Or accurate 2D mode is enabled, which forces each + // shape to be rendered separately. for (int i = 0; i < childCount; i++) { ((PShape3D) children[i]).draw(g); } - } else { - // None of the child shapes below this group has a matrix - // transformation applied to them, so we can render everything - // in a single block. - // And all have the same texture applied to them. + } else { PImage tex = null; if (textures != null && textures.size() == 1) { tex = (PImage)textures.toArray()[0]; @@ -3925,10 +3968,23 @@ public class PShape3D extends PShape { } else { render((PGraphicsOpenGL)g, texture); } + + post(g); } } + protected void pre(PGraphics g) { + if (!style) { + styles(g); + } + } + + + public void post(PGraphics g) { + } + + // Render the geometry stored in the root shape as VBOs, for the vertices // corresponding to this shape. Sometimes we can have root == this. protected void render(PGraphicsOpenGL g, PImage texture) {