From 18ebfeff49d875b1a773959f8e7e186b7878cd2a Mon Sep 17 00:00:00 2001 From: codeanticode Date: Wed, 17 Apr 2013 17:35:57 -0400 Subject: [PATCH] reworking logic for 2D clamping --- .../processing/opengl/PGraphicsOpenGL.java | 285 +++++++++++++----- 1 file changed, 215 insertions(+), 70 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 7eed354ce..af666f3a7 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -523,10 +523,6 @@ public class PGraphicsOpenGL extends PGraphics { protected IntBuffer intBuffer; protected FloatBuffer floatBuffer; - - /** Flag used to disable coord clamping in 2D when strokes have fractional weight */ - protected boolean clampingEnabled = false; - ////////////////////////////////////////////////////////////// // INIT/ALLOCATE/FINISH @@ -2193,6 +2189,8 @@ public class PGraphicsOpenGL extends PGraphics { if (normalMode == NORMAL_MODE_AUTO) inGeo.calcTriangleStripNormals(); tessellator.tessellateTriangleStrip(); } else if (shape == QUAD || shape == QUADS) { + + if (stroke && defaultEdges) inGeo.addQuadsEdges(); if (normalMode == NORMAL_MODE_AUTO) inGeo.calcQuadsNormals(); tessellator.tessellateQuads(); @@ -9909,29 +9907,32 @@ public class PGraphicsOpenGL extends PGraphics { int rgba, float nx, float ny, float nz, float u, float v, - int am, int sp, int em, float shine) { + int am, int sp, int em, float shine, + boolean clamp) { polyVertexCheck(); int tessIdx = polyVertexCount - 1; setPolyVertex(tessIdx, x, y, z, rgba, nx, ny, nz, u, v, - am, sp, em, shine); + am, sp, em, shine, clamp); } - void setPolyVertex(int tessIdx, float x, float y, float z, int rgba) { + void setPolyVertex(int tessIdx, float x, float y, float z, int rgba, + boolean clamp) { setPolyVertex(tessIdx, x, y, z, rgba, 0, 0, 1, 0, 0, - 0, 0, 0, 0); + 0, 0, 0, 0, clamp); } void setPolyVertex(int tessIdx, float x, float y, float z, int rgba, float nx, float ny, float nz, float u, float v, - int am, int sp, int em, float shine) { + int am, int sp, int em, float shine, + boolean clamp) { int index; if (renderMode == IMMEDIATE && flushMode == FLUSH_WHEN_FULL) { @@ -9939,20 +9940,18 @@ public class PGraphicsOpenGL extends PGraphics { PMatrix3D nm = modelviewInv; index = 4 * tessIdx; - if (is2D() && clampingEnabled) { + if (is2D() && clamp) { // ceil emulates the behavior of JAVA2D polyVertices[index++] = PApplet.ceil(x*mm.m00 + y*mm.m01 + z*mm.m02 + mm.m03); polyVertices[index++] = PApplet.ceil(x*mm.m10 + y*mm.m11 + z*mm.m12 + mm.m13); - polyVertices[index++] = x*mm.m20 + y*mm.m21 + z*mm.m22 + mm.m23; - polyVertices[index ] = x*mm.m30 + y*mm.m31 + z*mm.m32 + mm.m33; } else { polyVertices[index++] = x*mm.m00 + y*mm.m01 + z*mm.m02 + mm.m03; polyVertices[index++] = x*mm.m10 + y*mm.m11 + z*mm.m12 + mm.m13; - polyVertices[index++] = x*mm.m20 + y*mm.m21 + z*mm.m22 + mm.m23; - polyVertices[index ] = x*mm.m30 + y*mm.m31 + z*mm.m32 + mm.m33; } + polyVertices[index++] = x*mm.m20 + y*mm.m21 + z*mm.m22 + mm.m23; + polyVertices[index ] = x*mm.m30 + y*mm.m31 + z*mm.m32 + mm.m33; index = 3 * tessIdx; polyNormals[index++] = nx*nm.m00 + ny*nm.m10 + nz*nm.m20; @@ -9983,15 +9982,15 @@ public class PGraphicsOpenGL extends PGraphics { polyShininess[tessIdx] = shine; } - void addPolyVertices(InGeometry in) { - addPolyVertices(in, in.firstVertex, in.lastVertex); + void addPolyVertices(InGeometry in, boolean clamp) { + addPolyVertices(in, in.firstVertex, in.lastVertex, clamp); } - void addPolyVertex(InGeometry in, int i) { - addPolyVertices(in, i, i); + void addPolyVertex(InGeometry in, int i, boolean clamp) { + addPolyVertices(in, i, i, clamp); } - void addPolyVertices(InGeometry in, int i0, int i1) { + void addPolyVertices(InGeometry in, int i0, int i1, boolean clamp) { int index; int nvert = i1 - i0 + 1; @@ -10016,19 +10015,18 @@ public class PGraphicsOpenGL extends PGraphics { float nz = in.normals[index ]; index = 4 * tessIdx; - if (is2D() && clampingEnabled) { + if (is2D() && clamp) { + // ceil emulates the behavior of JAVA2D polyVertices[index++] = PApplet.ceil(x*mm.m00 + y*mm.m01 + z*mm.m02 + mm.m03); polyVertices[index++] = PApplet.ceil(x*mm.m10 + y*mm.m11 + z*mm.m12 + mm.m13); - polyVertices[index++] = x*mm.m20 + y*mm.m21 + z*mm.m22 + mm.m23; - polyVertices[index ] = x*mm.m30 + y*mm.m31 + z*mm.m32 + mm.m33; } else { polyVertices[index++] = x*mm.m00 + y*mm.m01 + z*mm.m02 + mm.m03; polyVertices[index++] = x*mm.m10 + y*mm.m11 + z*mm.m12 + mm.m13; - polyVertices[index++] = x*mm.m20 + y*mm.m21 + z*mm.m22 + mm.m23; - polyVertices[index ] = x*mm.m30 + y*mm.m31 + z*mm.m32 + mm.m33; } + polyVertices[index++] = x*mm.m20 + y*mm.m21 + z*mm.m22 + mm.m23; + polyVertices[index ] = x*mm.m30 + y*mm.m31 + z*mm.m32 + mm.m33; index = 3 * tessIdx; polyNormals[index++] = nx*nm.m00 + ny*nm.m10 + nz*nm.m20; @@ -10528,13 +10526,13 @@ public class PGraphicsOpenGL extends PGraphics { float val = 0; float inc = (float) SINCOS_LENGTH / perim; - tess.setPolyVertex(vertIdx, x0, y0, 0, rgba); + tess.setPolyVertex(vertIdx, x0, y0, 0, rgba, false); vertIdx++; for (int k = 0; k < perim; k++) { tess.setPolyVertex(vertIdx, x0 + 0.5f * cosLUT[(int) val] * strokeWeight, y0 + 0.5f * sinLUT[(int) val] * strokeWeight, - 0, rgba); + 0, rgba, false); vertIdx++; val = (val + inc) % SINCOS_LENGTH; } @@ -10636,6 +10634,7 @@ public class PGraphicsOpenGL extends PGraphics { void tessellateSquarePoints2D(int nvertTot, int nindTot) { tess.polyVertexCheck(nvertTot); tess.polyIndexCheck(nindTot); + boolean clamp = clampSquarePoints2D(); int vertIdx = tess.firstPolyVertex; int indIdx = tess.firstPolyIndex; IndexCache cache = tess.polyIndexCache; @@ -10654,13 +10653,13 @@ public class PGraphicsOpenGL extends PGraphics { float y0 = in.vertices[3 * i + 1]; int rgba = in.strokeColors[i]; - tess.setPolyVertex(vertIdx, x0, y0, 0, rgba); + tess.setPolyVertex(vertIdx, x0, y0, 0, rgba, clamp); vertIdx++; for (int k = 0; k < nvert - 1; k++) { tess.setPolyVertex(vertIdx, x0 + 0.5f * QUAD_POINT_SIGNS[k][0] * strokeWeight, y0 + 0.5f * QUAD_POINT_SIGNS[k][1] * strokeWeight, - 0, rgba); + 0, rgba, clamp); vertIdx++; } @@ -10679,6 +10678,15 @@ public class PGraphicsOpenGL extends PGraphics { lastPointIndexCache = lastPolyIndexCache = index; } + boolean clamp2D() { + return is2D && tess.renderMode == IMMEDIATE && + zero(modelview.m01) && zero(modelview.m10); + } + + boolean clampSquarePoints2D() { + return clamp2D(); + } + // ----------------------------------------------------------------- // // Line tessellation @@ -10714,11 +10722,22 @@ public class PGraphicsOpenGL extends PGraphics { for (int ln = 0; ln < lineCount; ln++) { int i0 = first + 2 * ln + 0; int i1 = first + 2 * ln + 1; - index = addLine3D(i0, i1, index, null, false); + index = addLineSegment3D(i0, i1, index, null, false); } lastLineIndexCache = index; } + boolean segmentIsAxisAligned(int i0, int i1) { + float x0 = in.vertices[3 * i0 + 0]; + float y0 = in.vertices[3 * i0 + 1]; + + float x1 = in.vertices[3 * i1 + 0]; + float y1 = in.vertices[3 * i1 + 1]; + + return zero(x0 - x1) || zero(y0 - y1); + } + + void tessellateLines2D(int lineCount) { int nvert = lineCount * 4; int nind = lineCount * 2 * 3; @@ -10731,10 +10750,11 @@ public class PGraphicsOpenGL extends PGraphics { tess.polyIndexCache.getLast(); firstLineIndexCache = index; if (firstPolyIndexCache == -1) firstPolyIndexCache = index; // If the geometry has no fill, needs the first poly index. + boolean clamp = clampLines2D(lineCount); for (int ln = 0; ln < lineCount; ln++) { int i0 = first + 2 * ln + 0; int i1 = first + 2 * ln + 1; - index = addLine2D(i0, i1, index, false); + index = addLineSegment2D(i0, i1, index, false, clamp); } lastLineIndexCache = lastPolyIndexCache = index; } else { // full stroking algorithm @@ -10751,6 +10771,19 @@ public class PGraphicsOpenGL extends PGraphics { } } + boolean clampLines2D(int lineCount) { + boolean res = clamp2D(); + if (res) { + int first = in.firstVertex; + for (int ln = 0; ln < lineCount; ln++) { + int i0 = first + 2 * ln + 0; + int i1 = first + 2 * ln + 1; + res &= segmentIsAxisAligned(i0, i1); + } + } + return res; + } + void tessellateLineStrip() { int nInVert = in.lastVertex - in.firstVertex + 1; if (stroke && 2 <= nInVert) { @@ -10781,9 +10814,9 @@ public class PGraphicsOpenGL extends PGraphics { for (int ln = 0; ln < lineCount; ln++) { int i1 = in.firstVertex + ln + 1; if (0 < nBevelTr) { - index = addLine3D(i0, i1, index, lastInd, false); + index = addLineSegment3D(i0, i1, index, lastInd, false); } else { - index = addLine3D(i0, i1, index, null, false); + index = addLineSegment3D(i0, i1, index, null, false); } i0 = i1; } @@ -10802,9 +10835,10 @@ public class PGraphicsOpenGL extends PGraphics { firstLineIndexCache = index; if (firstPolyIndexCache == -1) firstPolyIndexCache = index; // If the geometry has no fill, needs the first poly index. int i0 = in.firstVertex; + boolean clamp = clampLineStrip2D(lineCount); for (int ln = 0; ln < lineCount; ln++) { int i1 = in.firstVertex + ln + 1; - index = addLine2D(i0, i1, index, false); + index = addLineSegment2D(i0, i1, index, false, clamp); i0 = i1; } lastLineIndexCache = lastPolyIndexCache = index; @@ -10822,6 +10856,18 @@ public class PGraphicsOpenGL extends PGraphics { } } + boolean clampLineStrip2D(int lineCount) { + boolean res = clamp2D(); + if (res) { + int i0 = in.firstVertex; + for (int ln = 0; ln < lineCount; ln++) { + int i1 = in.firstVertex + ln + 1; + res &= segmentIsAxisAligned(i0, i1); + } + } + return res; + } + void tessellateLineLoop() { int nInVert = in.lastVertex - in.firstVertex + 1; if (stroke && 2 <= nInVert) { @@ -10853,14 +10899,15 @@ public class PGraphicsOpenGL extends PGraphics { for (int ln = 0; ln < lineCount - 1; ln++) { int i1 = in.firstVertex + ln + 1; if (0 < nBevelTr) { - index = addLine3D(i0, i1, index, lastInd, false); + index = addLineSegment3D(i0, i1, index, lastInd, false); if (ln == 0) firstInd = (short)(lastInd[0] - 2); } else { - index = addLine3D(i0, i1, index, null, false); + index = addLineSegment3D(i0, i1, index, null, false); } i0 = i1; } - index = addLine3D(in.lastVertex, in.firstVertex, index, lastInd, false); + index = addLineSegment3D(in.lastVertex, in.firstVertex, index, lastInd, + false); if (0 < nBevelTr) { index = addBevel3D(in.firstVertex, index, lastInd, firstInd, false); } @@ -10879,12 +10926,14 @@ public class PGraphicsOpenGL extends PGraphics { firstLineIndexCache = index; if (firstPolyIndexCache == -1) firstPolyIndexCache = index; // If the geometry has no fill, needs the first poly index. int i0 = in.firstVertex; + boolean clamp = clampLineLoop2D(lineCount); for (int ln = 0; ln < lineCount - 1; ln++) { int i1 = in.firstVertex + ln + 1; - index = addLine2D(i0, i1, index, false); + index = addLineSegment2D(i0, i1, index, false, clamp); i0 = i1; } - index = addLine2D(in.lastVertex, in.firstVertex, index, false); + index = addLineSegment2D(in.lastVertex, in.firstVertex, index, false, + clamp); lastLineIndexCache = lastPolyIndexCache = index; } else { // full stroking algorithm int first = in.firstVertex; @@ -10901,6 +10950,18 @@ public class PGraphicsOpenGL extends PGraphics { } } + boolean clampLineLoop2D(int lineCount) { + boolean res = clamp2D(); + if (res) { + int i0 = in.firstVertex; + for (int ln = 0; ln < lineCount; ln++) { + int i1 = in.firstVertex + ln + 1; + res &= segmentIsAxisAligned(i0, i1); + } + } + return res; + } + void tessellateEdges() { if (stroke) { if (in.edgeCount == 0) return; @@ -10935,14 +10996,14 @@ public class PGraphicsOpenGL extends PGraphics { index = addBevel3D(edge[1], index, lastInd, firstInd, false); lastInd[0] = lastInd[1] = -1; // No join with next line segment. } else { - index = addLine3D(i0, i1, index, lastInd, false); + index = addLineSegment3D(i0, i1, index, lastInd, false); if (edge[2] == EDGE_START) firstInd = (short)(lastInd[0] - 2); if (edge[2] == EDGE_STOP || edge[2] == EDGE_SINGLE) { lastInd[0] = lastInd[1] = -1; // No join with next line segment. } } } else { - index = addLine3D(i0, i1, index, null, false); + index = addLineSegment3D(i0, i1, index, null, false); } } lastLineIndexCache = index; @@ -10959,12 +11020,13 @@ public class PGraphicsOpenGL extends PGraphics { tess.polyIndexCache.getLast(); firstLineIndexCache = index; if (firstPolyIndexCache == -1) firstPolyIndexCache = index; // If the geometry has no fill, needs the first poly index. + boolean clamp = clampEdges2D(); for (int i = in.firstEdge; i <= in.lastEdge; i++) { int[] edge = in.edges[i]; if (edge[2] == EDGE_CLOSE) continue; // ignoring edge closures when not doing caps or joins. int i0 = edge[0]; int i1 = edge[1]; - index = addLine2D(i0, i1, index, false); + index = addLineSegment2D(i0, i1, index, false, clamp); } lastLineIndexCache = lastPolyIndexCache = index; } else { // full stroking algorithm @@ -11007,9 +11069,23 @@ public class PGraphicsOpenGL extends PGraphics { } } + boolean clampEdges2D() { + boolean res = clamp2D(); + if (res) { + for (int i = in.firstEdge; i <= in.lastEdge; i++) { + int[] edge = in.edges[i]; + if (edge[2] == EDGE_CLOSE) continue; // ignoring edge closures when not doing caps or joins. + int i0 = edge[0]; + int i1 = edge[1]; + res &= segmentIsAxisAligned(i0, i1); + } + } + return res; + } + // Adding the data that defines a quad starting at vertex i0 and // ending at i1. - int addLine3D(int i0, int i1, int index, short[] lastInd, + int addLineSegment3D(int i0, int i1, int index, short[] lastInd, boolean constStroke) { IndexCache cache = tess.lineIndexCache; int count = cache.vertexCount[index]; @@ -11139,7 +11215,8 @@ public class PGraphicsOpenGL extends PGraphics { // Adding the data that defines a quad starting at vertex i0 and // ending at i1, in the case of pure 2D renderers (line geometry // is added to the poly arrays). - int addLine2D(int i0, int i1, int index, boolean constStroke) { + int addLineSegment2D(int i0, int i1, int index, + boolean constStroke, boolean clampXY) { IndexCache cache = tess.polyIndexCache; int count = cache.vertexCount[index]; if (PGL.MAX_VERTEX_INDEX1 <= count + 4) { @@ -11152,7 +11229,7 @@ public class PGraphicsOpenGL extends PGraphics { int color = constStroke ? strokeColor : in.strokeColors[i0]; float weight = constStroke ? strokeWeight : in.strokeWeights[i0]; - if (subPixelStroke(weight)) clampingEnabled = false; + if (subPixelStroke(weight)) clampXY = false; float x0 = in.vertices[3 * i0 + 0]; float y0 = in.vertices[3 * i0 + 1]; @@ -11183,14 +11260,14 @@ public class PGraphicsOpenGL extends PGraphics { float normdy = normy * weight/2; tess.setPolyVertex(vidx++, x0 + normdx - dirdx, y0 + normdy - dirdy, - 0, color); + 0, color, clampXY); tess.polyIndices[iidx++] = (short) (count + 0); tess.setPolyVertex(vidx++, x0 - normdx - dirdx, y0 - normdy - dirdy, - 0, color); + 0, color, clampXY); tess.polyIndices[iidx++] = (short) (count + 1); - if (clampingEnabled) { + if (clampXY) { // Check for degeneracy due to coordinate clamping float xac = tess.polyVertices[4 * (vidx - 2) + 0]; float yac = tess.polyVertices[4 * (vidx - 2) + 1]; @@ -11207,11 +11284,11 @@ public class PGraphicsOpenGL extends PGraphics { weight = in.strokeWeights[i1]; normdx = normx * weight/2; normdy = normy * weight/2; - if (subPixelStroke(weight)) clampingEnabled = false; + if (subPixelStroke(weight)) clampXY = false; } tess.setPolyVertex(vidx++, x1 - normdx + dirdx, y1 - normdy + dirdy, - 0, color); + 0, color, clampXY); tess.polyIndices[iidx++] = (short) (count + 2); // Starting a new triangle re-using prev vertices. @@ -11219,10 +11296,10 @@ public class PGraphicsOpenGL extends PGraphics { tess.polyIndices[iidx++] = (short) (count + 0); tess.setPolyVertex(vidx++, x1 + normdx + dirdx, y1 + normdy + dirdy, - 0, color); + 0, color, clampXY); tess.polyIndices[iidx++] = (short) (count + 3); - if (clampingEnabled) { + if (clampXY) { // Check for degeneracy due to coordinate clamping float xac = tess.polyVertices[4 * (vidx - 2) + 0]; float yac = tess.polyVertices[4 * (vidx - 2) + 1]; @@ -11235,8 +11312,6 @@ public class PGraphicsOpenGL extends PGraphics { } cache.incCounts(index, 6, 4); - - clampingEnabled = true; return index; } @@ -11307,15 +11382,23 @@ public class PGraphicsOpenGL extends PGraphics { int nInInd = nInVert; setRawSize(nInInd); int idx = 0; + boolean clamp = clampTriangles(); for (int i = in.firstVertex; i <= in.lastVertex; i++) { rawIndices[idx++] = i; } - splitRawIndices(); + splitRawIndices(clamp); } endTex(); tessellateEdges(); } + boolean clampTriangles() { + boolean res = clamp2D(); + if (res) { + } + return res; + } + void tessellateTriangles(int[] indices) { beginTex(); int nInVert = in.lastVertex - in.firstVertex + 1; @@ -11323,12 +11406,20 @@ public class PGraphicsOpenGL extends PGraphics { int nInInd = indices.length; setRawSize(nInInd); PApplet.arrayCopy(indices, rawIndices, nInInd); - splitRawIndices(); + boolean clamp = clampTriangles(indices); + splitRawIndices(clamp); } endTex(); tessellateEdges(); } + boolean clampTriangles(int[] indices) { + boolean res = clamp2D(); + if (res) { + } + return res; + } + void tessellateTriangleFan() { beginTex(); int nInVert = in.lastVertex - in.firstVertex + 1; @@ -11336,17 +11427,25 @@ public class PGraphicsOpenGL extends PGraphics { int nInInd = 3 * (nInVert - 2); setRawSize(nInInd); int idx = 0; + boolean clamp = clampTriangleFan(); for (int i = in.firstVertex + 1; i < in.lastVertex; i++) { rawIndices[idx++] = in.firstVertex; rawIndices[idx++] = i; rawIndices[idx++] = i + 1; } - splitRawIndices(); + splitRawIndices(clamp); } endTex(); tessellateEdges(); } + boolean clampTriangleFan() { + boolean res = clamp2D(); + if (res) { + } + return res; + } + void tessellateTriangleStrip() { beginTex(); int nInVert = in.lastVertex - in.firstVertex + 1; @@ -11354,6 +11453,7 @@ public class PGraphicsOpenGL extends PGraphics { int nInInd = 3 * (nInVert - 2); setRawSize(nInInd); int idx = 0; + boolean clamp = clampTriangleStrip(); for (int i = in.firstVertex + 1; i < in.lastVertex; i++) { rawIndices[idx++] = i; if (i % 2 == 0) { @@ -11364,12 +11464,19 @@ public class PGraphicsOpenGL extends PGraphics { rawIndices[idx++] = i - 1; } } - splitRawIndices(); + splitRawIndices(clamp); } endTex(); tessellateEdges(); } + boolean clampTriangleStrip() { + boolean res = clamp2D(); + if (res) { + } + return res; + } + void tessellateQuads() { beginTex(); int nInVert = in.lastVertex - in.firstVertex + 1; @@ -11378,6 +11485,7 @@ public class PGraphicsOpenGL extends PGraphics { int nInInd = 6 * quadCount; setRawSize(nInInd); int idx = 0; + boolean clamp = clampQuads(quadCount); for (int qd = 0; qd < quadCount; qd++) { int i0 = in.firstVertex + 4 * qd + 0; int i1 = in.firstVertex + 4 * qd + 1; @@ -11392,12 +11500,29 @@ public class PGraphicsOpenGL extends PGraphics { rawIndices[idx++] = i3; rawIndices[idx++] = i0; } - splitRawIndices(); + splitRawIndices(clamp); } endTex(); tessellateEdges(); } + boolean clampQuads(int quadCount) { + boolean res = clamp2D(); + if (res) { + for (int qd = 0; qd < quadCount; qd++) { + int i0 = in.firstVertex + 4 * qd + 0; + int i1 = in.firstVertex + 4 * qd + 1; + int i2 = in.firstVertex + 4 * qd + 2; + int i3 = in.firstVertex + 4 * qd + 3; + res &= segmentIsAxisAligned(i0, i1) && + segmentIsAxisAligned(i1, i2) && + segmentIsAxisAligned(i2, i3); + } + } + PApplet.println("quads are axis aligned " + res); + return res; + } + void tessellateQuadStrip() { beginTex(); int nInVert = in.lastVertex - in.firstVertex + 1; @@ -11406,6 +11531,7 @@ public class PGraphicsOpenGL extends PGraphics { int nInInd = 6 * quadCount; setRawSize(nInInd); int idx = 0; + boolean clamp = clampQuadStrip(); for (int qd = 1; qd < nInVert / 2; qd++) { int i0 = in.firstVertex + 2 * (qd - 1); int i1 = in.firstVertex + 2 * (qd - 1) + 1; @@ -11420,12 +11546,19 @@ public class PGraphicsOpenGL extends PGraphics { rawIndices[idx++] = i2; rawIndices[idx++] = i3; } - splitRawIndices(); + splitRawIndices(clamp); } endTex(); tessellateEdges(); } + boolean clampQuadStrip() { + boolean res = clamp2D(); + if (res) { + } + return res; + } + // 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 @@ -11442,7 +11575,7 @@ 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 splitRawIndices() { + void splitRawIndices(boolean clampXY) { tess.polyIndexCheck(rawSize); int offset = tess.firstPolyIndex; @@ -11522,17 +11655,17 @@ public class PGraphicsOpenGL extends PGraphics { if (inMaxVertRef <= inMaxVert1) { // Copy non-duplicated vertices from current region first - tess.addPolyVertices(in, inMaxVertRef, inMaxVert1); + tess.addPolyVertices(in, inMaxVertRef, inMaxVert1, clampXY); nondupCount = inMaxVert1 - inMaxVertRef + 1; } // Copy duplicated vertices from previous regions last for (int i = 0; i < dupCount; i++) { - tess.addPolyVertex(in, dupIndices[i] + inMaxVertRef); + tess.addPolyVertex(in, dupIndices[i] + inMaxVertRef, clampXY); } } else { // Copy non-duplicated vertices from current region first - tess.addPolyVertices(in, inMaxVert0, inMaxVert1); + tess.addPolyVertices(in, inMaxVert0, inMaxVert1, clampXY); nondupCount = inMaxVert1 - inMaxVert0 + 1; } @@ -11664,7 +11797,8 @@ public class PGraphicsOpenGL extends PGraphics { if (fill && 3 <= nInVert) { firstPolyIndexCache = -1; - callback.init(in.renderMode == RETAINED, false, calcNormals); + boolean clamp = clampPolygon(); + callback.init(in.renderMode == RETAINED, false, calcNormals, clamp); gluTess.beginPolygon(); @@ -11727,11 +11861,17 @@ public class PGraphicsOpenGL extends PGraphics { tessellateEdges(); } + boolean clampPolygon() { + return false; + } + // 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) { - callback.init(in.renderMode == RETAINED, true, false); + boolean clamp = clampLinePath(); + + callback.init(in.renderMode == RETAINED, true, false, clamp); int cap = strokeCap == ROUND ? LinePath.CAP_ROUND : strokeCap == PROJECT ? LinePath.CAP_SQUARE : @@ -11740,8 +11880,6 @@ public class PGraphicsOpenGL extends PGraphics { strokeJoin == BEVEL ? LinePath.JOIN_BEVEL : LinePath.JOIN_MITER; - if (subPixelStroke(strokeWeight)) clampingEnabled = false; - // Make the outline of the stroke from the path LinePath strokedPath = LinePath.createStrokedPath(path, strokeWeight, cap, join); @@ -11788,8 +11926,12 @@ public class PGraphicsOpenGL extends PGraphics { iter.next(); } gluTess.endPolygon(); + } - clampingEnabled = true; + boolean clampLinePath() { + return clamp2D() && + strokeCap == PROJECT && strokeJoin == BEVEL && + !subPixelStroke(strokeWeight); } ///////////////////////////////////////// @@ -11810,15 +11952,18 @@ public class PGraphicsOpenGL extends PGraphics { protected class TessellatorCallback implements PGL.TessellatorCallback { boolean calcNormals; boolean strokeTess; + boolean clampXY; IndexCache cache; int cacheIndex; int vertFirst; int vertCount; int primitive; - public void init(boolean addCache, boolean strokeTess, boolean calcNorm) { + public void init(boolean addCache, boolean strokeTess, boolean calcNorm, + boolean clampXY) { this.strokeTess = strokeTess; this.calcNormals = calcNorm; + this.clampXY = clampXY; cache = tess.polyIndexCache; if (addCache) { @@ -11949,7 +12094,7 @@ public class PGraphicsOpenGL extends PGraphics { (float) d[ 7], (float) d[ 8], (float) d[ 9], (float) d[10], (float) d[11], acolor, scolor, ecolor, - (float) d[24]); + (float) d[24], clampXY); vertCount++; } else {