package com.kreative.paint.draw;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
import java.awt.image.BufferedImage;
import com.kreative.paint.document.draw.PaintSettings;
import com.kreative.paint.document.draw.Path;
import com.kreative.paint.material.sprite.Sprite;
public class BrushStrokeDrawObject extends StrokeDrawObject {
private Sprite brush;
private transient BufferedImage cache;
private transient int cachex, cachey;
public BrushStrokeDrawObject(PaintSettings ps, Path path, Sprite brush) {
super(ps, path);
this.brush = brush;
this.cache = null;
}
public BrushStrokeDrawObject(PaintSettings ps, Shape path, Sprite brush) {
super(ps, path);
this.brush = brush;
this.cache = null;
}
private BrushStrokeDrawObject(BrushStrokeDrawObject o) {
super(o);
this.brush = o.brush;
this.cache = null;
}
@Override
public BrushStrokeDrawObject clone() {
return new BrushStrokeDrawObject(this);
}
@Override
protected void notifyDrawObjectListeners(int id) {
this.cache = null;
super.notifyDrawObjectListeners(id);
}
@Override
protected int getStrokeWidth() {
return Math.max(brush.getWidth(), brush.getHeight());
}
public Sprite getBrush() { return brush; }
@Override
protected void preTxPaintImpl(Graphics2D g, AffineTransform tx) {
if (cache == null) {
Shape s = path.toAWTShape();
if (tx != null) {
try { s = tx.createTransformedShape(s); }
catch (Exception e) { s = path.toAWTShape(); }
}
Rectangle b = s.getBounds();
this.cachex = b.x - brush.getWidth();
this.cachey = b.y - brush.getHeight();
this.cache = new BufferedImage(
b.width + brush.getWidth() * 2,
b.height + brush.getHeight() * 2,
BufferedImage.TYPE_INT_ARGB
);
if (ps.isFilled()) {
Graphics2D gc = cache.createGraphics();
gc.translate(-cachex, -cachey);
ps.applyFill(gc);
drag(gc, s);
gc.dispose();
}
}
g.drawImage(cache, null, cachex, cachey);
}
private void drag(Graphics2D g, Shape s) {
double sx = 0, sy = 0;
double cx = 0, cy = 0;
double[] c = new double[6];
for (PathIterator i = s.getPathIterator(null, 1); !i.isDone(); i.next()) {
switch (i.currentSegment(c)) {
case PathIterator.SEG_MOVETO:
sx = cx = c[0];
sy = cy = c[1];
break;
case PathIterator.SEG_LINETO:
drag(g, cx, cy, c[0], c[1]);
cx = c[0]; cy = c[1];
break;
case PathIterator.SEG_QUADTO:
drag(g, cx, cy, c[2], c[3]);
cx = c[2]; cy = c[3];
break;
case PathIterator.SEG_CUBICTO:
drag(g, cx, cy, c[4], c[5]);
cx = c[4]; cy = c[5];
break;
case PathIterator.SEG_CLOSE:
drag(g, cx, cy, sx, sy);
cx = sx; cy = sy;
break;
}
}
}
private void drag(Graphics2D g, double sx, double sy, double dx, double dy) {
int m = (int)Math.ceil(Math.max(Math.abs(dx - sx), Math.abs(dy - sy)));
for (int i = 0; i <= m; i++) {
double x = sx + ((dx - sx) * i) / m;
double y = sy + ((dy - sy) * i) / m;
brush.paint(g, (int)x, (int)y);
}
}
}