diff --git a/java/libraries/opengl/src/processing/opengl/PGL.java b/java/libraries/opengl/src/processing/opengl/PGL.java index 47a38967b..81e917d70 100644 --- a/java/libraries/opengl/src/processing/opengl/PGL.java +++ b/java/libraries/opengl/src/processing/opengl/PGL.java @@ -114,7 +114,7 @@ public class PGL { /** Minimum stroke weight needed to apply the full path stroking * algorithm that properly generates caps and joing. */ - public static final float MIN_CAPS_JOINS_WEIGHT = 2.1f; + public static final float MIN_CAPS_JOINS_WEIGHT = 1.5f; /** Minimum array size to use arrayCopy method(). **/ static protected final int MIN_ARRAYCOPY_SIZE = 2; diff --git a/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java b/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java index 8a2d606b9..fd8baf7af 100644 --- a/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java +++ b/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java @@ -9823,9 +9823,14 @@ public class PGraphicsOpenGL extends PGraphics { int i0 = first + 2 * ln + 0; int i1 = first + 2 * ln + 1; path.moveTo(in.vertices[4 * i0 + 0], in.vertices[4 * i0 + 1]); - path.lineTo(in.vertices[4 * i1 + 0], in.vertices[4 * i1 + 1]); + path.lineTo(in.vertices[4 * i1 + 0], in.vertices[4 * i1 + 1]); + if (tess.renderMode == RETAINED) { + // The input vertices cannot the tessellated geometry + in.tessMap.addFillIndex(i0, -1); + in.tessMap.addFillIndex(i1, -1); + } } - tessellateLinePath(path); + tessellateLinePath(path, false); } } } @@ -9877,11 +9882,17 @@ public class PGraphicsOpenGL extends PGraphics { int first = in.firstVertex; LinePath path = new LinePath(LinePath.WIND_NON_ZERO); path.moveTo(in.vertices[4 * first + 0], in.vertices[4 * first + 1]); + if (tess.renderMode == RETAINED) { + in.tessMap.addFillIndex(first, -1); + } for (int ln = 0; ln < lineCount; ln++) { int i1 = first + ln + 1; path.lineTo(in.vertices[4 * i1 + 0], in.vertices[4 * i1 + 1]); + if (tess.renderMode == RETAINED) { + in.tessMap.addFillIndex(i1, -1); + } } - tessellateLinePath(path); + tessellateLinePath(path, false); } } } @@ -9935,19 +9946,25 @@ public class PGraphicsOpenGL extends PGraphics { int first = in.firstVertex; LinePath path = new LinePath(LinePath.WIND_NON_ZERO); path.moveTo(in.vertices[4 * first + 0], in.vertices[4 * first + 1]); + if (tess.renderMode == RETAINED) { + in.tessMap.addFillIndex(first, -1); + } for (int ln = 0; ln < lineCount - 1; ln++) { int i1 = first + ln + 1; path.lineTo(in.vertices[4 * i1 + 0], in.vertices[4 * i1 + 1]); + if (tess.renderMode == RETAINED) { + in.tessMap.addFillIndex(i1, -1); + } } path.closePath(); - tessellateLinePath(path); + tessellateLinePath(path, false); } } } } - void tessellateEdges() { + void tessellateEdges(boolean haveFill) { if (stroke) { int nInVert = in.getNumLineVertices(); int nInInd = in.getNumLineIndices(); @@ -9971,7 +9988,7 @@ public class PGraphicsOpenGL extends PGraphics { if (strokeWeight < PGL.MIN_CAPS_JOINS_WEIGHT) { // no caps, edges tess.fillVertexCheck(nInVert); tess.fillIndexCheck(nInInd); - int index = in.renderMode == RETAINED ? tess.fillIndexCache.addNew() : tess.fillIndexCache.getLast(); + int index = in.renderMode == RETAINED && !haveFill ? tess.fillIndexCache.addNew() : tess.fillIndexCache.getLast(); firstFillIndexCache = index; for (int i = in.firstEdge; i <= in.lastEdge; i++) { int[] edge = in.edges[i]; @@ -10005,9 +10022,13 @@ public class PGraphicsOpenGL extends PGraphics { path.lineTo(in.vertices[4 * i1 + 0], in.vertices[4 * i1 + 1]); path.closePath(); break; - } + } + if (tess.renderMode == RETAINED) { + in.tessMap.addFillIndex(i0, -1); + in.tessMap.addFillIndex(i1, -1); + } } - tessellateLinePath(path); + tessellateLinePath(path, haveFill); } } } @@ -10145,7 +10166,7 @@ public class PGraphicsOpenGL extends PGraphics { } partitionRawIndices(); } - tessellateEdges(); + tessellateEdges(fill && 3 <= nInVert); } void tessellateTriangles(int[] indices) { @@ -10156,7 +10177,7 @@ public class PGraphicsOpenGL extends PGraphics { PApplet.arrayCopy(indices, rawIndices, nInInd); partitionRawIndices(); } - tessellateEdges(); + tessellateEdges(fill && 3 <= nInVert); } void tessellateTriangleFan() { @@ -10172,7 +10193,7 @@ public class PGraphicsOpenGL extends PGraphics { } partitionRawIndices(); } - tessellateEdges(); + tessellateEdges(fill && 3 <= nInVert); } void tessellateTriangleStrip() { @@ -10193,7 +10214,7 @@ public class PGraphicsOpenGL extends PGraphics { } partitionRawIndices(); } - tessellateEdges(); + tessellateEdges(fill && 3 <= nInVert); } void tessellateQuads() { @@ -10219,7 +10240,7 @@ public class PGraphicsOpenGL extends PGraphics { } partitionRawIndices(); } - tessellateEdges(); + tessellateEdges(fill && 4 <= nInVert); } void tessellateQuadStrip() { @@ -10245,7 +10266,7 @@ public class PGraphicsOpenGL extends PGraphics { } partitionRawIndices(); } - tessellateEdges(); + tessellateEdges(fill && 4 <= nInVert); } // Uses the raw indices to partition the geometry into contiguous @@ -10387,7 +10408,7 @@ public class PGraphicsOpenGL extends PGraphics { if (fill && 3 <= nInVert) { firstFillIndexCache = -1; - callback.calcNormals = calcNormals; + callback.init(in.renderMode == RETAINED, calcNormals); gluTess.beginPolygon(); @@ -10435,8 +10456,8 @@ public class PGraphicsOpenGL extends PGraphics { fa, fr, fg, fb, in.normals [3 * i + 0], in.normals [3 * i + 1], in.normals [3 * i + 2], in.texcoords[2 * i + 0], in.texcoords[2 * i + 1], - aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, - in.shininess[i], i, 1.0 }; + aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, in.shininess[i], + i, 1.0 }; gluTess.addVertex(vertex); } @@ -10445,15 +10466,14 @@ public class PGraphicsOpenGL extends PGraphics { gluTess.endPolygon(); } - tessellateEdges(); + tessellateEdges(fill && 3 <= nInVert); } // Tessellates the path given as parameter. This will work only in 2D. // Based on the opengl stroke hack described here: // http://wiki.processing.org/w/Stroke_attributes_in_OpenGL - public void tessellateLinePath(LinePath path) { - //firstFillIndexCache = -1; - callback.calcNormals = true; + public void tessellateLinePath(LinePath path, boolean haveFill) { + callback.init(in.renderMode == RETAINED && !haveFill, true); int cap = strokeCap == ROUND ? LinePath.CAP_ROUND : strokeCap == PROJECT ? LinePath.CAP_SQUARE : @@ -10503,8 +10523,8 @@ public class PGraphicsOpenGL extends PGraphics { sa, sr, sg, sb, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1.0 }; // what about i!!!!!!!!!!! + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0.0 }; gluTess.addVertex(vertex); @@ -10539,9 +10559,19 @@ public class PGraphicsOpenGL extends PGraphics { int vertCount; int primitive; - public void begin(int type) { + public void init(boolean add, boolean calcn) { + calcNormals = calcn; cache = tess.fillIndexCache; - cacheIndex = in.renderMode == RETAINED ? cache.addNew() : cache.getLast(); + + if (add) { + cache.addNew(); + } + } + + public void begin(int type) { + + //cacheIndex = in.renderMode == RETAINED ? cache.addNew() : cache.getLast(); + cacheIndex = cache.getLast(); if (cacheIndex < firstFillIndexCache || firstFillIndexCache == -1) { firstFillIndexCache = cacheIndex; } diff --git a/java/libraries/opengl/src/processing/opengl/PShape3D.java b/java/libraries/opengl/src/processing/opengl/PShape3D.java index 148985b0d..9e1310eae 100644 --- a/java/libraries/opengl/src/processing/opengl/PShape3D.java +++ b/java/libraries/opengl/src/processing/opengl/PShape3D.java @@ -164,6 +164,7 @@ public class PShape3D extends PShape { protected boolean tessellated; protected boolean needBufferInit; + protected boolean forceTessellation; protected boolean isSolid; protected boolean isClosed; @@ -1792,7 +1793,7 @@ public class PShape3D extends PShape { int[] indices; int[] indices1; float[] vertices; - float[] attribs; + float[] attribs; if (havePoints) { indices = inGeo.tessMap.pointIndices[index]; @@ -1830,7 +1831,7 @@ public class PShape3D extends PShape { vertices = tessGeo.fillVertices; if (-1 < inGeo.tessMap.firstFillIndex) { // 1-1 mapping, only need to offset the input index - int tessIdx = inGeo.tessMap.firstFillIndex + index; + int tessIdx = inGeo.tessMap.firstFillIndex + index; vertices[4 * tessIdx + 0] = x; vertices[4 * tessIdx + 1] = y; vertices[4 * tessIdx + 2] = z; @@ -1855,21 +1856,26 @@ public class PShape3D extends PShape { // = xt + w2 * (x2' - x2) // This explains the calculations below: int tessIdx = indices[i]; - float weight = weights[i]; - float tx0 = vertices[4 * tessIdx + 0]; - float ty0 = vertices[4 * tessIdx + 1]; - float tz0 = vertices[4 * tessIdx + 2]; - vertices[4 * tessIdx + 0] = tx0 + weight * (x - x0); - vertices[4 * tessIdx + 1] = ty0 + weight * (y - y0); - vertices[4 * tessIdx + 2] = tz0 + weight * (z - z0); - root.setModifiedFillVertices(tessIdx, tessIdx); + if (-1 < tessIdx) { + float weight = weights[i]; + float tx0 = vertices[4 * tessIdx + 0]; + float ty0 = vertices[4 * tessIdx + 1]; + float tz0 = vertices[4 * tessIdx + 2]; + vertices[4 * tessIdx + 0] = tx0 + weight * (x - x0); + vertices[4 * tessIdx + 1] = ty0 + weight * (y - y0); + vertices[4 * tessIdx + 2] = tz0 + weight * (z - z0); + root.setModifiedFillVertices(tessIdx, tessIdx); + } else { + root.forceTessellation = true; + break; + } } } } - + inGeo.vertices[4 * index + 0] = x; inGeo.vertices[4 * index + 1] = y; - inGeo.vertices[4 * index + 2] = z; + inGeo.vertices[4 * index + 2] = z; } @@ -1927,26 +1933,28 @@ public class PShape3D extends PShape { float[] weights = inGeo.tessMap.fillWeights[index]; for (int i = 0; i < indices.length; i++) { int tessIdx = indices[i]; - float weight = weights[i]; - float tnx0 = normals[3 * tessIdx + 0]; - float tny0 = normals[3 * tessIdx + 1]; - float tnz0 = normals[3 * tessIdx + 2]; - float tnx = tnx0 + weight * (nx - nx0); - float tny = tny0 + weight * (ny - ny0); - float tnz = tnz0 + weight * (nz - nz0); - - // Making sure that the new normal vector is indeed - // normalized. - float sum = tnx * tnx + tny * tny + tnz * tnz; - float len = PApplet.sqrt(sum); - tnx /= len; - tny /= len; - tnz /= len; - - normals[3 * tessIdx + 0] = tnx; - normals[3 * tessIdx + 1] = tny; - normals[3 * tessIdx + 2] = tnz; - root.setModifiedFillNormals(tessIdx, tessIdx); + if (-1 < tessIdx) { + float weight = weights[i]; + float tnx0 = normals[3 * tessIdx + 0]; + float tny0 = normals[3 * tessIdx + 1]; + float tnz0 = normals[3 * tessIdx + 2]; + float tnx = tnx0 + weight * (nx - nx0); + float tny = tny0 + weight * (ny - ny0); + float tnz = tnz0 + weight * (nz - nz0); + + // Making sure that the new normal vector is indeed + // normalized. + float sum = tnx * tnx + tny * tny + tnz * tnz; + float len = PApplet.sqrt(sum); + tnx /= len; + tny /= len; + tnz /= len; + + normals[3 * tessIdx + 0] = tnx; + normals[3 * tessIdx + 1] = tny; + normals[3 * tessIdx + 2] = tnz; + root.setModifiedFillNormals(tessIdx, tessIdx); + } } } } @@ -1989,14 +1997,16 @@ public class PShape3D extends PShape { float[] weights = inGeo.tessMap.fillWeights[index]; for (int i = 0; i < indices.length; i++) { int tessIdx = indices[i]; - float weight = weights[i]; - float tu0 = texcoords[2 * tessIdx + 0]; - float tv0 = texcoords[2 * tessIdx + 1]; - float tu = tu0 + weight * (u - u0); - float tv = tv0 + weight * (v - v0); - texcoords[2 * tessIdx + 0] = tu; - texcoords[2 * tessIdx + 1] = tv; - root.setModifiedFillTexcoords(tessIdx, tessIdx); + if (-1 < tessIdx) { + float weight = weights[i]; + float tu0 = texcoords[2 * tessIdx + 0]; + float tv0 = texcoords[2 * tessIdx + 1]; + float tu = tu0 + weight * (u - u0); + float tv = tv0 + weight * (v - v0); + texcoords[2 * tessIdx + 0] = tu; + texcoords[2 * tessIdx + 1] = tv; + root.setModifiedFillTexcoords(tessIdx, tessIdx); + } } } } @@ -2031,7 +2041,10 @@ public class PShape3D extends PShape { int fill0 = inGeo.colors[index]; setColorARGB(colors, fill, fill0, indices, weights); for (int i = 0; i < indices.length; i++) { - root.setModifiedFillColors(indices[i], indices[i]); + int tessIdx = indices[i]; + if (-1 < tessIdx) { + root.setModifiedFillColors(tessIdx, indices[i]); + } } } } @@ -2156,7 +2169,10 @@ public class PShape3D extends PShape { int ambient0 = inGeo.ambient[index]; setColorRGB(colors, ambient, ambient0, indices, weights); for (int i = 0; i < indices.length; i++) { - root.setModifiedFillAmbient(indices[i], indices[i]); + int tessIdx = indices[i]; + if (-1 < tessIdx) { + root.setModifiedFillAmbient(tessIdx, indices[i]); + } } } } @@ -2189,7 +2205,10 @@ public class PShape3D extends PShape { int specular0 = inGeo.specular[index]; setColorRGB(colors, specular, specular0, indices, weights); for (int i = 0; i < indices.length; i++) { - root.setModifiedFillSpecular(indices[i], indices[i]); + int tessIdx = indices[i]; + if (-1 < tessIdx) { + root.setModifiedFillSpecular(tessIdx, indices[i]); + } } } } @@ -2223,7 +2242,10 @@ public class PShape3D extends PShape { int emissive0 = inGeo.emissive[index]; setColorRGB(colors, emissive, emissive0, indices, weights); for (int i = 0; i < indices.length; i++) { - root.setModifiedFillEmissive(indices[i], indices[i]); + int tessIdx = indices[i]; + if (-1 < tessIdx) { + root.setModifiedFillEmissive(tessIdx, indices[i]); + } } } } @@ -2255,11 +2277,13 @@ public class PShape3D extends PShape { float[] weights = inGeo.tessMap.fillWeights[index]; for (int i = 0; i < indices.length; i++) { int tessIdx = indices[i]; - float weight = weights[i]; - float tshine0 = shininess[tessIdx]; - float tshine = tshine0 + weight * (shine - shine0); - shininess[tessIdx] = tshine; - root.setModifiedFillShininess(tessIdx, tessIdx); + if (-1 < tessIdx) { + float weight = weights[i]; + float tshine0 = shininess[tessIdx]; + float tshine = tshine0 + weight * (shine - shine0); + shininess[tessIdx] = tshine; + root.setModifiedFillShininess(tessIdx, tessIdx); + } } } } @@ -2281,19 +2305,21 @@ public class PShape3D extends PShape { for (int i = 0; i < indices.length; i++) { int tessIdx = indices[i]; - float weight = weights[i]; - int tfill0 = colors[tessIdx]; - float ta0 = (tfill0 >> 24) & 0xFF; - float tr0 = (tfill0 >> 16) & 0xFF; - float tg0 = (tfill0 >> 8) & 0xFF; - float tb0 = (tfill0 >> 0) & 0xFF; - - int ta = (int) (ta0 + weight * (a - a0)); - int tr = (int) (tr0 + weight * (r - r0)); - int tg = (int) (tg0 + weight * (g - g0)); - int tb = (int) (tb0 + weight * (b - b0)); - - colors[tessIdx] = (ta << 24) | (tr << 16) | (tg << 8) | tb; + if (-1 < tessIdx) { + float weight = weights[i]; + int tfill0 = colors[tessIdx]; + float ta0 = (tfill0 >> 24) & 0xFF; + float tr0 = (tfill0 >> 16) & 0xFF; + float tg0 = (tfill0 >> 8) & 0xFF; + float tb0 = (tfill0 >> 0) & 0xFF; + + int ta = (int) (ta0 + weight * (a - a0)); + int tr = (int) (tr0 + weight * (r - r0)); + int tg = (int) (tg0 + weight * (g - g0)); + int tb = (int) (tb0 + weight * (b - b0)); + + colors[tessIdx] = (ta << 24) | (tr << 16) | (tg << 8) | tb; + } } } @@ -2309,17 +2335,19 @@ public class PShape3D extends PShape { for (int i = 0; i < indices.length; i++) { int tessIdx = indices[i]; - float weight = weights[i]; - int tfill0 = colors[tessIdx]; - float tr0 = (tfill0 >> 16) & 0xFF; - float tg0 = (tfill0 >> 8) & 0xFF; - float tb0 = (tfill0 >> 0) & 0xFF; - - int tr = (int) (tr0 + weight * (r - r0)); - int tg = (int) (tg0 + weight * (g - g0)); - int tb = (int) (tb0 + weight * (b - b0)); - - colors[tessIdx] = 0xff000000 | (tr << 16) | (tg << 8) | tb; + if (-1 < tessIdx) { + float weight = weights[i]; + int tfill0 = colors[tessIdx]; + float tr0 = (tfill0 >> 16) & 0xFF; + float tg0 = (tfill0 >> 8) & 0xFF; + float tb0 = (tfill0 >> 0) & 0xFF; + + int tr = (int) (tr0 + weight * (r - r0)); + int tg = (int) (tg0 + weight * (g - g0)); + int tb = (int) (tb0 + weight * (b - b0)); + + colors[tessIdx] = 0xff000000 | (tr << 16) | (tg << 8) | tb; + } } } @@ -2398,7 +2426,15 @@ public class PShape3D extends PShape { root.aggregate(); } } - + + + protected void updateTessellation(boolean force) { + if (force || !root.tessellated || root.contextIsOutdated()) { + root.tessellate(); + root.aggregate(); + } + } + protected void tessellate() { if (root == this && parent == null) { @@ -2416,6 +2452,9 @@ public class PShape3D extends PShape { needBufferInit = true; + forceTessellation = false; + PApplet.println("tessellating root"); + modified = false; modifiedFillVertices = false; @@ -3925,7 +3964,7 @@ public class PShape3D extends PShape { if (visible) { pre(g); - updateTessellation(); + updateTessellation(root.forceTessellation); updateGeometry(); if (family == GROUP) {