< prev index next >
modules/javafx.graphics/src/main/java/com/sun/marlin/DRendererNoAA.java
Print this page
*** 26,41 ****
package com.sun.marlin;
import static com.sun.marlin.OffHeapArray.SIZE_INT;
import jdk.internal.misc.Unsafe;
! public final class RendererNoAA implements MarlinRenderer, MarlinConst {
static final boolean DISABLE_RENDER = false;
private static final int ALL_BUT_LSB = 0xfffffffe;
! private static final int ERR_STEP_MAX = 0x7fffffff; // = 2^31 - 1
private static final double POWER_2_TO_32 = 0x1.0p32;
// 2048 (pixelSize) pixels (height) x 8 subpixels = 64K
static final int INITIAL_BUCKET_ARRAY = INITIAL_PIXEL_DIM;
--- 26,41 ----
package com.sun.marlin;
import static com.sun.marlin.OffHeapArray.SIZE_INT;
import jdk.internal.misc.Unsafe;
! public final class DRendererNoAA implements DMarlinRenderer, MarlinConst {
static final boolean DISABLE_RENDER = false;
private static final int ALL_BUT_LSB = 0xfffffffe;
! private static final int ERR_STEP_MAX = 0x7Dffffff; // = 2^31 - 1
private static final double POWER_2_TO_32 = 0x1.0p32;
// 2048 (pixelSize) pixels (height) x 8 subpixels = 64K
static final int INITIAL_BUCKET_ARRAY = INITIAL_PIXEL_DIM;
*** 56,102 ****
// size of one edge in bytes
public static final int SIZEOF_EDGE_BYTES = (int)(OFF_YMAX + SIZE_INT);
// curve break into lines
// cubic error in subpixels to decrement step
! private static final float CUB_DEC_ERR_SUBPIX
! = 1f * (1f / 8f); // 1 pixel for typical 1x1 subpixels
// cubic error in subpixels to increment step
! private static final float CUB_INC_ERR_SUBPIX
! = 0.4f * (1f / 8f); // 0.4 pixel for typical 1x1 subpixels
// cubic bind length to decrement step = 8 * error in subpixels
// multiply by 8 = error scale factor:
! public static final float CUB_DEC_BND
! = 8f * CUB_DEC_ERR_SUBPIX;
// cubic bind length to increment step = 8 * error in subpixels
! public static final float CUB_INC_BND
! = 8f * CUB_INC_ERR_SUBPIX;
// cubic countlg
public static final int CUB_COUNT_LG = 2;
// cubic count = 2^countlg
private static final int CUB_COUNT = 1 << CUB_COUNT_LG;
// cubic count^2 = 4^countlg
private static final int CUB_COUNT_2 = 1 << (2 * CUB_COUNT_LG);
// cubic count^3 = 8^countlg
private static final int CUB_COUNT_3 = 1 << (3 * CUB_COUNT_LG);
// cubic dt = 1 / count
! private static final float CUB_INV_COUNT = 1f / CUB_COUNT;
// cubic dt^2 = 1 / count^2 = 1 / 4^countlg
! private static final float CUB_INV_COUNT_2 = 1f / CUB_COUNT_2;
// cubic dt^3 = 1 / count^3 = 1 / 8^countlg
! private static final float CUB_INV_COUNT_3 = 1f / CUB_COUNT_3;
// quad break into lines
// quadratic error in subpixels
! private static final float QUAD_DEC_ERR_SUBPIX
! = 1f * (1f / 8f); // 1 pixel for typical 1x1 subpixels
// quadratic bind length to decrement step = 8 * error in subpixels
! public static final float QUAD_DEC_BND
! = 8f * QUAD_DEC_ERR_SUBPIX;
//////////////////////////////////////////////////////////////////////////////
// SCAN LINE
//////////////////////////////////////////////////////////////////////////////
// crossings ie subpixel edge x coordinates
--- 56,109 ----
// size of one edge in bytes
public static final int SIZEOF_EDGE_BYTES = (int)(OFF_YMAX + SIZE_INT);
// curve break into lines
// cubic error in subpixels to decrement step
! private static final double CUB_DEC_ERR_SUBPIX
! = 1D * (1D / 8D); // 1 pixel for typical 1x1 subpixels
// cubic error in subpixels to increment step
! private static final double CUB_INC_ERR_SUBPIX
! = 0.4D * (1D / 8D); // 0.4 pixel for typical 1x1 subpixels
// cubic bind length to decrement step = 8 * error in subpixels
// multiply by 8 = error scale factor:
! public static final double CUB_DEC_BND
! = 8D * CUB_DEC_ERR_SUBPIX;
// cubic bind length to increment step = 8 * error in subpixels
! public static final double CUB_INC_BND
! = 8D * CUB_INC_ERR_SUBPIX;
// cubic countlg
public static final int CUB_COUNT_LG = 2;
// cubic count = 2^countlg
private static final int CUB_COUNT = 1 << CUB_COUNT_LG;
// cubic count^2 = 4^countlg
private static final int CUB_COUNT_2 = 1 << (2 * CUB_COUNT_LG);
// cubic count^3 = 8^countlg
private static final int CUB_COUNT_3 = 1 << (3 * CUB_COUNT_LG);
// cubic dt = 1 / count
! private static final double CUB_INV_COUNT = 1D / CUB_COUNT;
// cubic dt^2 = 1 / count^2 = 1 / 4^countlg
! private static final double CUB_INV_COUNT_2 = 1D / CUB_COUNT_2;
// cubic dt^3 = 1 / count^3 = 1 / 8^countlg
! private static final double CUB_INV_COUNT_3 = 1D / CUB_COUNT_3;
// quad break into lines
// quadratic error in subpixels
! private static final double QUAD_DEC_ERR_SUBPIX
! = 0.5D * (1D / 8D); // 1 pixel for typical 1x1 subpixels
// quadratic bind length to decrement step = 8 * error in subpixels
! public static final double QUAD_DEC_BND
! = 8D * QUAD_DEC_ERR_SUBPIX;
!
! public static final boolean USE_SUBDIVIDE_QUAD = false;
! public static final int SUBDIVIDE_MAX = 30;
!
! public static final double QUAD_ERR_SUBPIX = 1D / 16D;
! public static final double MAX_FLAT_SQ
! = 4D * QUAD_ERR_SUBPIX * QUAD_ERR_SUBPIX; // x4
//////////////////////////////////////////////////////////////////////////////
// SCAN LINE
//////////////////////////////////////////////////////////////////////////////
// crossings ie subpixel edge x coordinates
*** 128,141 ****
//////////////////////////////////////////////////////////////////////////////
// EDGE LIST
//////////////////////////////////////////////////////////////////////////////
private int edgeMinY = Integer.MAX_VALUE;
private int edgeMaxY = Integer.MIN_VALUE;
! private float edgeMinX = Float.POSITIVE_INFINITY;
! private float edgeMaxX = Float.NEGATIVE_INFINITY;
! // edges [floats|ints] stored in off-heap memory
private final OffHeapArray edges;
private int[] edgeBuckets;
private int[] edgeBucketCounts; // 2*newedges + (1 if pruning needed)
// used range for edgeBuckets / edgeBucketCounts
--- 135,148 ----
//////////////////////////////////////////////////////////////////////////////
// EDGE LIST
//////////////////////////////////////////////////////////////////////////////
private int edgeMinY = Integer.MAX_VALUE;
private int edgeMaxY = Integer.MIN_VALUE;
! private double edgeMinX = Double.POSITIVE_INFINITY;
! private double edgeMaxX = Double.NEGATIVE_INFINITY;
! // edges [doubles|ints] stored in off-heap memory
private final OffHeapArray edges;
private int[] edgeBuckets;
private int[] edgeBucketCounts; // 2*newedges + (1 if pruning needed)
// used range for edgeBuckets / edgeBucketCounts
*** 150,191 ****
boolean useRLE = false;
// Flattens using adaptive forward differencing. This only carries out
// one iteration of the AFD loop. All it does is update AFD variables (i.e.
// X0, Y0, D*[X|Y], COUNT; not variables used for computing scanline crossings).
! private void quadBreakIntoLinesAndAdd(float x0, float y0,
! final Curve c,
! final float x2, final float y2)
{
int count = 1; // dt = 1 / count
// maximum(ddX|Y) = norm(dbx, dby) * dt^2 (= 1)
! float maxDD = FloatMath.max(Math.abs(c.dbx), Math.abs(c.dby));
! final float _DEC_BND = QUAD_DEC_BND;
while (maxDD >= _DEC_BND) {
// divide step by half:
! maxDD /= 4f; // error divided by 2^2 = 4
count <<= 1;
if (DO_STATS) {
rdrCtx.stats.stat_rdr_quadBreak_dec.add(count);
}
}
int nL = 0; // line count
if (count > 1) {
! final float icount = 1f / count; // dt
! final float icount2 = icount * icount; // dt^2
! final float ddx = c.dbx * icount2;
! final float ddy = c.dby * icount2;
! float dx = c.bx * icount2 + c.cx * icount;
! float dy = c.by * icount2 + c.cy * icount;
! float x1, y1;
while (--count > 0) {
x1 = x0 + dx;
dx += ddx;
y1 = y0 + dy;
--- 157,198 ----
boolean useRLE = false;
// Flattens using adaptive forward differencing. This only carries out
// one iteration of the AFD loop. All it does is update AFD variables (i.e.
// X0, Y0, D*[X|Y], COUNT; not variables used for computing scanline crossings).
! private void quadBreakIntoLinesAndAdd(double x0, double y0,
! final DCurve c,
! final double x2, final double y2)
{
int count = 1; // dt = 1 / count
// maximum(ddX|Y) = norm(dbx, dby) * dt^2 (= 1)
! double maxDD = FloatMath.max(Math.abs(c.dbx), Math.abs(c.dby));
! final double _DEC_BND = QUAD_DEC_BND;
while (maxDD >= _DEC_BND) {
// divide step by half:
! maxDD /= 4D; // error divided by 2^2 = 4
count <<= 1;
if (DO_STATS) {
rdrCtx.stats.stat_rdr_quadBreak_dec.add(count);
}
}
int nL = 0; // line count
if (count > 1) {
! final double icount = 1D / count; // dt
! final double icount2 = icount * icount; // dt^2
! final double ddx = c.dbx * icount2;
! final double ddy = c.dby * icount2;
! double dx = c.bx * icount2 + c.cx * icount;
! double dy = c.by * icount2 + c.cy * icount;
! double x1, y1;
while (--count > 0) {
x1 = x0 + dx;
dx += ddx;
y1 = y0 + dy;
*** 208,252 ****
// x0, y0 and x3,y3 are the endpoints of the curve. We could compute these
// using c.xat(0),c.yat(0) and c.xat(1),c.yat(1), but this might introduce
// numerical errors, and our callers already have the exact values.
// Another alternative would be to pass all the control points, and call
// c.set here, but then too many numbers are passed around.
! private void curveBreakIntoLinesAndAdd(float x0, float y0,
! final Curve c,
! final float x3, final float y3)
{
int count = CUB_COUNT;
! final float icount = CUB_INV_COUNT; // dt
! final float icount2 = CUB_INV_COUNT_2; // dt^2
! final float icount3 = CUB_INV_COUNT_3; // dt^3
// the dx and dy refer to forward differencing variables, not the last
// coefficients of the "points" polynomial
! float dddx, dddy, ddx, ddy, dx, dy;
! dddx = 2f * c.dax * icount3;
! dddy = 2f * c.day * icount3;
ddx = dddx + c.dbx * icount2;
ddy = dddy + c.dby * icount2;
dx = c.ax * icount3 + c.bx * icount2 + c.cx * icount;
dy = c.ay * icount3 + c.by * icount2 + c.cy * icount;
// we use x0, y0 to walk the line
! float x1 = x0, y1 = y0;
int nL = 0; // line count
! final float _DEC_BND = CUB_DEC_BND;
! final float _INC_BND = CUB_INC_BND;
while (count > 0) {
// divide step by half:
while (Math.abs(ddx) >= _DEC_BND || Math.abs(ddy) >= _DEC_BND) {
! dddx /= 8f;
! dddy /= 8f;
! ddx = ddx/4f - dddx;
! ddy = ddy/4f - dddy;
! dx = (dx - ddx) / 2f;
! dy = (dy - ddy) / 2f;
count <<= 1;
if (DO_STATS) {
rdrCtx.stats.stat_rdr_curveBreak_dec.add(count);
}
--- 215,259 ----
// x0, y0 and x3,y3 are the endpoints of the curve. We could compute these
// using c.xat(0),c.yat(0) and c.xat(1),c.yat(1), but this might introduce
// numerical errors, and our callers already have the exact values.
// Another alternative would be to pass all the control points, and call
// c.set here, but then too many numbers are passed around.
! private void curveBreakIntoLinesAndAdd(double x0, double y0,
! final DCurve c,
! final double x3, final double y3)
{
int count = CUB_COUNT;
! final double icount = CUB_INV_COUNT; // dt
! final double icount2 = CUB_INV_COUNT_2; // dt^2
! final double icount3 = CUB_INV_COUNT_3; // dt^3
// the dx and dy refer to forward differencing variables, not the last
// coefficients of the "points" polynomial
! double dddx, dddy, ddx, ddy, dx, dy;
! dddx = 2D * c.dax * icount3;
! dddy = 2D * c.day * icount3;
ddx = dddx + c.dbx * icount2;
ddy = dddy + c.dby * icount2;
dx = c.ax * icount3 + c.bx * icount2 + c.cx * icount;
dy = c.ay * icount3 + c.by * icount2 + c.cy * icount;
// we use x0, y0 to walk the line
! double x1 = x0, y1 = y0;
int nL = 0; // line count
! final double _DEC_BND = CUB_DEC_BND;
! final double _INC_BND = CUB_INC_BND;
while (count > 0) {
// divide step by half:
while (Math.abs(ddx) >= _DEC_BND || Math.abs(ddy) >= _DEC_BND) {
! dddx /= 8D;
! dddy /= 8D;
! ddx = ddx/4D - dddx;
! ddy = ddy/4D - dddy;
! dx = (dx - ddx) / 2D;
! dy = (dy - ddy) / 2D;
count <<= 1;
if (DO_STATS) {
rdrCtx.stats.stat_rdr_curveBreak_dec.add(count);
}
*** 258,273 ****
// can only do this on even "count" values, because we must divide count by 2
while (count % 2 == 0
&& Math.abs(dx) <= _INC_BND && Math.abs(dy) <= _INC_BND)
{
! dx = 2f * dx + ddx;
! dy = 2f * dy + ddy;
! ddx = 4f * (ddx + dddx);
! ddy = 4f * (ddy + dddy);
! dddx *= 8f;
! dddy *= 8f;
count >>= 1;
if (DO_STATS) {
rdrCtx.stats.stat_rdr_curveBreak_inc.add(count);
}
--- 265,280 ----
// can only do this on even "count" values, because we must divide count by 2
while (count % 2 == 0
&& Math.abs(dx) <= _INC_BND && Math.abs(dy) <= _INC_BND)
{
! dx = 2D * dx + ddx;
! dy = 2D * dy + ddy;
! ddx = 4D * (ddx + dddx);
! ddy = 4D * (ddy + dddy);
! dddx *= 8D;
! dddy *= 8D;
count >>= 1;
if (DO_STATS) {
rdrCtx.stats.stat_rdr_curveBreak_inc.add(count);
}
*** 293,321 ****
if (DO_STATS) {
rdrCtx.stats.stat_rdr_curveBreak.add(nL);
}
}
! private void addLine(float x1, float y1, float x2, float y2) {
if (DO_MONITORS) {
rdrCtx.stats.mon_rdr_addLine.start();
}
if (DO_STATS) {
rdrCtx.stats.stat_rdr_addLine.add(1);
}
int or = 1; // orientation of the line. 1 if y increases, 0 otherwise.
if (y2 < y1) {
or = 0;
! float tmp = y2;
y2 = y1;
y1 = tmp;
tmp = x2;
x2 = x1;
x1 = tmp;
}
! // convert subpixel coordinates (float) into pixel positions (int)
// The index of the pixel that holds the next HPC is at ceil(trueY - 0.5)
// Since y1 and y2 are biased by -0.5 in tosubpixy(), this is simply
// ceil(y1) or ceil(y2)
// upper integer (inclusive)
--- 300,328 ----
if (DO_STATS) {
rdrCtx.stats.stat_rdr_curveBreak.add(nL);
}
}
! private void addLine(double x1, double y1, double x2, double y2) {
if (DO_MONITORS) {
rdrCtx.stats.mon_rdr_addLine.start();
}
if (DO_STATS) {
rdrCtx.stats.stat_rdr_addLine.add(1);
}
int or = 1; // orientation of the line. 1 if y increases, 0 otherwise.
if (y2 < y1) {
or = 0;
! double tmp = y2;
y2 = y1;
y1 = tmp;
tmp = x2;
x2 = x1;
x1 = tmp;
}
! // convert subpixel coordinates into pixel positions (int)
// The index of the pixel that holds the next HPC is at ceil(trueY - 0.5)
// Since y1 and y2 are biased by -0.5 in tosubpixy(), this is simply
// ceil(y1) or ceil(y2)
// upper integer (inclusive)
*** 408,429 ****
// The x coordinate at that HPC is then:
// x1_intercept = x1 + (firstcrossing - y1) * slope
// The next VPC is then given by:
// VPC index = ceil(x1_intercept - 0.5), or alternately
// VPC index = floor(x1_intercept - 0.5 + 1 - epsilon)
! // epsilon is hard to pin down in floating point, but easy in fixed point, so if
// we convert to fixed point then these operations get easier:
// long x1_fixed = x1_intercept * 2^32; (fixed point 32.32 format)
// curx = next VPC = fixed_floor(x1_fixed - 2^31 + 2^32 - 1)
// = fixed_floor(x1_fixed + 2^31 - 1)
! // = fixed_floor(x1_fixed + 0x7fffffff)
! // and error = fixed_fract(x1_fixed + 0x7fffffff)
final double x1_intercept = x1d + (firstCrossing - y1d) * slope;
// inlined scalb(x1_intercept, 32):
final long x1_fixed_biased = ((long) (POWER_2_TO_32 * x1_intercept))
! + 0x7fffffffL;
// curx:
// last bit corresponds to the orientation
_unsafe.putInt(addr, (((int) (x1_fixed_biased >> 31L)) & ALL_BUT_LSB) | or);
addr += SIZE_INT;
_unsafe.putInt(addr, ((int) x1_fixed_biased) >>> 1);
--- 415,436 ----
// The x coordinate at that HPC is then:
// x1_intercept = x1 + (firstcrossing - y1) * slope
// The next VPC is then given by:
// VPC index = ceil(x1_intercept - 0.5), or alternately
// VPC index = floor(x1_intercept - 0.5 + 1 - epsilon)
! // epsilon is hard to pin down in doubleing point, but easy in fixed point, so if
// we convert to fixed point then these operations get easier:
// long x1_fixed = x1_intercept * 2^32; (fixed point 32.32 format)
// curx = next VPC = fixed_floor(x1_fixed - 2^31 + 2^32 - 1)
// = fixed_floor(x1_fixed + 2^31 - 1)
! // = fixed_floor(x1_fixed + 0x7Dffffff)
! // and error = fixed_fract(x1_fixed + 0x7Dffffff)
final double x1_intercept = x1d + (firstCrossing - y1d) * slope;
// inlined scalb(x1_intercept, 32):
final long x1_fixed_biased = ((long) (POWER_2_TO_32 * x1_intercept))
! + 0x7DffffffL;
// curx:
// last bit corresponds to the orientation
_unsafe.putInt(addr, (((int) (x1_fixed_biased >> 31L)) & ALL_BUT_LSB) | or);
addr += SIZE_INT;
_unsafe.putInt(addr, ((int) x1_fixed_biased) >>> 1);
*** 476,494 ****
// Current winding rule
private int windingRule;
// Current drawing position, i.e., final point of last segment
! private float x0, y0;
// Position of most recent 'moveTo' command
! private float sx0, sy0;
// per-thread renderer context
! final RendererContext rdrCtx;
// dirty curve
! private final Curve curve;
// clean alpha array (zero filled)
private int[] alphaLine;
// alphaLine ref (clean)
--- 483,501 ----
// Current winding rule
private int windingRule;
// Current drawing position, i.e., final point of last segment
! private double x0, y0;
// Position of most recent 'moveTo' command
! private double sx0, sy0;
// per-thread renderer context
! final DRendererContext rdrCtx;
// dirty curve
! private final DCurve curve;
// clean alpha array (zero filled)
private int[] alphaLine;
// alphaLine ref (clean)
*** 501,511 ****
private int[] blkFlags;
// blkFlags ref (clean)
private final IntArrayCache.Reference blkFlags_ref;
! RendererNoAA(final RendererContext rdrCtx) {
this.rdrCtx = rdrCtx;
this.edges = rdrCtx.newOffHeapArray(INITIAL_EDGES_CAPACITY); // 96K
this.curve = rdrCtx.curve;
--- 508,518 ----
private int[] blkFlags;
// blkFlags ref (clean)
private final IntArrayCache.Reference blkFlags_ref;
! DRendererNoAA(final DRendererContext rdrCtx) {
this.rdrCtx = rdrCtx;
this.edges = rdrCtx.newOffHeapArray(INITIAL_EDGES_CAPACITY); // 96K
this.curve = rdrCtx.curve;
*** 532,542 ****
blkFlags_ref = rdrCtx.newCleanIntArrayRef(INITIAL_ARRAY); // 1K = 1 tile line
blkFlags = blkFlags_ref.initial;
}
! public RendererNoAA init(final int pix_boundsX, final int pix_boundsY,
final int pix_boundsWidth, final int pix_boundsHeight,
final int windingRule)
{
this.windingRule = windingRule;
--- 539,549 ----
blkFlags_ref = rdrCtx.newCleanIntArrayRef(INITIAL_ARRAY); // 1K = 1 tile line
blkFlags = blkFlags_ref.initial;
}
! public DRendererNoAA init(final int pix_boundsX, final int pix_boundsY,
final int pix_boundsWidth, final int pix_boundsHeight,
final int windingRule)
{
this.windingRule = windingRule;
*** 567,578 ****
edgeBucketCounts = edgeBucketCounts_ref.getArray(edgeBucketsLength);
}
edgeMinY = Integer.MAX_VALUE;
edgeMaxY = Integer.MIN_VALUE;
! edgeMinX = Float.POSITIVE_INFINITY;
! edgeMaxX = Float.NEGATIVE_INFINITY;
// reset used mark:
edgeCount = 0;
activeEdgeMaxUsed = 0;
edges.used = 0;
--- 574,585 ----
edgeBucketCounts = edgeBucketCounts_ref.getArray(edgeBucketsLength);
}
edgeMinY = Integer.MAX_VALUE;
edgeMaxY = Integer.MIN_VALUE;
! edgeMinX = Double.POSITIVE_INFINITY;
! edgeMaxX = Double.NEGATIVE_INFINITY;
// reset used mark:
edgeCount = 0;
activeEdgeMaxUsed = 0;
edges.used = 0;
*** 637,699 ****
if (DO_MONITORS) {
rdrCtx.stats.mon_rdr_endRendering.stop();
}
}
! private static float tosubpixx(final float pix_x) {
return pix_x;
}
! private static float tosubpixy(final float pix_y) {
// shift y by -0.5 for fast ceil(y - 0.5):
! return pix_y - 0.5f;
}
@Override
! public void moveTo(float pix_x0, float pix_y0) {
closePath();
! final float sx = tosubpixx(pix_x0);
! final float sy = tosubpixy(pix_y0);
this.sx0 = sx;
this.sy0 = sy;
this.x0 = sx;
this.y0 = sy;
}
@Override
! public void lineTo(float pix_x1, float pix_y1) {
! final float x1 = tosubpixx(pix_x1);
! final float y1 = tosubpixy(pix_y1);
addLine(x0, y0, x1, y1);
x0 = x1;
y0 = y1;
}
@Override
! public void curveTo(float x1, float y1,
! float x2, float y2,
! float x3, float y3)
{
! final float xe = tosubpixx(x3);
! final float ye = tosubpixy(y3);
curve.set(x0, y0, tosubpixx(x1), tosubpixy(y1),
tosubpixx(x2), tosubpixy(y2), xe, ye);
curveBreakIntoLinesAndAdd(x0, y0, curve, xe, ye);
x0 = xe;
y0 = ye;
}
@Override
! public void quadTo(float x1, float y1, float x2, float y2) {
! final float xe = tosubpixx(x2);
! final float ye = tosubpixy(y2);
! curve.set(x0, y0, tosubpixx(x1), tosubpixy(y1), xe, ye);
! quadBreakIntoLinesAndAdd(x0, y0, curve, xe, ye);
x0 = xe;
y0 = ye;
}
@Override
public void closePath() {
addLine(x0, y0, sx0, sy0);
x0 = sx0;
y0 = sy0;
--- 644,811 ----
if (DO_MONITORS) {
rdrCtx.stats.mon_rdr_endRendering.stop();
}
}
! private static double tosubpixx(final double pix_x) {
return pix_x;
}
! private static double tosubpixy(final double pix_y) {
// shift y by -0.5 for fast ceil(y - 0.5):
! return pix_y - 0.5D;
}
@Override
! public void moveTo(double pix_x0, double pix_y0) {
closePath();
! final double sx = tosubpixx(pix_x0);
! final double sy = tosubpixy(pix_y0);
this.sx0 = sx;
this.sy0 = sy;
this.x0 = sx;
this.y0 = sy;
}
@Override
! public void lineTo(double pix_x1, double pix_y1) {
! final double x1 = tosubpixx(pix_x1);
! final double y1 = tosubpixy(pix_y1);
addLine(x0, y0, x1, y1);
x0 = x1;
y0 = y1;
}
@Override
! public void curveTo(double x1, double y1,
! double x2, double y2,
! double x3, double y3)
{
! final double xe = tosubpixx(x3);
! final double ye = tosubpixy(y3);
curve.set(x0, y0, tosubpixx(x1), tosubpixy(y1),
tosubpixx(x2), tosubpixy(y2), xe, ye);
curveBreakIntoLinesAndAdd(x0, y0, curve, xe, ye);
x0 = xe;
y0 = ye;
}
@Override
! public void quadTo(double pix_x1, double pix_y1,
! double pix_x2, double pix_y2)
! {
! final double cx1 = tosubpixx(pix_x1);
! final double cy1 = tosubpixy(pix_y1);
!
! final double xe = tosubpixx(pix_x2);
! final double ye = tosubpixy(pix_y2);
!
! if (USE_SUBDIVIDE_QUAD) {
! subdivideQuad(0, x0, y0, cx1, cy1, xe, ye);
! } else {
! curve.set(x0, y0, cx1, cy1, xe, ye);
! quadBreakIntoLinesAndAdd(x0, y0, curve, xe, ye);
! }
x0 = xe;
y0 = ye;
}
+ void subdivideQuad(final int level,
+ final double x0, final double y0,
+ final double x1, final double y1,
+ final double x2, final double y2)
+ {
+ if (level < SUBDIVIDE_MAX) {
+
+ /* Test if the curve is flat enough for insertion. */
+
+ // use Roger Willcocks bezier flatness criterion
+ // var tolerance:Number = 4*tol*tol;
+
+ final double ux = 2D * x1 - x0 - x2;
+
+ final double uy = 2D * y1 - y0 - y2;
+
+ if (ux * ux + uy * uy > MAX_FLAT_SQ) {
+ /*
+ AGG
+ double dx = x2 - x0;
+ double dy = y2 - y0;
+ final double dist = Math.abs( (x1 - x2) * dy - (y1 - y2) * dx);
+ // TODO: check collinearity ?
+ */
+
+ // if (level == 0 || dist * dist > MAX_FLAT_SQ * (dx * dx + dy * dy)) {
+ // if (ptSegDistSq(x0, y0, x2, y2, x1, y1) > MAX_FLAT_SQ) {
+ final double cx01 = (x0 + x1) / 2.0D;
+ final double cx12 = (x1 + x2) / 2.0D;
+ final double cx012 = (cx01 + cx12) / 2.0D;
+
+ final double cy01 = (y0 + y1) / 2.0D;
+ final double cy12 = (y1 + y2) / 2.0D;
+ final double cy012 = (cy01 + cy12) / 2.0D;
+
+ subdivideQuad(level + 1, x0, y0, cx01, cy01, cx012, cy012);
+ subdivideQuad(level + 1, cx012, cy012, cx12, cy12, x2, y2);
+ return;
+ }
+ }
+
+ addLine(x0, y0, x2, y2);
+ }
+
+ public static double ptSegDistSq(double x1, double y1,
+ double x2, double y2,
+ double px, double py)
+ {
+ // Adjust vectors relative to x1,y1
+ // x2,y2 becomes relative vector from x1,y1 to end of segment
+ x2 -= x1;
+ y2 -= y1;
+ // px,py becomes relative vector from x1,y1 to test point
+ px -= x1;
+ py -= y1;
+ double dotprod = px * x2 + py * y2;
+ double projlenSq;
+ if (dotprod <= 0D) {
+ // px,py is on the side of x1,y1 away from x2,y2
+ // distance to segment is length of px,py vector
+ // "length of its (clipped) projection" is now 0.0
+ projlenSq = 0D;
+ } else {
+ // switch to backwards vectors relative to x2,y2
+ // x2,y2 are already the negative of x1,y1=>x2,y2
+ // to get px,py to be the negative of px,py=>x2,y2
+ // the dot product of two negated vectors is the same
+ // as the dot product of the two normal vectors
+ px = x2 - px;
+ py = y2 - py;
+ dotprod = px * x2 + py * y2;
+ if (dotprod <= 0D) {
+ // px,py is on the side of x2,y2 away from x1,y1
+ // distance to segment is length of (backwards) px,py vector
+ // "length of its (clipped) projection" is now 0.0
+ projlenSq = 0D;
+ } else {
+ // px,py is between x1,y1 and x2,y2
+ // dotprod is the length of the px,py vector
+ // projected on the x2,y2=>x1,y1 vector times the
+ // length of the x2,y2=>x1,y1 vector
+ projlenSq = dotprod * dotprod / (x2 * x2 + y2 * y2);
+ }
+ }
+ // Distance to line is now the length of the relative point
+ // vector minus the length of its projection onto the line
+ // (which is zero if the projection falls outside the range
+ // of the line segment).
+ double lenSq = px * px + py * py - projlenSq;
+ if (lenSq < 0D) {
+ lenSq = 0D;
+ }
+ return lenSq;
+ }
+
@Override
public void closePath() {
addLine(x0, y0, sx0, sy0);
x0 = sx0;
y0 = sy0;
*** 928,938 ****
for (i = 0; i < numCrossings; i++) {
// get the pointer to the edge
ecur = _edgePtrs[i];
! /* convert subpixel coordinates (float) into pixel
positions (int) for coming scanline */
/* note: it is faster to always update edges even
if it is removed from AEL for coming or last scanline */
// random access so use unsafe:
--- 1040,1050 ----
for (i = 0; i < numCrossings; i++) {
// get the pointer to the edge
ecur = _edgePtrs[i];
! /* convert subpixel coordinates into pixel
positions (int) for coming scanline */
/* note: it is faster to always update edges even
if it is removed from AEL for coming or last scanline */
// random access so use unsafe:
*** 1028,1038 ****
for (i = 0; i < numCrossings; i++) {
// get the pointer to the edge
ecur = _edgePtrs[i];
! /* convert subpixel coordinates (float) into pixel
positions (int) for coming scanline */
/* note: it is faster to always update edges even
if it is removed from AEL for coming or last scanline */
// random access so use unsafe:
--- 1140,1150 ----
for (i = 0; i < numCrossings; i++) {
// get the pointer to the edge
ecur = _edgePtrs[i];
! /* convert subpixel coordinates into pixel
positions (int) for coming scanline */
/* note: it is faster to always update edges even
if it is removed from AEL for coming or last scanline */
// random access so use unsafe:
*** 1305,1316 ****
final int _boundsMinY = boundsMinY;
final int _boundsMaxY = boundsMaxY;
// bounds as inclusive intervals
! final int spminX = FloatMath.max(FloatMath.ceil_int(edgeMinX - 0.5f), boundsMinX);
! final int spmaxX = FloatMath.min(FloatMath.ceil_int(edgeMaxX - 0.5f), boundsMaxX - 1);
// edge Min/Max Y are already rounded to subpixels within bounds:
final int spminY = edgeMinY;
final int spmaxY;
int maxY = edgeMaxY;
--- 1417,1428 ----
final int _boundsMinY = boundsMinY;
final int _boundsMaxY = boundsMaxY;
// bounds as inclusive intervals
! final int spminX = FloatMath.max(FloatMath.ceil_int(edgeMinX - 0.5D), boundsMinX);
! final int spmaxX = FloatMath.min(FloatMath.ceil_int(edgeMaxX - 0.5D), boundsMaxX - 1);
// edge Min/Max Y are already rounded to subpixels within bounds:
final int spminY = edgeMinY;
final int spmaxY;
int maxY = edgeMaxY;
< prev index next >