diff --git a/android/core/src/processing/opengl/PGraphicsOpenGL.java b/android/core/src/processing/opengl/PGraphicsOpenGL.java index 7e69a6110..1d80826a4 100644 --- a/android/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/android/core/src/processing/opengl/PGraphicsOpenGL.java @@ -35,6 +35,7 @@ import processing.core.PVector; import java.net.URL; import java.nio.*; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -9521,6 +9522,8 @@ public class PGraphicsOpenGL extends PGraphics { int[] rawIndices; int rawSize; + int[] dupIndices; + int dupCount; int firstPolyIndexCache; int lastPolyIndexCache; @@ -10328,7 +10331,7 @@ public class PGraphicsOpenGL extends PGraphics { for (int i = in.firstVertex; i <= in.lastVertex; i++) { rawIndices[idx++] = i; } - partitionRawIndices(); + splitRawIndices(); } endTex(); tessellateEdges(); @@ -10341,7 +10344,7 @@ public class PGraphicsOpenGL extends PGraphics { int nInInd = indices.length; setRawSize(nInInd); PApplet.arrayCopy(indices, rawIndices, nInInd); - partitionRawIndices(); + splitRawIndices(); } endTex(); tessellateEdges(); @@ -10359,7 +10362,7 @@ public class PGraphicsOpenGL extends PGraphics { rawIndices[idx++] = i; rawIndices[idx++] = i + 1; } - partitionRawIndices(); + splitRawIndices(); } endTex(); tessellateEdges(); @@ -10382,7 +10385,7 @@ public class PGraphicsOpenGL extends PGraphics { rawIndices[idx++] = i - 1; } } - partitionRawIndices(); + splitRawIndices(); } endTex(); tessellateEdges(); @@ -10410,7 +10413,7 @@ public class PGraphicsOpenGL extends PGraphics { rawIndices[idx++] = i2; rawIndices[idx++] = i3; } - partitionRawIndices(); + splitRawIndices(); } endTex(); tessellateEdges(); @@ -10438,13 +10441,13 @@ public class PGraphicsOpenGL extends PGraphics { rawIndices[idx++] = i2; rawIndices[idx++] = i3; } - partitionRawIndices(); + splitRawIndices(); } endTex(); tessellateEdges(); } - // Uses the raw indices to partition the geometry into contiguous + // Uses the raw indices to split the geometry into contiguous // index groups when the vertex indices become too large. The basic // idea of this algorithm is to scan through the array of raw indices // in groups of three vertices at the time (since we are always dealing @@ -10460,15 +10463,19 @@ public class PGraphicsOpenGL extends PGraphics { // http://gameangst.com/?p=9 // http://home.comcast.net/~tom_forsyth/papers/fast_vert_cache_opt.html // http://www.ludicon.com/castano/blog/2009/02/optimal-grid-rendering/ - void partitionRawIndices() { + void splitRawIndices() { tess.polyIndexCheck(rawSize); int offset = tess.firstPolyIndex; + // Current index and vertex ranges int inInd0 = 0, inInd1 = 0; int inMaxVert0 = in.firstVertex, inMaxVert1 = in.firstVertex; - int inMaxRel = 0; - - Set inDupSet = null; + + int inMaxVertRef = inMaxVert0; // Reference vertex where last break split occurred + int inMaxVertRel = -1; // Position of vertices from last range relative to + // split position. + dupCount = 0; + IndexCache cache = tess.polyIndexCache; // In retained mode, each shape has with its own cache item, since // they should always be available to be rendererd individually, even @@ -10485,26 +10492,23 @@ public class PGraphicsOpenGL extends PGraphics { int i2 = rawIndices[3 * tr + 2]; // Vertex indices relative to the last copy position. - int ii0 = i0 - inMaxVert0; - int ii1 = i1 - inMaxVert0; - int ii2 = i2 - inMaxVert0; + int ii0 = i0 - inMaxVertRef; + int ii1 = i1 - inMaxVertRef; + int ii2 = i2 - inMaxVertRef; // Vertex indices relative to the current group. int count = cache.vertexCount[index]; int ri0, ri1, ri2; if (ii0 < 0) { - if (inDupSet == null) inDupSet = new HashSet(); - inDupSet.add(ii0); + addDupIndex(ii0); ri0 = ii0; } else ri0 = count + ii0; if (ii1 < 0) { - if (inDupSet == null) inDupSet = new HashSet(); - inDupSet.add(ii1); + addDupIndex(ii1); ri1 = ii1; } else ri1 = count + ii1; if (ii2 < 0) { - if (inDupSet == null) inDupSet = new HashSet(); - inDupSet.add(ii2); + addDupIndex(ii2); ri2 = ii2; } else ri2 = count + ii2; @@ -10513,51 +10517,101 @@ public class PGraphicsOpenGL extends PGraphics { tess.polyIndices[offset + 3 * tr + 2] = (short) ri2; inInd1 = 3 * tr + 2; - inMaxVert1 = PApplet.max(i0, i1, i2); + inMaxVert1 = PApplet.max(inMaxVert1, PApplet.max(i0, i1, i2)); + inMaxVert0 = PApplet.min(inMaxVert0, PApplet.min(i0, i1, i2)); - inMaxRel = PApplet.max(inMaxRel, PApplet.max(ri0, ri1, ri2)); - int dup = inDupSet == null ? 0 : inDupSet.size(); + inMaxVertRel = PApplet.max(inMaxVertRel, PApplet.max(ri0, ri1, ri2)); - if ((PGL.MAX_VERTEX_INDEX1 - 3 <= inMaxRel + dup && inMaxRel + dup < PGL.MAX_VERTEX_INDEX1) || + if ((PGL.MAX_VERTEX_INDEX1 - 3 <= inMaxVertRel + dupCount && inMaxVertRel + dupCount < PGL.MAX_VERTEX_INDEX1) || (tr == trCount - 1)) { // The vertex indices of the current group are about to // surpass the MAX_VERTEX_INDEX limit, or we are at the last triangle // so we need to wrap-up things anyways. - // So, copy vertices in current region first - tess.addPolyVertices(in, inMaxVert0, inMaxVert1); - - if (0 < dup) { + int nondupCount = 0; + if (0 < dupCount) { // Adjusting the negative indices so they correspond to vertices added // at the end of the block. - ArrayList inDupList = new ArrayList(inDupSet); - Collections.sort(inDupList); for (int i = inInd0; i <= inInd1; i++) { int ri = tess.polyIndices[offset + i]; if (ri < 0) { - tess.polyIndices[offset + i] = (short) (inMaxRel + 1 + inDupList.indexOf(ri)); + tess.polyIndices[offset + i] = (short) (inMaxVertRel + 1 + dupIndexPos(ri)); } } - // Copy duplicated vertices from previous regions last - for (int i = 0; i < inDupList.size(); i++) { - int ri = inDupList.get(i); - tess.addPolyVertex(in, ri + inMaxVert0); + if (inMaxVertRef <= inMaxVert1) { + // Copy non-duplicated vertices from current region first + tess.addPolyVertices(in, inMaxVertRef, inMaxVert1); + nondupCount = inMaxVert1 - inMaxVertRef + 1; } + + // Copy duplicated vertices from previous regions last + for (int i = 0; i < dupCount; i++) { + tess.addPolyVertex(in, dupIndices[i] + inMaxVertRef); + } + } else { + // Copy non-duplicated vertices from current region first + tess.addPolyVertices(in, inMaxVert0, inMaxVert1); + nondupCount = inMaxVert1 - inMaxVert0 + 1; } // Increment counts: - cache.incCounts(index, inInd1 - inInd0 + 1, inMaxVert1 - inMaxVert0 + 1 + dup); + cache.incCounts(index, inInd1 - inInd0 + 1, nondupCount + dupCount); lastPolyIndexCache = index; + + // Prepare all variables to start next cache: index = -1; - - inMaxRel = 0; - inMaxVert0 = inMaxVert1 + 1; + inMaxVertRel = -1; + inMaxVertRef = inMaxVert1 + 1; + inMaxVert0 = inMaxVertRef; inInd0 = inInd1 + 1; - if (inDupSet != null) inDupSet.clear(); + if (dupIndices != null) Arrays.fill(dupIndices, 0, dupCount, 0); + dupCount = 0; } } } + + void addDupIndex(int idx) { + if (dupIndices == null) { + dupIndices = new int[16]; + } + if (dupIndices.length == dupCount) { + int n = dupCount << 1; + + int temp[] = new int[n]; + PApplet.arrayCopy(dupIndices, 0, temp, 0, dupCount); + dupIndices = temp; + } + + if (idx < dupIndices[0]) { + // Add at the beginning + for (int i = dupCount; i > 0; i--) dupIndices[i] = dupIndices[i - 1]; + dupIndices[0] = idx; + dupCount++; + } else if (dupIndices[dupCount - 1] < idx) { + // Add at the end + dupIndices[dupCount] = idx; + dupCount++; + } else { + for (int i = 0; i < dupCount - 1; i++) { + if (dupIndices[i] == idx) break; + if (dupIndices[i] < idx && idx < dupIndices[i + 1]) { + // Insert between i and i + 1: + for (int j = dupCount; j > i + 1; j--) dupIndices[j] = dupIndices[j - 1]; + dupIndices[i + 1] = idx; + dupCount++; + break; + } + } + } + } + + int dupIndexPos(int idx) { + for (int i = 0; i < dupCount; i++) { + if (dupIndices[i] == idx) return i; + } + return 0; + } void setRawSize(int size) { int size0 = rawIndices.length;