From f09d4affa5c0887214034f18e7b6c32f24ade91c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Fri, 29 Dec 2023 10:35:45 +0100 Subject: [PATCH] Fixed #2156 FLA export - morphshapes --- CHANGELOG.md | 3 +- .../decompiler/flash/xfl/XFLConverter.java | 18 +++---- .../flash/xfl/shapefixer/MorphShapeFixer.java | 51 +++++++++++++------ 3 files changed, 47 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fe4433e4..9e059c566 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -72,7 +72,7 @@ All notable changes to this project will be documented in this file. - [#2136] FLA Export - optimized Shape fixer speed, repeated shape on timeline not exported twice - [#2139] FLA Export - labels layer not counted as layer index causing masked layer parentindex wrong - [#2138] Nested clipping (masks) display -- [#2138] FLA Export - Missing morphshapes (incorrect holes calculation) +- [#2138], [#2156] FLA Export - Missing morphshapes (incorrect holes calculation) - [#2138] FLA Export - Mask layer was visible when did not contain a masked layer - FLA Export - frame numbering problem - [#2145] FLA Export - missing frames, cliping layers order, nullpointer, empty sound layers @@ -3366,6 +3366,7 @@ Major version of SWF to XML export changed to 2. [#1194]: https://www.free-decompiler.com/flash/issues/1194 [#2136]: https://www.free-decompiler.com/flash/issues/2136 [#2139]: https://www.free-decompiler.com/flash/issues/2139 +[#2156]: https://www.free-decompiler.com/flash/issues/2156 [#2145]: https://www.free-decompiler.com/flash/issues/2145 [#2142]: https://www.free-decompiler.com/flash/issues/2142 [#2148]: https://www.free-decompiler.com/flash/issues/2148 diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java index 32c5bfdcb..4e2ee2505 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java @@ -620,8 +620,8 @@ public class XFLConverter { return false; } - private static void convertShape(SWF swf, HashMap characters, MATRIX mat, int shapeNum, List shapeRecords, FILLSTYLEARRAY fillStyles, LINESTYLEARRAY lineStyles, boolean morphshape, boolean useLayers, XFLXmlWriter writer) throws XMLStreamException { - List layers = getShapeLayers(swf, characters, mat, shapeNum, shapeRecords, fillStyles, lineStyles, morphshape); + private static void convertShape(int characterId, SWF swf, HashMap characters, MATRIX mat, int shapeNum, List shapeRecords, FILLSTYLEARRAY fillStyles, LINESTYLEARRAY lineStyles, boolean morphshape, boolean useLayers, XFLXmlWriter writer) throws XMLStreamException { + List layers = getShapeLayers(characterId, swf, characters, mat, shapeNum, shapeRecords, fillStyles, lineStyles, morphshape); if (!useLayers) { for (int l = layers.size() - 1; l >= 0; l--) { writer.writeCharactersRaw(layers.get(l)); @@ -813,7 +813,7 @@ public class XFLConverter { return ret; } - private static List getShapeLayers(SWF swf, HashMap characters, MATRIX mat, int shapeNum, List shapeRecords, FILLSTYLEARRAY fillStyles, LINESTYLEARRAY lineStyles, boolean morphshape) throws XMLStreamException { + private static List getShapeLayers(int characterId, SWF swf, HashMap characters, MATRIX mat, int shapeNum, List shapeRecords, FILLSTYLEARRAY fillStyles, LINESTYLEARRAY lineStyles, boolean morphshape) throws XMLStreamException { if (mat == null) { mat = new MATRIX(); } @@ -1877,7 +1877,7 @@ public class XFLConverter { if ((character instanceof ShapeTag) && (nonLibraryShapes.contains(characterId))) { ShapeTag shape = (ShapeTag) character; statusStack.pushStatus(character.toString()); - convertShape(swf, characters, matrix, shape.getShapeNum(), shape.getShapes().shapeRecords, shape.getShapes().fillStyles, shape.getShapes().lineStyles, false, false, recCharWriter); + convertShape(characterId, swf, characters, matrix, shape.getShapeNum(), shape.getShapes().shapeRecords, shape.getShapes().fillStyles, shape.getShapes().lineStyles, false, false, recCharWriter); statusStack.popStatus(); } else if (character instanceof TextTag) { statusStack.pushStatus(character.toString()); @@ -1946,7 +1946,7 @@ public class XFLConverter { symbolStr.writeStartElement("layers"); SHAPEWITHSTYLE shapeWithStyle = shape.getShapes(); if (shapeWithStyle != null) { - convertShape(swf, characters, null, shape.getShapeNum(), shapeWithStyle.shapeRecords, shapeWithStyle.fillStyles, shapeWithStyle.lineStyles, false, true, symbolStr); + convertShape(shape.getCharacterId(), swf, characters, null, shape.getShapeNum(), shapeWithStyle.shapeRecords, shapeWithStyle.fillStyles, shapeWithStyle.lineStyles, false, true, symbolStr); } symbolStr.writeEndElement(); // layers @@ -2769,12 +2769,12 @@ public class XFLConverter { if ((character instanceof MorphShapeTag) && (!multiUsageMorphShapes.contains(character.getCharacterId()))) { MorphShapeTag m2 = (MorphShapeTag) character; statusStack.pushStatus(m2.toString()); - convertShape(swf, characters, matrix, m2.getShapeNum() == 1 ? 3 : 4, m2.getStartEdges().shapeRecords, m2.getFillStyles().getStartFillStyles(), m2.getLineStyles().getStartLineStyles(m2.getShapeNum()), true, false, addLastWriter); + convertShape(m2.getCharacterId(), swf, characters, matrix, m2.getShapeNum() == 1 ? 3 : 4, m2.getStartEdges().shapeRecords, m2.getFillStyles().getStartFillStyles(), m2.getLineStyles().getStartLineStyles(m2.getShapeNum()), true, false, addLastWriter); statusStack.popStatus(); shapeTween = true; } else { SHAPEWITHSTYLE endShape = m.getShapeAtRatio(65535); //lastTweenRatio); - convertShape(swf, characters, matrix, m.getShapeNum() == 1 ? 3 : 4, endShape.shapeRecords, m.getFillStyles().getFillStylesAt(65535), m.getLineStyles().getLineStylesAt(m.getShapeNum(), 65535), true, false, addLastWriter); + convertShape(m.getCharacterId(), swf, characters, matrix, m.getShapeNum() == 1 ? 3 : 4, endShape.shapeRecords, m.getFillStyles().getFillStylesAt(65535), m.getLineStyles().getLineStylesAt(m.getShapeNum(), 65535), true, false, addLastWriter); } Integer ease = EasingDetector.getEaseFromShapeRatios(morphShapeRatios); @@ -2801,7 +2801,7 @@ public class XFLConverter { } else { ShapeTag shape = (ShapeTag) character; statusStack.pushStatus(character.toString()); - convertShape(swf, characters, matrix, shape.getShapeNum(), shape.getShapes().shapeRecords, shape.getShapes().fillStyles, shape.getShapes().lineStyles, false, false, elementsWriter); + convertShape(shape.getCharacterId(), swf, characters, matrix, shape.getShapeNum(), shape.getShapes().shapeRecords, shape.getShapes().fillStyles, shape.getShapes().lineStyles, false, false, elementsWriter); statusStack.popStatus(); } shapeTween = false; @@ -2820,7 +2820,7 @@ public class XFLConverter { elementsWriter.writeCharactersRaw(lastElements); } else { statusStack.pushStatus(m.toString()); - convertShape(swf, characters, matrix, m.getShapeNum() == 1 ? 3 : 4, m.getStartEdges().shapeRecords, m.getFillStyles().getStartFillStyles(), m.getLineStyles().getStartLineStyles(m.getShapeNum()), true, false, elementsWriter); + convertShape(m.getCharacterId(), swf, characters, matrix, m.getShapeNum() == 1 ? 3 : 4, m.getStartEdges().shapeRecords, m.getFillStyles().getStartFillStyles(), m.getLineStyles().getStartLineStyles(m.getShapeNum()), true, false, elementsWriter); statusStack.popStatus(); } shapeTween = true; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/shapefixer/MorphShapeFixer.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/shapefixer/MorphShapeFixer.java index ee077671c..b3ee2d88a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/shapefixer/MorphShapeFixer.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/shapefixer/MorphShapeFixer.java @@ -270,24 +270,45 @@ public class MorphShapeFixer extends ShapeFixer { PathIterator pi = region.getPathIterator(null); - if (!pi.isDone()) { + Rectangle2D bounds = region.getBounds2D(); + double centerX = bounds.getCenterX(); + double centerY = bounds.getCenterY(); + int numPoints = 0; + int numContains = 0; + int numNotContains = 0; + double x = 0; + double y = 0; + while (!pi.isDone()) { double[] points = new double[6]; int type = pi.currentSegment(points); - if (type == PathIterator.SEG_MOVETO) { - double x = points[0]; - double y = points[1]; - Rectangle2D bounds = region.getBounds2D(); - double centerX = bounds.getCenterX(); - double centerY = bounds.getCenterY(); - - double p = Math.sqrt((centerX - x) * (centerX - x) + (centerY - y) * (centerY - y)); - double x1 = (centerX - x) * 0.1 / p; - double y1 = (centerY - y) * 0.1 / p; - if (!path.contains(x + x1, y + y1)) { - closedHolesI.add(i); - } + switch (type) { + case PathIterator.SEG_MOVETO: + case PathIterator.SEG_LINETO: + x = points[0]; + y = points[1]; + break; + case PathIterator.SEG_QUADTO: + x = points[2]; + y = points[3]; } - } + + numPoints++; + double p = Math.sqrt((centerX - x) * (centerX - x) + (centerY - y) * (centerY - y)); + double x1 = (centerX - x) * 0.1 / p; + double y1 = (centerY - y) * 0.1 / p; + if (path.contains(x + x1, y + y1)) { + numContains++; + } else { + numNotContains++; + } + if (numPoints == 4) { + break; + } + pi.next(); + } + if (numNotContains > numContains) { + closedHolesI.add(i); + } } }