There are several performance issues:
- It's doing a ton of allocations when boxing the segments into Floats and Integers.
- A new vertex array is allocated for each segment.
- The segment floats are converted to double (because Stream::mapToFloat() doesn't exist), then to float again when calling the nvg functions.
- Using .parallelStream() is almost always a bad idea. You need a lot of data to benefit from concurrency. This is by far the biggest performance hit.
I would do things differently:
public class SGLNanoVGUtil {
private static float cross(float x0, float y0, float x1, float y1) {
return (x0 * y1) - (x1 * y0);
}
private static float cross0(float x, float y, float[] segment) {
return cross(x, y, segment[0], segment[1]);
}
private static float cross1(float x, float y, float[] segment) {
return cross0(x, y, segment) + cross(segment[0], segment[1], segment[2], segment[3]);
}
private static float cross2(float x, float y, float[] segment) {
return cross1(x, y, segment) + cross(segment[2], segment[3], segment[4], segment[5]);
}
public static void toNVGPath(long nvgContext, Shape shape) {
nvgBeginPath(nvgContext);
PathIterator pi = shape.getPathIterator(null);
float area = 0.0f;
float x0 = 0.0f, y0 = 0.0f;
float x = 0.0f, y = 0.0f;
float[] segment = new float[6];
while (!pi.isDone()) {
switch (pi.currentSegment(segment)) {
case PathIterator.SEG_MOVETO:
nvgMoveTo(nvgContext, segment[0], segment[1]);
x0 = x = segment[0];
y0 = y = segment[1];
break;
case PathIterator.SEG_LINETO:
area += cross0(x, y, segment);
nvgLineTo(nvgContext, segment[0], segment[1]);
x = segment[0];
y = segment[1];
break;
case PathIterator.SEG_QUADTO:
area += cross1(x, y, segment);
nvgQuadTo(nvgContext, segment[0], segment[1], segment[2], segment[3]);
x = segment[2];
y = segment[3];
break;
case PathIterator.SEG_CUBICTO:
area += cross2(x, y, segment);
nvgBezierTo(nvgContext, segment[0], segment[1], segment[2], segment[3], segment[4], segment[5]);
x = segment[4];
y = segment[5];
break;
case PathIterator.SEG_CLOSE:
area += cross(x, y, x0, y0);
nvgClosePath(nvgContext);
nvgPathWinding(nvgContext, area < 0 ? NVG_SOLID : NVG_HOLE);
area = 0.0f;
break;
}
pi.next();
}
}
}