mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-09-25 03:50:44 +00:00
#559 morphshapes as animated SVG/CSS3: animate styles
This commit is contained in:
@@ -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";
|
||||
|
||||
Reference in New Issue
Block a user