Skip to content

Commit

Permalink
Fixed bugs in PathClipFilter: fixed clip() to handle L/R corners + mo…
Browse files Browse the repository at this point in the history
…veTo() must finishPath() first
  • Loading branch information
bourgesl committed Nov 4, 2017
1 parent 25501b7 commit aafb87d
Show file tree
Hide file tree
Showing 6 changed files with 216 additions and 105 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<groupId>org.marlin</groupId>
<artifactId>marlin</artifactId>
<packaging>jar</packaging>
<version>0.8.1.2-Unsafe</version>
<version>0.8.2-Unsafe</version>
<name>Marlin software rasterizer</name>

<url>https://github.com/bourgesl/marlin-renderer</url>
Expand Down
35 changes: 12 additions & 23 deletions src/main/java/org/marlin/pisces/DMarlinRenderingEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,6 @@ abstract PathIterator getNormalizingPathIterator(DRendererContext rdrCtx,

static final boolean DO_CLIP_RUNTIME_ENABLE = MarlinProperties.isDoClipRuntimeFlag();

static final boolean DO_CLIP_TEST = false;

/**
* Public constructor
*/
Expand Down Expand Up @@ -816,24 +814,10 @@ public AATileGenerator getAATileGenerator(Shape s,
// Define the initial clip bounds:
final double[] clipRect = rdrCtx.clipRect;

if (DO_CLIP_TEST) {
// clip rect area / 4 to see remaining paths after clipping:
double h = clip.getHeight();
double w = clip.getWidth();
final double cx = (clip.getLoX() + w) / 2.0d;
final double cy = (clip.getLoY() + h) / 2.0d;
h /= 4.0d;
w /= 4.0d;
clipRect[0] = cy - h;
clipRect[1] = cy + h;
clipRect[2] = cx - w;
clipRect[3] = cx + w;
} else {
clipRect[0] = clip.getLoY();
clipRect[1] = clip.getLoY() + clip.getHeight();
clipRect[2] = clip.getLoX();
clipRect[3] = clip.getLoX() + clip.getWidth();
}
clipRect[0] = clip.getLoY();
clipRect[1] = clip.getLoY() + clip.getHeight();
clipRect[2] = clip.getLoX();
clipRect[3] = clip.getLoX() + clip.getWidth();

// Enable clipping:
rdrCtx.doClip = true;
Expand All @@ -859,14 +843,19 @@ public AATileGenerator getAATileGenerator(Shape s,

DPathConsumer2D pc2d = r;

if (DO_CLIP_FILL && (windingRule == WIND_NON_ZERO) && rdrCtx.doClip) {
if (DO_CLIP_FILL && rdrCtx.doClip) {
if (DO_TRACE_PATH) {
// trace Input:
pc2d = rdrCtx.transformerPC2D.traceInput(pc2d);
// trace Filler:
pc2d = rdrCtx.transformerPC2D.traceFiller(pc2d);
}
pc2d = rdrCtx.transformerPC2D.pathClipper(pc2d);
}

if (DO_TRACE_PATH) {
// trace Input:
pc2d = rdrCtx.transformerPC2D.traceInput(pc2d);
}

// TODO: subdivide quad/cubic curves into monotonic curves ?
pathTo(rdrCtx, pi, pc2d);

Expand Down
64 changes: 36 additions & 28 deletions src/main/java/org/marlin/pisces/DTransformingPathConsumer2D.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ final class DTransformingPathConsumer2D {
// recycled PathTracer instances from tracer...() methods
private final PathTracer tracerInput = new PathTracer("[Input]");
private final PathTracer tracerCPDetector = new PathTracer("ClosedPathDetector");
private final PathTracer tracerFiller = new PathTracer("Filler");
private final PathTracer tracerStroker = new PathTracer("Stroker");

DTransformingPathConsumer2D(final DRendererContext rdrCtx) {
Expand All @@ -76,6 +77,10 @@ DPathConsumer2D traceClosedPathDetector(DPathConsumer2D out) {
return tracerCPDetector.init(out);
}

DPathConsumer2D traceFiller(DPathConsumer2D out) {
return tracerFiller.init(out);
}

DPathConsumer2D traceStroker(DPathConsumer2D out) {
return tracerStroker.init(out);
}
Expand All @@ -96,10 +101,10 @@ DPathConsumer2D deltaTransformConsumer(DPathConsumer2D out,
if (at == null) {
return out;
}
double mxx = at.getScaleX();
double mxy = at.getShearX();
double myx = at.getShearY();
double myy = at.getScaleY();
final double mxx = at.getScaleX();
final double mxy = at.getShearX();
final double myx = at.getShearY();
final double myy = at.getScaleY();

if (mxy == 0.0d && myx == 0.0d) {
if (mxx == 1.0d && myy == 1.0d) {
Expand Down Expand Up @@ -489,16 +494,15 @@ static final class PathClipFilter implements DPathConsumer2D {

private final IndexStack stack;

// the outcode of the starting point
private int sOutCode = 0;

// the current outcode of the current sub path
private int cOutCode = 0;

// the cumulated (and) outcode of the complete path
private int gOutCode = MarlinConst.OUTCODE_MASK_T_B_L_R;

private boolean outside = false;

// The current point OUTSIDE
private double cx0, cy0;

PathClipFilter(final DRendererContext rdrCtx) {
Expand Down Expand Up @@ -541,25 +545,6 @@ void dispose() {
stack.dispose();
}

@Override
public void pathDone() {
finishPath();

out.pathDone();

// TODO: fix possible leak if exception happened
// Dispose this instance:
dispose();
}

@Override
public void closePath() {
finishPath();

out.closePath();
this.cOutCode = sOutCode;
}

private void finishPath() {
if (outside) {
// criteria: inside or totally outside ?
Expand Down Expand Up @@ -599,10 +584,29 @@ private void finish() {
out.lineTo(cx0, cy0);
}

@Override
public void pathDone() {
finishPath();

out.pathDone();

// TODO: fix possible leak if exception happened
// Dispose this instance:
dispose();
}

@Override
public void closePath() {
finishPath();

out.closePath();
}

@Override
public void moveTo(final double x0, final double y0) {
finishPath();

final int outcode = DHelpers.outcode(x0, y0, clipRect);
this.sOutCode = outcode;
this.cOutCode = outcode;
this.outside = false;
out.moveTo(x0, y0);
Expand Down Expand Up @@ -642,7 +646,7 @@ private void clip(final int sideCode,
{
// corner or cross-boundary on left or right side:
if ((outcode0 != outcode1)
&& ((sideCode & MarlinConst.OUTCODE_MASK_T_B) != 0))
&& ((sideCode & MarlinConst.OUTCODE_MASK_L_R) != 0))
{
// combine outcodes:
final int mergeCode = (outcode0 | outcode1);
Expand All @@ -653,18 +657,22 @@ private void clip(final int sideCode,
// add corners to outside stack:
switch (tbCode) {
case MarlinConst.OUTCODE_TOP:
// System.out.println("TOP "+ ((off == 0) ? "LEFT" : "RIGHT"));
stack.push(off); // top
return;
case MarlinConst.OUTCODE_BOTTOM:
// System.out.println("BOTTOM "+ ((off == 0) ? "LEFT" : "RIGHT"));
stack.push(off + 1); // bottom
return;
default:
// both TOP / BOTTOM:
if ((outcode0 & MarlinConst.OUTCODE_TOP) != 0) {
// System.out.println("TOP + BOTTOM "+ ((off == 0) ? "LEFT" : "RIGHT"));
// top to bottom
stack.push(off); // top
stack.push(off + 1); // bottom
} else {
// System.out.println("BOTTOM + TOP "+ ((off == 0) ? "LEFT" : "RIGHT"));
// bottom to top
stack.push(off + 1); // bottom
stack.push(off); // top
Expand Down
35 changes: 12 additions & 23 deletions src/main/java/org/marlin/pisces/MarlinRenderingEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,6 @@ abstract PathIterator getNormalizingPathIterator(RendererContext rdrCtx,

static final boolean DO_CLIP_RUNTIME_ENABLE = MarlinProperties.isDoClipRuntimeFlag();

static final boolean DO_CLIP_TEST = false;

/**
* Public constructor
*/
Expand Down Expand Up @@ -814,24 +812,10 @@ public AATileGenerator getAATileGenerator(Shape s,
// Define the initial clip bounds:
final float[] clipRect = rdrCtx.clipRect;

if (DO_CLIP_TEST) {
// clip rect area / 4 to see remaining paths after clipping:
float h = clip.getHeight();
float w = clip.getWidth();
final float cx = (clip.getLoX() + w) / 2.0f;
final float cy = (clip.getLoY() + h) / 2.0f;
h /= 4.0f;
w /= 4.0f;
clipRect[0] = cy - h;
clipRect[1] = cy + h;
clipRect[2] = cx - w;
clipRect[3] = cx + w;
} else {
clipRect[0] = clip.getLoY();
clipRect[1] = clip.getLoY() + clip.getHeight();
clipRect[2] = clip.getLoX();
clipRect[3] = clip.getLoX() + clip.getWidth();
}
clipRect[0] = clip.getLoY();
clipRect[1] = clip.getLoY() + clip.getHeight();
clipRect[2] = clip.getLoX();
clipRect[3] = clip.getLoX() + clip.getWidth();

// Enable clipping:
rdrCtx.doClip = true;
Expand All @@ -857,14 +841,19 @@ public AATileGenerator getAATileGenerator(Shape s,

PathConsumer2D pc2d = r;

if (DO_CLIP_FILL && (windingRule == WIND_NON_ZERO) && rdrCtx.doClip) {
if (DO_CLIP_FILL && rdrCtx.doClip) {
if (DO_TRACE_PATH) {
// trace Input:
pc2d = rdrCtx.transformerPC2D.traceInput(pc2d);
// trace Filler:
pc2d = rdrCtx.transformerPC2D.traceFiller(pc2d);
}
pc2d = rdrCtx.transformerPC2D.pathClipper(pc2d);
}

if (DO_TRACE_PATH) {
// trace Input:
pc2d = rdrCtx.transformerPC2D.traceInput(pc2d);
}

// TODO: subdivide quad/cubic curves into monotonic curves ?
pathTo(rdrCtx, pi, pc2d);

Expand Down
56 changes: 32 additions & 24 deletions src/main/java/org/marlin/pisces/TransformingPathConsumer2D.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ final class TransformingPathConsumer2D {
// recycled PathTracer instances from tracer...() methods
private final PathTracer tracerInput = new PathTracer("[Input]");
private final PathTracer tracerCPDetector = new PathTracer("ClosedPathDetector");
private final PathTracer tracerFiller = new PathTracer("Filler");
private final PathTracer tracerStroker = new PathTracer("Stroker");

TransformingPathConsumer2D(final RendererContext rdrCtx) {
Expand All @@ -77,6 +78,10 @@ PathConsumer2D traceClosedPathDetector(PathConsumer2D out) {
return tracerCPDetector.init(out);
}

PathConsumer2D traceFiller(PathConsumer2D out) {
return tracerFiller.init(out);
}

PathConsumer2D traceStroker(PathConsumer2D out) {
return tracerStroker.init(out);
}
Expand Down Expand Up @@ -490,16 +495,15 @@ static final class PathClipFilter implements PathConsumer2D {

private final IndexStack stack;

// the outcode of the starting point
private int sOutCode = 0;

// the current outcode of the current sub path
private int cOutCode = 0;

// the cumulated (and) outcode of the complete path
private int gOutCode = MarlinConst.OUTCODE_MASK_T_B_L_R;

private boolean outside = false;

// The current point OUTSIDE
private float cx0, cy0;

PathClipFilter(final RendererContext rdrCtx) {
Expand Down Expand Up @@ -542,25 +546,6 @@ void dispose() {
stack.dispose();
}

@Override
public void pathDone() {
finishPath();

out.pathDone();

// TODO: fix possible leak if exception happened
// Dispose this instance:
dispose();
}

@Override
public void closePath() {
finishPath();

out.closePath();
this.cOutCode = sOutCode;
}

private void finishPath() {
if (outside) {
// criteria: inside or totally outside ?
Expand Down Expand Up @@ -600,10 +585,29 @@ private void finish() {
out.lineTo(cx0, cy0);
}

@Override
public void pathDone() {
finishPath();

out.pathDone();

// TODO: fix possible leak if exception happened
// Dispose this instance:
dispose();
}

@Override
public void closePath() {
finishPath();

out.closePath();
}

@Override
public void moveTo(final float x0, final float y0) {
finishPath();

final int outcode = Helpers.outcode(x0, y0, clipRect);
this.sOutCode = outcode;
this.cOutCode = outcode;
this.outside = false;
out.moveTo(x0, y0);
Expand Down Expand Up @@ -643,7 +647,7 @@ private void clip(final int sideCode,
{
// corner or cross-boundary on left or right side:
if ((outcode0 != outcode1)
&& ((sideCode & MarlinConst.OUTCODE_MASK_T_B) != 0))
&& ((sideCode & MarlinConst.OUTCODE_MASK_L_R) != 0))
{
// combine outcodes:
final int mergeCode = (outcode0 | outcode1);
Expand All @@ -654,18 +658,22 @@ private void clip(final int sideCode,
// add corners to outside stack:
switch (tbCode) {
case MarlinConst.OUTCODE_TOP:
// System.out.println("TOP "+ ((off == 0) ? "LEFT" : "RIGHT"));
stack.push(off); // top
return;
case MarlinConst.OUTCODE_BOTTOM:
// System.out.println("BOTTOM "+ ((off == 0) ? "LEFT" : "RIGHT"));
stack.push(off + 1); // bottom
return;
default:
// both TOP / BOTTOM:
if ((outcode0 & MarlinConst.OUTCODE_TOP) != 0) {
// System.out.println("TOP + BOTTOM "+ ((off == 0) ? "LEFT" : "RIGHT"));
// top to bottom
stack.push(off); // top
stack.push(off + 1); // bottom
} else {
// System.out.println("BOTTOM + TOP "+ ((off == 0) ? "LEFT" : "RIGHT"));
// bottom to top
stack.push(off + 1); // bottom
stack.push(off); // top
Expand Down
Loading

0 comments on commit aafb87d

Please sign in to comment.