#559 morphshapes as animated SVG/CSS3: animate styles

This commit is contained in:
Honfika
2014-04-17 17:53:17 +02:00
parent c3bf4963b0
commit c9e4779224
5 changed files with 95 additions and 32 deletions
@@ -65,12 +65,12 @@ public abstract class DefaultSVGMorphShapeExporter extends MorphShapeExporterBas
}
@Override
public void beginFill(RGB color) {
public void beginFill(RGB color, RGB colorEnd) {
finalizePath();
}
@Override
public void beginGradientFill(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) {
public void beginGradientFill(int type, GRADRECORD[] gradientRecords, Matrix matrix, Matrix matrixEnd, int spreadMethod, int interpolationMethod, float focalPointRatio) {
finalizePath();
}
@@ -85,12 +85,12 @@ public abstract class DefaultSVGMorphShapeExporter extends MorphShapeExporterBas
}
@Override
public void lineStyle(double thickness, RGB color, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, int miterLimit) {
public void lineStyle(double thickness, double thicknessEnd, RGB color, RGB colorEnd, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, int miterLimit) {
finalizePath();
}
@Override
public void lineGradientStyle(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) {
public void lineGradientStyle(int type, GRADRECORD[] gradientRecords, Matrix matrix, Matrix matrixEnd, int spreadMethod, int interpolationMethod, float focalPointRatio) {
}
@Override
@@ -38,17 +38,17 @@ public interface IMorphShapeExporter {
public void endLines();
public void beginFill(RGB color);
public void beginFill(RGB color, RGB colorEnd);
public void beginGradientFill(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio);
public void beginGradientFill(int type, GRADRECORD[] gradientRecords, Matrix matrix, Matrix matrixEnd, int spreadMethod, int interpolationMethod, float focalPointRatio);
public void beginBitmapFill(int bitmapId, Matrix matrix, boolean repeat, boolean smooth, ColorTransform colorTransform);
public void endFill();
public void lineStyle(double thickness, RGB color, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, int miterLimit);
public void lineStyle(double thickness, double thicknessEnd, RGB color, RGB colorEnd, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, int miterLimit);
public void lineGradientStyle(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio);
public void lineGradientStyle(int type, GRADRECORD[] gradientRecords, Matrix matrix, Matrix matrixEnd, int spreadMethod, int interpolationMethod, float focalPointRatio);
public void moveTo(double x, double y, double x2, double y2);
@@ -82,7 +82,7 @@ public abstract class MorphShapeExporterBase implements IMorphShapeExporter {
// Create edge maps
_fillEdgeMaps = new ArrayList<>();
_lineEdgeMaps = new ArrayList<>();
createEdgeMaps(_fillStyles, _lineStyles, _fillEdgeMaps, _lineEdgeMaps);
createEdgeMaps(_fillStyles, _lineStyles, _fillStylesEnd, _lineStylesEnd, _fillEdgeMaps, _lineEdgeMaps);
// Let the doc handler know that a shape export starts
beginShape();
@@ -97,7 +97,8 @@ public abstract class MorphShapeExporterBase implements IMorphShapeExporter {
endShape();
}
protected void createEdgeMaps(List<FILLSTYLE> fillStyles, List<LINESTYLE> lineStyles,
protected void createEdgeMaps(List<FILLSTYLE> fillStyles, List<LINESTYLE> lineStyles,
List<FILLSTYLE> fillStylesEnd, List<LINESTYLE> lineStylesEnd,
List<Map<Integer, List<IMorphEdge>>> fillEdgeMaps, List<Map<Integer, List<IMorphEdge>>> lineEdgeMaps) {
if (!edgeMapsCreated) {
int xPos = 0;
@@ -137,6 +138,8 @@ public abstract class MorphShapeExporterBase implements IMorphShapeExporter {
lineStyleIdxOffset = lineStyles.size();
appendFillStyles(fillStyles, styleChangeRecord.fillStyles.fillStyles);
appendLineStyles(lineStyles, styleChangeRecord.lineStyles.lineStyles);
appendFillStyles(fillStylesEnd, styleChangeRecord.fillStyles.fillStyles);
appendLineStyles(lineStylesEnd, styleChangeRecord.lineStyles.lineStyles);
}
// Check if all styles are reset to 0.
// This (probably) means that a new group starts with the next record
@@ -294,21 +297,25 @@ public abstract class MorphShapeExporterBase implements IMorphShapeExporter {
pos = new PointInt(Integer.MAX_VALUE, Integer.MAX_VALUE);
try {
Matrix matrix;
Matrix matrixEnd;
FILLSTYLE fillStyle = _fillStyles.get(fillStyleIdx - 1);
FILLSTYLE fillStyleEnd = _fillStylesEnd.get(fillStyleIdx - 1);
switch (fillStyle.fillStyleType) {
case FILLSTYLE.SOLID:
// Solid fill
beginFill(colorTransform.apply(fillStyle.color));
beginFill(colorTransform.apply(fillStyle.color), colorTransform.apply(fillStyleEnd.color));
break;
case FILLSTYLE.LINEAR_GRADIENT:
case FILLSTYLE.RADIAL_GRADIENT:
case FILLSTYLE.FOCAL_RADIAL_GRADIENT:
// Gradient fill
matrix = new Matrix(fillStyle.gradientMatrix);
matrixEnd = new Matrix(fillStyleEnd.gradientMatrix);
beginGradientFill(
fillStyle.fillStyleType,
colorTransform.apply(fillStyle.gradient.gradientRecords),
matrix,
matrixEnd,
fillStyle.gradient.spreadMode,
fillStyle.gradient.interpolationMode,
(fillStyle.gradient instanceof FOCALGRADIENT) ? ((FOCALGRADIENT) fillStyle.gradient).focalPoint : 0
@@ -332,7 +339,7 @@ public abstract class MorphShapeExporterBase implements IMorphShapeExporter {
} catch (Exception ex) {
// Font shapes define no fillstyles per se, but do reference fillstyle index 1,
// which represents the font color. We just report null in this case.
beginFill(null);
beginFill(null, null);
}
}
if (!pos.equals(e.getFrom())) {
@@ -357,7 +364,6 @@ public abstract class MorphShapeExporterBase implements IMorphShapeExporter {
List<IMorphEdge> path = createPathFromEdgeMap(_lineEdgeMaps.get(groupIndex));
PointInt pos = new PointInt(Integer.MAX_VALUE, Integer.MAX_VALUE);
int lineStyleIdx = Integer.MAX_VALUE;
LINESTYLE lineStyle;
if (path.size() > 0) {
beginLines();
for (int i = 0; i < path.size(); i++) {
@@ -365,10 +371,12 @@ public abstract class MorphShapeExporterBase implements IMorphShapeExporter {
if (lineStyleIdx != e.getLineStyleIdx()) {
lineStyleIdx = e.getLineStyleIdx();
pos = new PointInt(Integer.MAX_VALUE, Integer.MAX_VALUE);
LINESTYLE lineStyle = null;
LINESTYLE lineStyleEnd = null;
try {
lineStyle = _lineStyles.get(lineStyleIdx - 1);
lineStyleEnd = _lineStylesEnd.get(lineStyleIdx - 1);
} catch (Exception ex) {
lineStyle = null;
}
if (lineStyle != null) {
String scaleMode = "NORMAL";
@@ -396,7 +404,9 @@ public abstract class MorphShapeExporterBase implements IMorphShapeExporter {
}
lineStyle(
lineStyle.width,
lineStyleEnd.width,
colorTransform.apply(lineStyle.color),
colorTransform.apply(lineStyleEnd.color),
pixelHintingFlag,
scaleMode,
startCapStyle,
@@ -407,16 +417,20 @@ public abstract class MorphShapeExporterBase implements IMorphShapeExporter {
if (hasFillFlag) {
LINESTYLE2 lineStyle2 = (LINESTYLE2) lineStyle;
FILLSTYLE fillStyle = lineStyle2.fillType;
LINESTYLE2 lineStyle2End = (LINESTYLE2) lineStyleEnd;
FILLSTYLE fillStyleEnd = lineStyle2End.fillType;
switch (fillStyle.fillStyleType) {
case FILLSTYLE.LINEAR_GRADIENT:
case FILLSTYLE.RADIAL_GRADIENT:
case FILLSTYLE.FOCAL_RADIAL_GRADIENT:
// Gradient fill
Matrix matrix = new Matrix(fillStyle.gradientMatrix);
Matrix matrixEnd = new Matrix(fillStyleEnd.gradientMatrix);
lineGradientStyle(
fillStyle.fillStyleType,
fillStyle.gradient.gradientRecords,
matrix,
matrixEnd,
fillStyle.gradient.spreadMode,
fillStyle.gradient.interpolationMode,
(fillStyle.gradient instanceof FOCALGRADIENT) ? ((FOCALGRADIENT) fillStyle.gradient).focalPoint : 0
@@ -426,7 +440,7 @@ public abstract class MorphShapeExporterBase implements IMorphShapeExporter {
}
} else {
// We should never get here
lineStyle(1, new RGB(Color.BLACK), false, "NORMAL", 0, 0, 0, 3);
lineStyle(1, 1, new RGB(Color.BLACK), new RGB(Color.BLACK), false, "NORMAL", 0, 0, 0, 3);
}
}
if (!e.getFrom().equals(pos)) {
@@ -120,13 +120,17 @@ public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter {
}
@Override
public void beginFill(RGB color) {
public void beginFill(RGB color, RGB colorEnd) {
if (color == null) {
color = new RGB(Color.BLACK);
}
if (colorEnd == null) {
colorEnd = new RGB(Color.BLACK);
}
finalizePath();
path.setAttribute("stroke", "none");
path.setAttribute("fill", color.toHexRGB());
path.appendChild(createAnimateElement("fill", color.toHexRGB(), colorEnd.toHexRGB()));
if (color instanceof RGBA) {
RGBA colorA = (RGBA) color;
if (colorA.alpha != 255) {
@@ -136,12 +140,12 @@ public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter {
}
@Override
public void beginGradientFill(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) {
public void beginGradientFill(int type, GRADRECORD[] gradientRecords, Matrix matrix, Matrix matrixEnd, int spreadMethod, int interpolationMethod, float focalPointRatio) {
finalizePath();
Element gradient = (type == FILLSTYLE.LINEAR_GRADIENT)
? _svg.createElement("linearGradient")
: _svg.createElement("radialGradient");
populateGradientElement(gradient, type, gradientRecords, matrix, spreadMethod, interpolationMethod, focalPointRatio);
populateGradientElement(gradient, type, gradientRecords, matrix, matrixEnd, spreadMethod, interpolationMethod, focalPointRatio);
int id = gradients.indexOf(gradient);
if (id < 0) {
// todo: filter same gradients
@@ -218,20 +222,26 @@ public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter {
}
@Override
public void lineStyle(double thickness, RGB color, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, int miterLimit) {
public void lineStyle(double thickness, double thicknessEnd, RGB color, RGB colorEnd, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, int miterLimit) {
finalizePath();
if (thickness > maxLineWidth) {
maxLineWidth = thickness;
}
thickness /= SWF.unitDivisor;
thicknessEnd /= SWF.unitDivisor;
path.setAttribute("fill", "none");
path.setAttribute("stroke", color.toHexRGB());
path.appendChild(createAnimateElement("stroke", color.toHexRGB(), colorEnd.toHexRGB()));
path.setAttribute("stroke-width", Double.toString(thickness == 0 ? 1 : thickness));
path.appendChild(createAnimateElement("stroke-width", thickness, thicknessEnd));
if (color instanceof RGBA) {
RGBA colorA = (RGBA) color;
if (colorA.alpha != 255) {
path.setAttribute("stroke-opacity", Float.toString(colorA.getAlphaFloat()));
}
RGBA colorAEnd = (RGBA) colorEnd;
path.appendChild(createAnimateElement("fill-opacity", colorA.getAlphaFloat(), colorAEnd.getAlphaFloat()));
}
switch (startCaps) {
case LINESTYLE2.NO_CAP:
@@ -261,12 +271,12 @@ public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter {
}
@Override
public void lineGradientStyle(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) {
public void lineGradientStyle(int type, GRADRECORD[] gradientRecords, Matrix matrix, Matrix matrixEnd, int spreadMethod, int interpolationMethod, float focalPointRatio) {
path.removeAttribute("stroke-opacity");
Element gradient = (type == FILLSTYLE.LINEAR_GRADIENT)
? _svg.createElement("linearGradient")
: _svg.createElement("radialGradient");
populateGradientElement(gradient, type, gradientRecords, matrix, spreadMethod, interpolationMethod, focalPointRatio);
populateGradientElement(gradient, type, gradientRecords, matrix, matrixEnd, spreadMethod, interpolationMethod, focalPointRatio);
int id = gradients.indexOf(gradient);
if (id < 0) {
// todo: filter same gradients
@@ -279,23 +289,27 @@ public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter {
_svgDefs.appendChild(gradient);
}
private Element createAnimateElement(String attributeName, Object startValue, Object endValue) {
Element animate = _svg.createElement("animate");
animate.setAttribute("dur", "2s"); // todo
animate.setAttribute("repeatCount", "indefinite");
animate.setAttribute("attributeName", attributeName);
animate.setAttribute("values", startValue + ";" + endValue);
return animate;
}
@Override
protected void finalizePath() {
if (path != null && !"".equals(pathData)) {
path.setAttribute("d", pathData.trim());
Element animatePath = _svg.createElement("animate");
animatePath.setAttribute("dur", "2s"); // todo
animatePath.setAttribute("repeatCount", "indefinite");
animatePath.setAttribute("attributeName", "d");
animatePath.setAttribute("values", pathData.trim() + ";" + pathDataEnd.trim());
path.appendChild(animatePath);
path.appendChild(createAnimateElement("d", pathData.trim(), pathDataEnd.trim()));
_svgG.appendChild(path);
}
path = _svg.createElement("path");
super.finalizePath();
}
protected void populateGradientElement(Element gradient, int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) {
protected void populateGradientElement(Element gradient, int type, GRADRECORD[] gradientRecords, Matrix matrix, Matrix matrixEnd, int spreadMethod, int interpolationMethod, float focalPointRatio) {
gradient.setAttribute("gradientUnits", "userSpaceOnUse");
if (type == FILLSTYLE.LINEAR_GRADIENT) {
gradient.setAttribute("x1", "-819.2");
@@ -330,8 +344,44 @@ public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter {
double rotateSkew1 = roundPixels400(matrix.rotateSkew1);
double scaleX = roundPixels400(matrix.scaleX);
double scaleY = roundPixels400(matrix.scaleY);
gradient.setAttribute("gradientTransform", "matrix(" + scaleX + ", " + rotateSkew0
+ ", " + rotateSkew1 + ", " + scaleY + ", " + translateX + ", " + translateY + ")");
String matrixStr = "matrix(" + scaleX + ", " + rotateSkew0
+ ", " + rotateSkew1 + ", " + scaleY + ", " + translateX + ", " + translateY + ")";
gradient.setAttribute("gradientTransform", matrixStr);
double translateXEnd = roundPixels400(matrixEnd.translateX / SWF.unitDivisor);
double translateYEnd = roundPixels400(matrixEnd.translateY / SWF.unitDivisor);
double rotateSkew0End = roundPixels400(matrixEnd.rotateSkew0);
double rotateSkew1End = roundPixels400(matrixEnd.rotateSkew1);
double scaleXEnd = roundPixels400(matrixEnd.scaleX);
double scaleYEnd = roundPixels400(matrixEnd.scaleY);
Element animateRotate = _svg.createElement("animateTransform");
animateRotate.setAttribute("dur", "2s"); // todo
animateRotate.setAttribute("repeatCount", "indefinite");
animateRotate.setAttribute("attributeName", "gradientTransform");
animateRotate.setAttribute("type", "rotate");
animateRotate.setAttribute("from", rotateSkew0 + " " + rotateSkew1);
animateRotate.setAttribute("to", rotateSkew0End + " " + rotateSkew1End);
Element animateScale = _svg.createElement("animateTransform");
animateScale.setAttribute("dur", "2s"); // todo
animateScale.setAttribute("repeatCount", "indefinite");
animateScale.setAttribute("attributeName", "gradientTransform");
animateScale.setAttribute("type", "scale");
animateScale.setAttribute("from", scaleX + " " + scaleY);
animateScale.setAttribute("to", scaleXEnd + " " + scaleYEnd);
Element animateTranslate = _svg.createElement("animateTransform");
animateTranslate.setAttribute("dur", "2s"); // todo
animateTranslate.setAttribute("repeatCount", "indefinite");
animateTranslate.setAttribute("attributeName", "gradientTransform");
animateTranslate.setAttribute("type", "translate");
animateTranslate.setAttribute("from", translateX + " " + translateY);
animateTranslate.setAttribute("to", translateXEnd + " " + translateYEnd);
gradient.appendChild(animateRotate);
gradient.appendChild(animateScale);
gradient.appendChild(animateTranslate);
}
for (int i = 0; i < gradientRecords.length; i++) {
GRADRECORD record = gradientRecords[i];
@@ -299,7 +299,6 @@ public abstract class ShapeExporterBase implements IShapeExporter {
List<IEdge> path = createPathFromEdgeMap(_lineEdgeMaps.get(groupIndex));
PointInt pos = new PointInt(Integer.MAX_VALUE, Integer.MAX_VALUE);
int lineStyleIdx = Integer.MAX_VALUE;
LINESTYLE lineStyle;
if (path.size() > 0) {
beginLines();
for (int i = 0; i < path.size(); i++) {
@@ -307,10 +306,10 @@ public abstract class ShapeExporterBase implements IShapeExporter {
if (lineStyleIdx != e.getLineStyleIdx()) {
lineStyleIdx = e.getLineStyleIdx();
pos = new PointInt(Integer.MAX_VALUE, Integer.MAX_VALUE);
LINESTYLE lineStyle = null;
try {
lineStyle = _lineStyles.get(lineStyleIdx - 1);
} catch (Exception ex) {
lineStyle = null;
}
if (lineStyle != null) {
String scaleMode = "NORMAL";