diff --git a/CHANGELOG.md b/CHANGELOG.md index e265e03f5..8fc2b6917 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,8 +11,9 @@ All notable changes to this project will be documented in this file. - ActionScript Debugger - Call stack frames switching - view variables around call stack - ActionScript Debugger - Highlight lines of callstack - [#2105] GFX - Basic tag info -- Context menu items to create new tags (shape, sprite, image, movie, sound, binaryData) from files +- Context menu items to create new tags (shape, morphshape, sprite, image, movie, sound, binaryData) from files and using font embed dialog for fonts +- Replacing morphshapes (currently only same shape for start/end) ### Fixed - [#1306], [#1768] Maximizing window on other than main monitor @@ -22,6 +23,7 @@ All notable changes to this project will be documented in this file. - GFX - Fonts with stripped shapes - [#2104] Empty texts import - Centered start playing triangle (Playing on demand) +- miterLimitFactor is FIXED8 value in MORPHLINESTYLE2 ### Changed - Basic tag info panel always visible even when nothing to display (to avoid flickering) diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java index 1ab543905..1a3ca32bf 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java @@ -3221,7 +3221,7 @@ public class SWFInputStream implements AutoCloseable { ret.noClose = (int) readUB(1, "noClose") == 1; ret.endCapStyle = (int) readUB(2, "endCapStyle"); if (ret.joinStyle == LINESTYLE2.MITER_JOIN) { - ret.miterLimitFactor = readUI16("miterLimitFactor"); + ret.miterLimitFactor = readFIXED8("miterLimitFactor"); } if (!ret.hasFillFlag) { ret.startColor = readRGBA("startColor"); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java index 2fc006c7f..cfc244081 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java @@ -1773,7 +1773,7 @@ public class SWFOutputStream extends OutputStream { writeUB(1, value.noClose ? 1 : 0); writeUB(2, value.endCapStyle); if (value.joinStyle == LINESTYLE2.MITER_JOIN) { - writeUI16(value.miterLimitFactor); + writeFIXED8(value.miterLimitFactor); } if (!value.hasFillFlag) { writeRGBA(value.startColor); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java index 17f387619..ddc340207 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java @@ -967,6 +967,11 @@ public final class Configuration { @ConfigurationDefaultBoolean(true) @ConfigurationCategory("ui") public static ConfigurationItem displayAs3PCodePanel = null; + + @ConfigurationDefaultBoolean(true) + @ConfigurationName("warning.replace.morphshape") + @ConfigurationCategory("ui") + public static ConfigurationItem warningReplaceMorphShape = null; private enum OSId { WINDOWS, OSX, UNIX diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ShapeImporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ShapeImporter.java index 21e85b4f1..c1248ec5d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ShapeImporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ShapeImporter.java @@ -31,6 +31,7 @@ import com.jpexs.decompiler.flash.tags.DefineShapeTag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.tags.base.MorphShapeTag; import com.jpexs.decompiler.flash.tags.base.ShapeTag; import com.jpexs.decompiler.flash.tags.enums.ImageFormat; import com.jpexs.decompiler.flash.types.RECT; @@ -57,22 +58,55 @@ import java.util.logging.Logger; public class ShapeImporter { public Tag importImage(ShapeTag st, byte[] newData) throws IOException { - return importImage(st, newData, 0, true); + return importImage((Tag) st, newData, 0, true); } + public Tag importImage(MorphShapeTag mst, byte[] newData) throws IOException { + return importImage((Tag) mst, newData, 0, true); + } + + public Tag importImage(MorphShapeTag mst, byte[] newData, int tagType, boolean fill) throws IOException { + return importImage((Tag) mst, newData, tagType, fill); + } + public Tag importImage(ShapeTag st, byte[] newData, int tagType, boolean fill) throws IOException { + return importImage((Tag) st, newData, tagType, fill); + } + + private Tag importImage(Tag st, byte[] newData, int tagType, boolean fill) throws IOException { ImageTag imageTag = addImage(st, newData, tagType); st.setModified(true); - RECT rect = st.getRect(); + RECT rect = null; + int shapeNum = 0; + if (st instanceof ShapeTag) { + rect = ((ShapeTag) st).getRect(); + shapeNum = ((ShapeTag) st).getShapeNum(); + } + if (st instanceof MorphShapeTag) { + rect = ((MorphShapeTag) st).getRect(); + int morphShapeNum = ((MorphShapeTag) st).getShapeNum(); + if (morphShapeNum == 2) { + shapeNum = 4; + } else { + shapeNum = 3; + } + } if (!fill) { Dimension dimension = imageTag.getImageDimension(); rect.Xmax = rect.Xmin + (int) (SWF.unitDivisor * dimension.getWidth()); rect.Ymax = rect.Ymin + (int) (SWF.unitDivisor * dimension.getHeight()); } - SHAPEWITHSTYLE shapes = imageTag.getShape(rect, fill, st.getShapeNum()); - st.shapes = shapes; + SHAPEWITHSTYLE shapes = imageTag.getShape(rect, fill, shapeNum); + if (st instanceof ShapeTag) { + ShapeTag shapeTag = (ShapeTag) st; + shapeTag.shapes = shapes; + } + if (st instanceof MorphShapeTag) { + MorphShapeTag morphShapeTag = (MorphShapeTag) st; + shapes.updateMorphShapeTag(morphShapeTag, fill); + } return (Tag) st; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/svg/SvgImporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/svg/SvgImporter.java index 9b43f0ea3..5e7035988 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/svg/SvgImporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/svg/SvgImporter.java @@ -28,9 +28,11 @@ import com.jpexs.decompiler.flash.importers.ShapeImporter; import com.jpexs.decompiler.flash.importers.svg.css.CssParseException; import com.jpexs.decompiler.flash.importers.svg.css.CssParser; import com.jpexs.decompiler.flash.importers.svg.css.CssSelectorToXPath; +import com.jpexs.decompiler.flash.tags.DefineMorphShape2Tag; import com.jpexs.decompiler.flash.tags.DefineShape4Tag; import com.jpexs.decompiler.flash.tags.ExportAssetsTag; import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.tags.base.MorphShapeTag; import com.jpexs.decompiler.flash.tags.base.ShapeTag; import com.jpexs.decompiler.flash.types.FILLSTYLE; import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY; @@ -91,16 +93,33 @@ public class SvgImporter { private final Set shownWarnings = new HashSet<>(); - ShapeTag shapeTag; - + /** + * Shape or morphshape tag + */ + Tag shapeTag; + private Rectangle2D.Double viewBox; - + public Tag importSvg(ShapeTag st, String svgXml) { - return importSvg(st, svgXml, true); + return importSvg((Tag) st, svgXml, true); } + public Tag importSvg(MorphShapeTag mst, String svgXml) { + return importSvg((Tag) mst, svgXml, true); + } + public Tag importSvg(ShapeTag st, String svgXml, boolean fill) { + return importSvg((Tag) st, svgXml, fill); + } + + public Tag importSvg(MorphShapeTag mst, String svgXml, boolean fill) { + return importSvg((Tag) mst, svgXml, fill); + } + + private Tag importSvg(Tag st, String svgXml, boolean fill) { shapeTag = st; + + boolean morphShape = st instanceof MorphShapeTag; if (st instanceof DefineShape4Tag) { DefineShape4Tag shape4 = (DefineShape4Tag) st; @@ -115,8 +134,23 @@ public class SvgImporter { shapes.fillStyles.fillStyles = new FILLSTYLE[0]; shapes.lineStyles.lineStyles = new LINESTYLE[0]; - int shapeNum = st.getShapeNum(); - RECT rect = st.getRect(); + int shapeNum = 0; + RECT rect = null; + + if (st instanceof ShapeTag) { + shapeNum = ((ShapeTag) st).getShapeNum(); + rect = ((ShapeTag) st).getRect(); + } + if (st instanceof MorphShapeTag) { + int morphShapeNum = ((MorphShapeTag) st).getShapeNum(); + if (morphShapeNum == 2) { + shapeNum = 4; + } else { + shapeNum = 3; + } + rect = ((MorphShapeTag) st).getRect(); + } + int origXmin = rect.Xmin; int origYmin = rect.Ymin; @@ -193,17 +227,24 @@ public class SvgImporter { transform.translate(origXmin / SWF.unitDivisor / ratioX, origYmin / SWF.unitDivisor / ratioY); } - processSvgObject(idMap, shapeNum, shapes, rootElement, transform, style); + processSvgObject(idMap, shapeNum, shapes, rootElement, transform, style, morphShape); } catch (SAXException | IOException | ParserConfigurationException ex) { Logger.getLogger(ShapeImporter.class.getName()).log(Level.SEVERE, null, ex); } shapes.shapeRecords.add(new EndShapeRecord()); - st.shapes = shapes; - if (!fill) { - st.updateBounds(); + if (st instanceof ShapeTag) { + ShapeTag shape = (ShapeTag) st; + shape.shapes = shapes; + if (!fill) { + shape.updateBounds(); + } } + if (st instanceof MorphShapeTag) { + shapes.updateMorphShapeTag((MorphShapeTag) st, fill); + } + st.setModified(true); return (Tag) st; @@ -272,7 +313,7 @@ public class SvgImporter { } } - private void processSwitch(Element element, Map idMap, int shapeNum, SHAPEWITHSTYLE shapes, Matrix transform, SvgStyle style) { + private void processSwitch(Element element, Map idMap, int shapeNum, SHAPEWITHSTYLE shapes, Matrix transform, SvgStyle style, boolean morphShape) { for (int i = 0; i < element.getChildNodes().getLength(); i++) { Node childNode = element.getChildNodes().item(i); if (childNode instanceof Element) { @@ -283,18 +324,18 @@ public class SvgImporter { if (childElement.hasAttribute("systemLanguage")) { String systemLanguage = childElement.getAttribute("systemLanguage"); if (systemLanguage.equals("en-us") || systemLanguage.equals("en")) { - processElement(childElement, idMap, shapeNum, shapes, transform, style); + processElement(childElement, idMap, shapeNum, shapes, transform, style, morphShape); return; } continue; } - processElement(childElement, idMap, shapeNum, shapes, transform, style); + processElement(childElement, idMap, shapeNum, shapes, transform, style, morphShape); return; } } } - private void processElement(Element element, Map idMap, int shapeNum, SHAPEWITHSTYLE shapes, Matrix transform, SvgStyle style) { + private void processElement(Element element, Map idMap, int shapeNum, SHAPEWITHSTYLE shapes, Matrix transform, SvgStyle style, boolean morphShape) { if (element.hasAttribute("requiredExtensions") && !element.getAttribute("requiredExtensions").isEmpty()) { return; } @@ -303,25 +344,25 @@ public class SvgImporter { Matrix m = Matrix.parseSvgMatrix(element.getAttribute("transform"), 1, 1); Matrix m2 = m == null ? transform : transform.concatenate(m); if ("switch".equals(tagName)) { - processSwitch(element, idMap, shapeNum, shapes, transform, style); + processSwitch(element, idMap, shapeNum, shapes, transform, style, morphShape); } else if ("style".equals(tagName)) { processStyle(element); } else if ("g".equals(tagName)) { - processSvgObject(idMap, shapeNum, shapes, element, m2, newStyle); + processSvgObject(idMap, shapeNum, shapes, element, m2, newStyle, morphShape); } else if ("path".equals(tagName)) { - processPath(shapeNum, shapes, element, m2, newStyle); + processPath(shapeNum, shapes, element, m2, newStyle, morphShape); } else if ("circle".equals(tagName)) { - processCircle(shapeNum, shapes, element, m2, newStyle); + processCircle(shapeNum, shapes, element, m2, newStyle, morphShape); } else if ("ellipse".equals(tagName)) { - processEllipse(shapeNum, shapes, element, m2, newStyle); + processEllipse(shapeNum, shapes, element, m2, newStyle, morphShape); } else if ("rect".equals(tagName)) { - processRect(shapeNum, shapes, element, m2, newStyle); + processRect(shapeNum, shapes, element, m2, newStyle, morphShape); } else if ("line".equals(tagName)) { - processLine(shapeNum, shapes, element, m2, newStyle); + processLine(shapeNum, shapes, element, m2, newStyle, morphShape); } else if ("polyline".equals(tagName)) { - processPolyline(shapeNum, shapes, element, m2, newStyle); + processPolyline(shapeNum, shapes, element, m2, newStyle, morphShape); } else if ("polygon".equals(tagName)) { - processPolygon(shapeNum, shapes, element, m2, newStyle); + processPolygon(shapeNum, shapes, element, m2, newStyle, morphShape); } else if ("defs".equals(tagName)) { processDefs(element); } else if ("title".equals(tagName) || "desc".equals(tagName) @@ -332,12 +373,12 @@ public class SvgImporter { } } - private void processSvgObject(Map idMap, int shapeNum, SHAPEWITHSTYLE shapes, Element element, Matrix transform, SvgStyle style) { + private void processSvgObject(Map idMap, int shapeNum, SHAPEWITHSTYLE shapes, Element element, Matrix transform, SvgStyle style, boolean morphShape) { for (int i = 0; i < element.getChildNodes().getLength(); i++) { Node childNode = element.getChildNodes().item(i); if (childNode instanceof Element) { Element childElement = (Element) childNode; - processElement(childElement, idMap, shapeNum, shapes, transform, style); + processElement(childElement, idMap, shapeNum, shapes, transform, style, morphShape); } } } @@ -372,7 +413,7 @@ public class SvgImporter { } } - private void processCommands(int shapeNum, SHAPEWITHSTYLE shapes, List commands, Matrix transform, SvgStyle style) { + private void processCommands(int shapeNum, SHAPEWITHSTYLE shapes, List commands, Matrix transform, SvgStyle style, boolean morphShape) { if ("nonzero".equals(style.getFillRule())) { if (shapeTag instanceof DefineShape4Tag) { @@ -387,14 +428,18 @@ public class SvgImporter { double x0 = 0; double y0 = 0; - StyleChangeRecord scrStyle = getStyleChangeRecord(shapeNum, style); - int fillStyle = scrStyle.fillStyle1; + StyleChangeRecord scrStyle = getStyleChangeRecord(shapeNum, style, morphShape); + int fillStyle = morphShape ? scrStyle.fillStyle0 : scrStyle.fillStyle1; int lineStyle = scrStyle.lineStyle; scrStyle.stateFillStyle0 = true; - scrStyle.stateFillStyle1 = true; + if (!morphShape) { + scrStyle.stateFillStyle1 = true; + } scrStyle.stateLineStyle = true; scrStyle.fillStyle0 = 0; - scrStyle.fillStyle1 = 0; + if (!morphShape) { + scrStyle.fillStyle1 = 0; + } scrStyle.lineStyle = 0; List newRecords = new ArrayList<>(); @@ -428,8 +473,13 @@ public class SvgImporter { StyleChangeRecord scr = new StyleChangeRecord(); if (fillStyle != 0) { - scr.stateFillStyle1 = true; - scr.fillStyle1 = fillStyle; + if (morphShape) { + scr.stateFillStyle0 = true; + scr.fillStyle0 = fillStyle; + } else { + scr.stateFillStyle1 = true; + scr.fillStyle1 = fillStyle; + } } if (lineStyle != 0) { scr.lineStyle = lineStyle; @@ -584,7 +634,7 @@ public class SvgImporter { shapes.shapeRecords.addAll(newRecords); } - private void processPath(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style) { + private void processPath(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style, boolean morphShape) { String data = childElement.getAttribute("d"); char command = 0; @@ -889,7 +939,7 @@ public class SvgImporter { // ignore remaining data as specified in SVG Specification F.2 Error processing } - processCommands(shapeNum, shapes, pathCommands, transform, style); + processCommands(shapeNum, shapes, pathCommands, transform, style, morphShape); } private double calcAngle(double ux, double uy, double vx, double vy) { @@ -903,7 +953,7 @@ public class SvgImporter { return sign * Math.acos(ux * vx + uy * vy / (lu * lv)); } - private void processCircle(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style) { + private void processCircle(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style, boolean morphShape) { String attr = childElement.getAttribute("cx"); double cx = attr.length() > 0 ? parseCoordinate(attr, viewBox.width) : 0; @@ -913,10 +963,10 @@ public class SvgImporter { attr = childElement.getAttribute("r"); double r = attr.length() > 0 ? parseLength(attr, (viewBox.width + viewBox.height) / 2) : 0; - processEllipse(shapeNum, shapes, transform, style, cx, cy, r, r); + processEllipse(shapeNum, shapes, transform, style, cx, cy, r, r, morphShape); } - private void processEllipse(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style) { + private void processEllipse(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style, boolean morphShape) { String attr = childElement.getAttribute("cx"); double cx = attr.length() > 0 ? parseCoordinate(attr, viewBox.width) : 0; @@ -929,10 +979,10 @@ public class SvgImporter { attr = childElement.getAttribute("ry"); double ry = attr.length() > 0 ? parseLength(attr, viewBox.height) : 0; - processEllipse(shapeNum, shapes, transform, style, cx, cy, rx, ry); + processEllipse(shapeNum, shapes, transform, style, cx, cy, rx, ry, morphShape); } - private void processEllipse(int shapeNum, SHAPEWITHSTYLE shapes, Matrix transform, SvgStyle style, double cx, double cy, double rx, double ry) { + private void processEllipse(int shapeNum, SHAPEWITHSTYLE shapes, Matrix transform, SvgStyle style, double cx, double cy, double rx, double ry, boolean morphShape) { double sqrt2RXHalf = Math.sqrt(2) * rx / 2; double sqrt2Minus1RX = (Math.sqrt(2) - 1) * rx; double sqrt2RYHalf = Math.sqrt(2) * ry / 2; @@ -987,10 +1037,10 @@ public class SvgImporter { serz.command = 'Z'; pathCommands.add(serz); - processCommands(shapeNum, shapes, pathCommands, transform, style); + processCommands(shapeNum, shapes, pathCommands, transform, style, morphShape); } - private void processRect(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style) { + private void processRect(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style, boolean morphShape) { String attr = childElement.getAttribute("x"); double x = attr.length() > 0 ? parseCoordinate(attr, viewBox.width) : 0; @@ -1098,10 +1148,10 @@ public class SvgImporter { serz.command = 'Z'; pathCommands.add(serz); - processCommands(shapeNum, shapes, pathCommands, transform, style); + processCommands(shapeNum, shapes, pathCommands, transform, style, morphShape); } - private void processLine(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style) { + private void processLine(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style, boolean morphShape) { String attr = childElement.getAttribute("x1"); double x1 = attr.length() > 0 ? parseCoordinate(attr, viewBox.width) : 0; @@ -1126,18 +1176,18 @@ public class SvgImporter { pathCommands.add(cer); - processCommands(shapeNum, shapes, pathCommands, transform, style); + processCommands(shapeNum, shapes, pathCommands, transform, style, morphShape); } - private void processPolygon(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style) { - processPolyline(shapeNum, shapes, childElement, transform, style, true); + private void processPolygon(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style, boolean morphShape) { + processPolyline(shapeNum, shapes, childElement, transform, style, true, morphShape); } - private void processPolyline(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style) { - processPolyline(shapeNum, shapes, childElement, transform, style, false); + private void processPolyline(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style, boolean morphShape) { + processPolyline(shapeNum, shapes, childElement, transform, style, false, morphShape); } - private void processPolyline(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style, boolean close) { + private void processPolyline(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style, boolean close, boolean morphShape) { String data = childElement.getAttribute("points"); char command = 'M'; @@ -1187,7 +1237,7 @@ public class SvgImporter { pathCommands.add(serz); } - processCommands(shapeNum, shapes, pathCommands, transform, style); + processCommands(shapeNum, shapes, pathCommands, transform, style, morphShape); } //Stub for w3 test. TODO: refactor and move to test directory. It's here because of easy access - compiling single file @@ -1671,12 +1721,16 @@ public class SvgImporter { } } - private StyleChangeRecord getStyleChangeRecord(int shapeNum, SvgStyle style) { + private StyleChangeRecord getStyleChangeRecord(int shapeNum, SvgStyle style, boolean morphShape) { StyleChangeRecord scr = new StyleChangeRecord(); scr.stateNewStyles = true; scr.fillStyles = new FILLSTYLEARRAY(); - scr.stateFillStyle1 = true; + if (morphShape) { + scr.stateFillStyle0 = true; + } else { + scr.stateFillStyle1 = true; + } scr.stateLineStyle = true; SvgFill fill = style.getFillWithOpacity(); if (fill != null && fill != SvgTransparentFill.INSTANCE) { @@ -1690,10 +1744,18 @@ public class SvgImporter { //...apply in second step - applyStyleGradients } - scr.fillStyle1 = 1; + if (morphShape) { + scr.fillStyle0 = 1; + } else { + scr.fillStyle1 = 1; + } } else { scr.fillStyles.fillStyles = new FILLSTYLE[0]; - scr.fillStyle1 = 0; + if (morphShape) { + scr.fillStyle0 = 0; + } else { + scr.fillStyle1 = 0; + } } scr.lineStyles = new LINESTYLEARRAY(); @@ -1717,11 +1779,19 @@ public class SvgImporter { DefineShape4Tag shape4 = (DefineShape4Tag) shapeTag; shape4.usesNonScalingStrokes = true; } + if (shapeTag instanceof DefineMorphShape2Tag) { + DefineMorphShape2Tag morph2 = (DefineMorphShape2Tag) shapeTag; + morph2.usesNonScalingStrokes = true; + } } else { if (shapeTag instanceof DefineShape4Tag) { DefineShape4Tag shape4 = (DefineShape4Tag) shapeTag; shape4.usesScalingStrokes = true; } + if (shapeTag instanceof DefineMorphShape2Tag) { + DefineMorphShape2Tag morph2 = (DefineMorphShape2Tag) shapeTag; + morph2.usesScalingStrokes = true; + } } int swfCap = lineCap == SvgLineCap.BUTT ? LINESTYLE2.NO_CAP diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FILLSTYLE.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FILLSTYLE.java index cb313dfe3..99bb5a55a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FILLSTYLE.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FILLSTYLE.java @@ -152,4 +152,23 @@ public class FILLSTYLE implements NeedsCharacters, FieldChangeObserver, Serializ } } } + + public MORPHFILLSTYLE toMorphStyle() { + MORPHFILLSTYLE morphFillStyle = new MORPHFILLSTYLE(); + morphFillStyle.bitmapId = bitmapId; + if (bitmapMatrix != null) { + morphFillStyle.startBitmapMatrix = new MATRIX(bitmapMatrix); + morphFillStyle.endBitmapMatrix = new MATRIX(bitmapMatrix); + } + if (color != null) { + morphFillStyle.startColor = new RGBA(color); + morphFillStyle.endColor = new RGBA(color); + } + morphFillStyle.fillStyleType = fillStyleType; + if (gradient != null) { + morphFillStyle.gradient = gradient.toMorphGradient(); + } + + return morphFillStyle; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FILLSTYLEARRAY.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FILLSTYLEARRAY.java index d634018fa..26751b13a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FILLSTYLEARRAY.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FILLSTYLEARRAY.java @@ -55,4 +55,13 @@ public class FILLSTYLEARRAY implements NeedsCharacters, Serializable { } return modified; } + + public MORPHFILLSTYLEARRAY toMorphFillStyleArray() { + MORPHFILLSTYLEARRAY morphFillStyleArray = new MORPHFILLSTYLEARRAY(); + morphFillStyleArray.fillStyles = new MORPHFILLSTYLE[fillStyles.length]; + for (int i = 0; i < fillStyles.length; i++) { + morphFillStyleArray.fillStyles[i] = fillStyles[i].toMorphStyle(); + } + return morphFillStyleArray; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/GRADIENT.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/GRADIENT.java index 27d6629fa..814a9bb2b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/GRADIENT.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/GRADIENT.java @@ -62,4 +62,15 @@ public class GRADIENT implements Serializable { @SWFArray(value = "record") public GRADRECORD[] gradientRecords = new GRADRECORD[0]; + + public MORPHGRADIENT toMorphGradient() { + MORPHGRADIENT morphGradient = new MORPHGRADIENT(); + morphGradient.interPolationMode = interpolationMode; + morphGradient.spreadMode = spreadMode; + morphGradient.gradientRecords = new MORPHGRADRECORD[gradientRecords.length]; + for (int i = 0; i < gradientRecords.length; i++) { + morphGradient.gradientRecords[i] = gradientRecords[i].toMorphGradRecord(); + } + return morphGradient; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/GRADRECORD.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/GRADRECORD.java index 5e7b85b80..947d02a06 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/GRADRECORD.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/GRADRECORD.java @@ -37,4 +37,13 @@ public class GRADRECORD implements Serializable { public float getRatioFloat() { return ((float) ratio) / 255.0f; } + + public MORPHGRADRECORD toMorphGradRecord() { + MORPHGRADRECORD morphGradRecord = new MORPHGRADRECORD(); + morphGradRecord.startColor = new RGBA(color); + morphGradRecord.endColor = new RGBA(color); + morphGradRecord.startRatio = ratio; + morphGradRecord.endRatio = ratio; + return morphGradRecord; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE.java index 320d762bc..1f36aba2e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE.java @@ -75,4 +75,13 @@ public class LINESTYLE implements NeedsCharacters, Serializable, ILINESTYLE { public void setWidth(int width) { this.width = width; } + + public MORPHLINESTYLE toMorphLineStyle() { + MORPHLINESTYLE morphLineStyle = new MORPHLINESTYLE(); + morphLineStyle.startColor = new RGBA(color); + morphLineStyle.endColor = new RGBA(color); + morphLineStyle.startWidth = width; + morphLineStyle.endWidth = width; + return morphLineStyle; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE2.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE2.java index 6c0b22c73..b5574e614 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE2.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE2.java @@ -142,4 +142,27 @@ public class LINESTYLE2 implements NeedsCharacters, Serializable, ILINESTYLE { public void setWidth(int width) { this.width = width; } + + public MORPHLINESTYLE2 toMorphLineStyle2() { + MORPHLINESTYLE2 morphLineStyle2 = new MORPHLINESTYLE2(); + morphLineStyle2.startWidth = width; + morphLineStyle2.endWidth = width; + morphLineStyle2.startCapStyle = startCapStyle; + morphLineStyle2.joinStyle = joinStyle; + morphLineStyle2.hasFillFlag = hasFillFlag; + morphLineStyle2.noHScaleFlag = noHScaleFlag; + morphLineStyle2.noVScaleFlag = noVScaleFlag; + morphLineStyle2.pixelHintingFlag = pixelHintingFlag; + morphLineStyle2.noClose = noClose; + morphLineStyle2.endCapStyle = endCapStyle; + morphLineStyle2.miterLimitFactor = miterLimitFactor; + if (color != null) { + morphLineStyle2.startColor = new RGBA(color); + morphLineStyle2.endColor = new RGBA(color); + } + if (fillType != null) { + morphLineStyle2.fillType = fillType.toMorphStyle(); + } + return morphLineStyle2; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLEARRAY.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLEARRAY.java index f5a7d1d26..1eb209cb6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLEARRAY.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLEARRAY.java @@ -87,4 +87,21 @@ public class LINESTYLEARRAY implements NeedsCharacters, Serializable { } return modified; } + + public MORPHLINESTYLEARRAY toMorphLineStyleArray() { + MORPHLINESTYLEARRAY morphLineStyleArray = new MORPHLINESTYLEARRAY(); + if (lineStyles != null) { + morphLineStyleArray.lineStyles = new MORPHLINESTYLE[lineStyles.length]; + for (int i = 0; i < lineStyles.length; i++) { + morphLineStyleArray.lineStyles[i] = lineStyles[i].toMorphLineStyle(); + } + } + if (lineStyles2 != null) { + morphLineStyleArray.lineStyles2 = new MORPHLINESTYLE2[lineStyles2.length]; + for (int i = 0; i < lineStyles2.length; i++) { + morphLineStyleArray.lineStyles2[i] = lineStyles2[i].toMorphLineStyle2(); + } + } + return morphLineStyleArray; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/MORPHLINESTYLE2.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/MORPHLINESTYLE2.java index 433e67a8d..24cf222cd 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/MORPHLINESTYLE2.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/MORPHLINESTYLE2.java @@ -78,9 +78,9 @@ public class MORPHLINESTYLE2 implements Serializable { public static final int SQUARE_CAP = 2; - @SWFType(value = BasicType.UI16) + @SWFType(value = BasicType.FIXED8) @Conditional(value = "joinStyle", options = {MITER_JOIN}) - public int miterLimitFactor; + public float miterLimitFactor; @Conditional("!hasFillFlag") public RGBA startColor; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/RGB.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/RGB.java index ef1c3cfc4..4b0055500 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/RGB.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/RGB.java @@ -46,6 +46,12 @@ public class RGB implements Serializable { @SWFType(BasicType.UI8) public int blue; + public RGB(RGB color) { + this.red = color.red; + this.green = color.green; + this.blue = color.blue; + } + public RGB(int red, int green, int blue) { this.red = red; this.green = green; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/RGBA.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/RGBA.java index 06886ac0b..2624db49d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/RGBA.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/RGBA.java @@ -72,6 +72,15 @@ public class RGBA extends RGB implements Serializable { super(rgb); alpha = (rgb >> 24) & 0xFF; } + + public RGBA(RGB color) { + super(color); + if (color instanceof RGBA) { + alpha = ((RGBA) color).alpha; + } else { + alpha = 255; + } + } public RGBA() { } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/SHAPEWITHSTYLE.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/SHAPEWITHSTYLE.java index e43209712..8c3bbbce8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/SHAPEWITHSTYLE.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/SHAPEWITHSTYLE.java @@ -17,9 +17,13 @@ package com.jpexs.decompiler.flash.types; import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.tags.base.MorphShapeTag; import com.jpexs.decompiler.flash.tags.base.NeedsCharacters; import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord; import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; +import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord; +import com.jpexs.helpers.Helper; import java.io.Serializable; import java.util.ArrayList; import java.util.List; @@ -104,4 +108,129 @@ public class SHAPEWITHSTYLE extends SHAPE implements NeedsCharacters, Serializab return SHAPERECORD.getBounds(shapeRecords, lineStyles, shapeNum, false); } + public void updateMorphShapeTag(MorphShapeTag morphShapeTag, boolean fill) { + morphShapeTag.startEdges.shapeRecords.clear(); + morphShapeTag.endEdges.shapeRecords.clear(); + + FILLSTYLEARRAY mergedFillStyles = new FILLSTYLEARRAY(); + LINESTYLEARRAY mergedLineStyles = new LINESTYLEARRAY(); + + List mergedFillStyleList = new ArrayList<>(); + List mergedLineStyleList = new ArrayList<>(); + List mergedLineStyle2List = new ArrayList<>(); + + int lastFillCount = fillStyles.fillStyles.length; + + for (int i = 0; i < fillStyles.fillStyles.length; i++) { + mergedFillStyleList.add(fillStyles.fillStyles[i]); + } + + int lastLineCount = 0; + + if (lineStyles.lineStyles != null) { + lastLineCount = lineStyles.lineStyles.length; + for (int i = 0; i < lineStyles.lineStyles.length; i++) { + mergedLineStyleList.add(lineStyles.lineStyles[i]); + } + } + if (lineStyles.lineStyles2 != null) { + lastLineCount = lineStyles.lineStyles2.length; + for (int i = 0; i < lineStyles.lineStyles2.length; i++) { + mergedLineStyle2List.add(lineStyles.lineStyles2[i]); + } + } + + int fillOffset = 0; + int lineOffset = 0; + List newShapeRecords = new ArrayList<>(); + for (int r = 0; r < shapeRecords.size(); r++) { + SHAPERECORD rec = shapeRecords.get(r); + rec = Helper.deepCopy(rec); + if (rec instanceof StyleChangeRecord) { + StyleChangeRecord scr = (StyleChangeRecord) rec; + if (scr.stateNewStyles) { + for (int i = 0; i < scr.fillStyles.fillStyles.length; i++) { + mergedFillStyleList.add(scr.fillStyles.fillStyles[i]); + } + fillOffset += lastFillCount; + lastFillCount = scr.fillStyles.fillStyles.length; + if (scr.lineStyles.lineStyles != null) { + for (int i = 0; i < scr.lineStyles.lineStyles.length; i++) { + mergedLineStyleList.add(scr.lineStyles.lineStyles[i]); + } + lineOffset += lastLineCount; + lastLineCount = scr.lineStyles.lineStyles.length; + } + if (scr.lineStyles.lineStyles2 != null) { + for (int i = 0; i < scr.lineStyles.lineStyles2.length; i++) { + mergedLineStyle2List.add(scr.lineStyles.lineStyles2[i]); + } + lineOffset += lastLineCount; + lastLineCount = scr.lineStyles.lineStyles2.length; + } + scr.stateNewStyles = false; + } + if (scr.stateFillStyle0) { + scr.fillStyle0 += fillOffset; + } + if (scr.stateFillStyle1) { + scr.fillStyle1 += fillOffset; + } + if (scr.stateLineStyle) { + scr.lineStyle += lineOffset; + } + } + newShapeRecords.add(rec); + } + + mergedFillStyles.fillStyles = new FILLSTYLE[mergedFillStyleList.size()]; + for (int i = 0; i < mergedFillStyleList.size(); i++) { + mergedFillStyles.fillStyles[i] = mergedFillStyleList.get(i); + } + mergedLineStyles.lineStyles = new LINESTYLE[mergedLineStyleList.size()]; + for (int i = 0; i < mergedLineStyleList.size(); i++) { + mergedLineStyles.lineStyles[i] = mergedLineStyleList.get(i); + } + mergedLineStyles.lineStyles2 = new LINESTYLE2[mergedLineStyle2List.size()]; + for (int i = 0; i < mergedLineStyle2List.size(); i++) { + mergedLineStyles.lineStyles2[i] = mergedLineStyle2List.get(i); + } + + + morphShapeTag.morphFillStyles = mergedFillStyles.toMorphFillStyleArray(); + morphShapeTag.morphLineStyles = mergedLineStyles.toMorphLineStyleArray(); + SHAPE startShapes = new SHAPE(); + startShapes.numFillBits = SWFOutputStream.getNeededBitsU(mergedFillStyleList.size()); + startShapes.numLineBits = SWFOutputStream.getNeededBitsU(mergedLineStyleList.size() + mergedLineStyle2List.size()); + startShapes.shapeRecords = newShapeRecords; + morphShapeTag.startEdges = startShapes; + + SHAPE endShapes = new SHAPE(); + endShapes.numFillBits = 0; + endShapes.numLineBits = 0; + List endRecords = new ArrayList<>(); + for (int i = 0; i < newShapeRecords.size(); i++) { + SHAPERECORD rec = newShapeRecords.get(i); + if (rec instanceof StyleChangeRecord) { + StyleChangeRecord scr = (StyleChangeRecord) rec; + if (scr.stateMoveTo) { + StyleChangeRecord nscr = new StyleChangeRecord(); + nscr.stateMoveTo = true; + nscr.moveDeltaX = scr.moveDeltaX; + nscr.moveDeltaY = scr.moveDeltaY; + nscr.calculateBits(); + endRecords.add(nscr); + } + } else { + endRecords.add(Helper.deepCopy(rec)); + } + } + endShapes.shapeRecords = endRecords; + morphShapeTag.endEdges = endShapes; + + if (!fill) { + morphShapeTag.updateBounds(); + } + } + } diff --git a/src/com/jpexs/decompiler/flash/gui/Main.java b/src/com/jpexs/decompiler/flash/gui/Main.java index 2f0fe453a..c87f7f766 100644 --- a/src/com/jpexs/decompiler/flash/gui/Main.java +++ b/src/com/jpexs/decompiler/flash/gui/Main.java @@ -826,7 +826,11 @@ public class Main { statusTimer.schedule(new TimerTask() { @Override public void run() { - if (mainFrame != null && mainFrame.getPanel().getStatusPanel().isStatusHidden()) { + if (mainFrame == null) { + return; + } + MainFrameStatusPanel sp = mainFrame.getPanel().getStatusPanel(); + if (sp != null && sp.isStatusHidden()) { long nowTime = System.currentTimeMillis(); if (nowTime > lastTimeStartWork + 5000) { mainFrame.getPanel().showOldStatus(); diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index 003e03c8d..0a919c411 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -4441,6 +4441,12 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se if (ti0 instanceof ShapeTag) { file = showImportFileChooser("filter.images|*.jpg;*.jpeg;*.gif;*.png;*.bmp;*.svg", true); } + if (ti0 instanceof MorphShapeTag) { + if (ViewMessages.showConfirmDialog(this, AppStrings.translate("warning.replace.morphshape"), AppStrings.translate("message.warning"), JOptionPane.WARNING_MESSAGE, JOptionPane.WARNING_MESSAGE, Configuration.warningReplaceMorphShape, JOptionPane.OK_OPTION) != JOptionPane.OK_OPTION) { + return false; + } + file = showImportFileChooser("filter.images|*.jpg;*.jpeg;*.gif;*.png;*.bmp;*.svg", true); + } if (ti0 instanceof DefineVideoStreamTag) { file = showImportFileChooser("filter.movies|*.flv", false); } @@ -4520,8 +4526,8 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se reload(true); } } - if (item instanceof ShapeTag) { - ShapeTag st = (ShapeTag) item; + if ((item instanceof ShapeTag) || (item instanceof MorphShapeTag)) { + Tag st = (Tag) item; File selfile = Helper.fixDialogFile(selectedFile); byte[] data = null; String svgText = null; @@ -4532,7 +4538,21 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se data = Helper.readFile(selfile.getAbsolutePath()); } try { - Tag newTag = svgText != null ? new SvgImporter().importSvg(st, svgText) : new ShapeImporter().importImage(st, data); + Tag newTag = null; + if (st instanceof ShapeTag) { + if (svgText != null) { + newTag = new SvgImporter().importSvg((ShapeTag) st, svgText); + } else { + newTag = new ShapeImporter().importImage((ShapeTag) st, data); + } + } + if (st instanceof MorphShapeTag) { + if (svgText != null) { + newTag = new SvgImporter().importSvg((MorphShapeTag) st, svgText); + } else { + newTag = new ShapeImporter().importImage((MorphShapeTag) st, data); + } + } SWF swf = st.getSwf(); if (newTag != null) { refreshTree(swf); @@ -4622,8 +4642,8 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se return false; } - if (item instanceof ShapeTag) { - ShapeTag st = (ShapeTag) item; + if ((item instanceof ShapeTag) || (item instanceof MorphShapeTag)) { + Tag st = (Tag) item; String filter = "filter.images|*.jpg;*.jpeg;*.gif;*.png;*.bmp;*.svg"; File selectedFile = showImportFileChooser(filter, true); if (selectedFile != null) { @@ -4637,7 +4657,21 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se data = Helper.readFile(selfile.getAbsolutePath()); } try { - Tag newTag = svgText != null ? new SvgImporter().importSvg(st, svgText, false) : new ShapeImporter().importImage(st, data, 0, false); + Tag newTag = null; + if (st instanceof ShapeTag) { + if (svgText != null) { + newTag = new SvgImporter().importSvg((ShapeTag) st, svgText, false); + } else { + newTag = new ShapeImporter().importImage((ShapeTag) st, data, 0, false); + } + } + if (st instanceof MorphShapeTag) { + if (svgText != null) { + newTag = new SvgImporter().importSvg((MorphShapeTag) st, svgText, false); + } else { + newTag = new ShapeImporter().importImage((MorphShapeTag) st, data, 0, false); + } + } SWF swf = st.getSwf(); if (newTag != null) { refreshTree(swf); diff --git a/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java b/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java index efe30e35d..23306f6ae 100644 --- a/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java @@ -1718,14 +1718,15 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel showSound = false; showMovie = false; showSprite = false; + showMorphShape = false; } replaceImageButton.setVisible(showImage); replaceImageAlphaButton.setVisible(showAlpha); replaceSpriteButton.setVisible(showSprite); - replaceShapeButton.setVisible(showShape); + replaceShapeButton.setVisible(showShape || showMorphShape); morphShowPanel.setVisible(showMorphShape); displayEditEditPointsButton.setVisible(showShape || showMorphShape); - replaceShapeUpdateBoundsButton.setVisible(showShape); + replaceShapeUpdateBoundsButton.setVisible(showShape || showMorphShape); replaceSoundButton.setVisible(showSound); replaceMovieButton.setVisible(showMovie); prevFontsButton.setVisible(false); diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/importmorphshape16.png b/src/com/jpexs/decompiler/flash/gui/graphics/importmorphshape16.png new file mode 100644 index 000000000..9a6e40d07 Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/importmorphshape16.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/importmorphshape32.png b/src/com/jpexs/decompiler/flash/gui/graphics/importmorphshape32.png new file mode 100644 index 000000000..18e61ee4e Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/importmorphshape32.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties index 251ce3c38..e5026cd7f 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties @@ -740,3 +740,6 @@ config.description.displayAs12PCodePanel = Show panel with disassembled P-code a config.name.displayAs3PCodePanel = Show AS3 P-code panel config.description.displayAs3PCodePanel = Show panel with disassembled P-code instructions for ActionScript 3 + +config.name.warning.replace.morphshape = Warn on replace morphshape +config.description.warning.replace.morphshape = Show warning on replacing morphshape about same start and end shape diff --git a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties index 0c7dbfc37..e1249c89c 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties @@ -730,3 +730,6 @@ config.description.displayAs12PCodePanel = Zobrazit panel s akcemi disassemblova config.name.displayAs3PCodePanel = Zobrazit AS3 panel s P-k\u00f3dem config.description.displayAs3PCodePanel = Zobrazit panel s instrukcemi disassemblovan\u00e9ho P-k\u00f3du pro ActionScript 3 + +config.name.warning.replace.morphshape = Varovat p\u0159i nahrazov\u00e1n\u00ed morphshape +config.description.warning.replace.morphshape = Zobrazovat varov\u00e1n\u00ed p\u0159i nahrazov\u00e1n\u00ed morphshape o tom, \u017ee bude startov\u00e1n\u00ed a koncov\u00fd tvar stejn\u00fd diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties index 908841773..d29a8f8a5 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties @@ -1197,10 +1197,15 @@ tagInfo.nominalGlyphSz = Nominal glyph size tagInfo.glyphCount = Glyph count tagInfo.fontCount = Font count -tag.shape.create = create shape from file... -tag.image.create = create image from file... -tag.sprite.create = create sprite from GIF file... -tag.movie.create = create movie from file... -tag.sound.create = create sound from file... -tag.font.create = create font using dialog... -tag.binaryData.create = create binary data from file... \ No newline at end of file +tag.shape.create = Create shape from file... +tag.image.create = Create image from file... +tag.sprite.create = Create sprite from GIF file... +tag.movie.create = Create movie from file... +tag.sound.create = Create sound from file... +tag.font.create = Create font using dialog... +tag.binaryData.create = Create binary data from file... +tag.morphshape.create = Create morphshape from shape file... + +warning.replace.morphshape = In the following dialog you select a shape file.\r\n \ + That shape would be set as start and also the end shape of the morphshape.\r\n\ + You won't see any morphing animation until you edit start/end shape to be different. \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties index 7d4c6ea9e..5f96d7ea7 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties @@ -1174,10 +1174,15 @@ tagInfo.nominalGlyphSz = Nomin\u00e1ln\u00ed velikost glyfu tagInfo.glyphCount = Po\u010det glyf\u016f tagInfo.fontCount = Po\u010det p\u00edsem -tag.shape.create = vytvo\u0159it tvar ze souboru... -tag.image.create = vytvo\u0159it obr\u00e1zek ze souboru... -tag.sprite.create = vytvo\u0159it sprite z GIF souboru... -tag.movie.create = vytvo\u0159it video ze souboru... -tag.sound.create = vytvo\u0159it zvuk ze souboru... -tag.font.create = vytvo\u0159it p\u00edsmo pomoc\u00ed dialogu... -tag.binaryData.create = vytvo\u0159it bin\u00e1rn\u00ed data ze souboru... \ No newline at end of file +tag.shape.create = Vytvo\u0159it tvar ze souboru... +tag.image.create = Vytvo\u0159it obr\u00e1zek ze souboru... +tag.sprite.create = Vytvo\u0159it sprite z GIF souboru... +tag.movie.create = Vytvo\u0159it video ze souboru... +tag.sound.create = Vytvo\u0159it zvuk ze souboru... +tag.font.create = Vytvo\u0159it p\u00edsmo pomoc\u00ed dialogu... +tag.binaryData.create = Vytvo\u0159it bin\u00e1rn\u00ed data ze souboru... +tag.morphshape.create = Vytvo\u0159it morphshape ze souboru tvaru... + +warning.replace.morphshape = V n\u00e1sleduj\u00edc\u00edm dialogu vyberete soubor s tvarem.\r\n \ + Ten tvar bude nastaven jako po\u010d\u00e1te\u010dn\u00ed a tak\u00e9 koncov\u00fd tvar tohot morphshape.\r\n\ + Neuvid\u00edte \u017e\u00e1dnou morfuj\u00edc\u00ed animaci do doby ne\u017e uprav\u00edte po\u010d\u00e1te\u010dn\u00ed/koncov\u00fd tvar tak, aby byly odli\u0161n\u00e9. \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java index 12de08bd9..ce15587b4 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java @@ -50,6 +50,7 @@ import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag; import com.jpexs.decompiler.flash.tags.DefineBitsLossless2Tag; import com.jpexs.decompiler.flash.tags.DefineButton2Tag; import com.jpexs.decompiler.flash.tags.DefineFont3Tag; +import com.jpexs.decompiler.flash.tags.DefineMorphShape2Tag; import com.jpexs.decompiler.flash.tags.DefineShape4Tag; import com.jpexs.decompiler.flash.tags.DefineSoundTag; import com.jpexs.decompiler.flash.tags.DefineSpriteTag; @@ -71,6 +72,7 @@ import com.jpexs.decompiler.flash.tags.base.ButtonTag; import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.tags.base.MorphShapeTag; import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag; import com.jpexs.decompiler.flash.tags.base.ShapeTag; import com.jpexs.decompiler.flash.tags.base.SoundTag; @@ -1037,7 +1039,7 @@ public class TagTreeContextMenu extends JPopupMenu { replaceMenuItem.setVisible(true); } - if (canReplace.test(it -> it instanceof ShapeTag)) { + if (canReplace.test(it -> (it instanceof ShapeTag) || (it instanceof MorphShapeTag))) { replaceMenuItem.setVisible(true); replaceNoFillMenuItem.setVisible(true); } @@ -1655,6 +1657,15 @@ public class TagTreeContextMenu extends JPopupMenu { }); addTagMenu.add(createBinaryDataItem); break; + case TagTreeModel.FOLDER_MORPHSHAPES: + addTagMenu.addSeparator(); + JMenuItem createMorphShapeItem = new JMenuItem(AppStrings.translate("tag.morphshape.create")); + createMorphShapeItem.setIcon(View.getIcon("importshape16")); + createMorphShapeItem.addActionListener((ActionEvent ae) -> { + listener.call(ae, item, DefineMorphShape2Tag.class, TreeNodeType.MORPH_SHAPE); + }); + addTagMenu.add(createMorphShapeItem); + break; } } @@ -3812,6 +3823,7 @@ public class TagTreeContextMenu extends JPopupMenu { remove = !mainPanel.replaceSpriteWithGif(tag); break; case SHAPE: + case MORPH_SHAPE: remove = !mainPanel.replaceNoFill(tag); break; case FONT: