for (int i = 1; i + 1 < count; i++) {
loadClipVertex(screen[1], uvs[1], store, clip + i * 7);
loadClipVertex(screen[2], uvs[2], store, clip + (i + 1) * 7);
+ // Fan sub-triangle screen perimeter — same expression as
+ // the object path (edge12 + edge13 + edge23); straddlers
+ // are rare, so it is computed here rather than stored.
+ final double dx01 = screen[0].x - screen[1].x;
+ final double dy01 = screen[0].y - screen[1].y;
+ final double dx02 = screen[0].x - screen[2].x;
+ final double dy02 = screen[0].y - screen[2].y;
+ final double dx12 = screen[1].x - screen[2].x;
+ final double dy12 = screen[1].y - screen[2].y;
+ final double visPerimeter = Math.sqrt(dx01 * dx01 + dy01 * dy01)
+ + Math.sqrt(dx02 * dx02 + dy02 * dy02)
+ + Math.sqrt(dx12 * dx12 + dy12 * dy12);
paintFlat(renderBuffer, block.texture(index), block.backfaceCull(),
screen[0], screen[1], screen[2],
uvs[0], uvs[1], uvs[2],
store[clip + 2],
store[clip + i * 7 + 2],
store[clip + (i + 1) * 7 + 2],
+ visPerimeter,
block.clipTtd(slot, clip));
}
return;
block.camZ(slot, index, 0),
block.camZ(slot, index, 1),
block.camZ(slot, index, 2),
- block.origTtd(index));
+ block.screenPerim(slot, index),
+ block.uvPerimeter(index));
}
/**
v1.transformedCoordinate(renderBuffer).z,
v2.transformedCoordinate(renderBuffer).z,
v3.transformedCoordinate(renderBuffer).z,
+ totalVisibleDistance,
totalTextureDistance);
}
* @param z1 camera-space depth of vertex 1
* @param z2 camera-space depth of vertex 2
* @param z3 camera-space depth of vertex 3
+ * @param totalVisibleDistance screen-edge perimeter for mipmap
+ * selection, computed once per paint call
+ * (or once per slot for mesh blocks) —
+ * callers share it instead of the core
+ * recomputing per tile
* @param totalTextureDistance UV perimeter for mipmap selection. For a
* near-plane-clipped fan this is the
* ORIGINAL triangle's perimeter (the clip
final Point2D texturePoint2,
final Point2D texturePoint3,
final double z1, final double z2, final double z3,
+ final double totalVisibleDistance,
final double totalTextureDistance) {
// Z-buffer two-pass classification: opaque-class triangles
throw new IllegalStateException(
"SDF textures are not supported in mesh blocks");
- final double edge12 = projectedPoint1.getDistanceTo(projectedPoint2);
- final double edge13 = projectedPoint1.getDistanceTo(projectedPoint3);
- final double edge23 = projectedPoint2.getDistanceTo(projectedPoint3);
- final double totalVisibleDistance = edge12 + edge13 + edge23;
-
final double scaleFactor = (totalVisibleDistance / totalTextureDistance) * 1.2d;
final TextureBitmap mipmap = texture.getMipmapForScale(scaleFactor);
private final int[][] clipRef = new int[3][];
private final double[][] clipStore = new double[3][];
private final double[][] clipTtd = new double[3][];
+
+ /** Per-triangle UV perimeter (mipmap metric), computed once at build:
+ * the uv array never changes afterwards. Same expression and
+ * accumulation order as {@code TexturedTriangle}'s
+ * computeTotalTextureDistance: d(0,1) + d(0,2) + d(1,2). */
+ private final double[] uvPerimeter;
+
+ /** Per-triangle screen-edge perimeter (mipmap metric's visible side),
+ * computed once per slot in the transform loop — identical expression
+ * to what the paint core used to recompute per tile. */
+ private final double[][] screenPerim = new double[3][];
private final int[] clipUsed = new int[3];
// Scratch for the composed top transform of the current transform call.
java.util.Arrays.fill(clipRef[s], -1);
clipStore[s] = new double[256];
clipTtd[s] = new double[16];
+ screenPerim[s] = new double[triCount];
+ }
+
+ uvPerimeter = new double[triCount];
+ for (int t = 0; t < triCount; t++) {
+ final int u = t * 6;
+ final double d1 = Math.sqrt(
+ ((uv[u] - uv[u + 2]) * (uv[u] - uv[u + 2]))
+ + ((uv[u + 1] - uv[u + 3]) * (uv[u + 1] - uv[u + 3])));
+ final double d2 = Math.sqrt(
+ ((uv[u] - uv[u + 4]) * (uv[u] - uv[u + 4]))
+ + ((uv[u + 1] - uv[u + 5]) * (uv[u + 1] - uv[u + 5])));
+ final double d3 = Math.sqrt(
+ ((uv[u + 2] - uv[u + 4]) * (uv[u + 2] - uv[u + 4]))
+ + ((uv[u + 3] - uv[u + 5]) * (uv[u + 3] - uv[u + 5])));
+ uvPerimeter[t] = d1 + d2 + d3;
}
double minX = Double.MAX_VALUE, minY = Double.MAX_VALUE,
if (maxX < rMinX || minX >= rMaxX || maxY < rMinY || minY >= rMaxY)
continue;
+ // Mipmap metric's visible side, once per slot instead of per
+ // tile: edge12 + edge13 + edge23, the same expression the
+ // paint core ran per tile (getDistanceTo sequence).
+ final double dx01 = sx0 - sx1, dy01 = sy0 - sy1;
+ final double dx02 = sx0 - sx2, dy02 = sy0 - sy2;
+ final double dx12 = sx1 - sx2, dy12 = sy1 - sy2;
+ screenPerim[slot][t] = Math.sqrt(dx01 * dx01 + dy01 * dy01)
+ + Math.sqrt(dx02 * dx02 + dy02 * dy02)
+ + Math.sqrt(dx12 * dx12 + dy12 * dy12);
+
aggregator.queueShapeForRendering(handles[t]);
}
}
clipTtd[slot] = grownTtd;
}
final int base = used;
- clipTtd[slot][base / CLIP_ENTRY] = origTtd(t);
+ clipTtd[slot][base / CLIP_ENTRY] = uvPerimeter[t];
final double scale = renderingContext.projectionScale;
final double centerX = renderingContext.centerCoordinate.x;
return clipTtd[slot][clipOffset / CLIP_ENTRY];
}
+ /** The triangle's UV perimeter, precomputed at build (see field). */
+ double uvPerimeter(final int tri) {
+ return uvPerimeter[tri];
+ }
+
/**
- * The triangle's UV perimeter, with the exact expression and
- * accumulation order of {@code TexturedTriangle}'s
- * computeTotalTextureDistance: d(0,1) + d(0,2) + d(1,2).
+ * The triangle's screen-edge perimeter for this slot, precomputed in
+ * the transform loop (only valid for triangles queued unclipped).
*/
- double origTtd(final int tri) {
- final int u = tri * 6;
- final double d1 = Math.sqrt(
- ((uv[u] - uv[u + 2]) * (uv[u] - uv[u + 2]))
- + ((uv[u + 1] - uv[u + 3]) * (uv[u + 1] - uv[u + 3])));
- final double d2 = Math.sqrt(
- ((uv[u] - uv[u + 4]) * (uv[u] - uv[u + 4]))
- + ((uv[u + 1] - uv[u + 5]) * (uv[u + 1] - uv[u + 5])));
- final double d3 = Math.sqrt(
- ((uv[u + 2] - uv[u + 4]) * (uv[u + 2] - uv[u + 4]))
- + ((uv[u + 3] - uv[u + 5]) * (uv[u + 3] - uv[u + 5])));
- return d1 + d2 + d3;
+ double screenPerim(final int slot, final int tri) {
+ return screenPerim[slot][tri];
}
/**