diff --git a/CHANGELOG.md b/CHANGELOG.md index 508485434..375800f14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ All notable changes to this project will be documented in this file. - [#2134] FLA Export - split main timeline into scenes when DefineSceneAndFrameLabelData tag is present - [#2132] Show and export streamed sound (SoundStreamHead/SoundStreamBlock) in frame ranges - FLA export - show export time +- [#2138] Morphshapes - detect classic easing ### Fixed - [#2021], [#2000] Caret position in editors when using tabs and / or unicode diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/Easing.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/Easing.java new file mode 100644 index 000000000..66bb00a0f --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/Easing.java @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2010-2023 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.xfl; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.math.BezierEdge; +import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.geom.GeneralPath; +import java.io.FileInputStream; +import java.util.ArrayList; +import java.util.List; +import javax.swing.JFrame; +import javax.swing.JPanel; + +/** + * + * @author JPEXS + */ +public class Easing extends JFrame { + + public Easing() { + setDefaultCloseOperation(EXIT_ON_CLOSE); + setSize(800, 800); + setContentPane(new JPanel(){ + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + + int ease = 100; + + //290 + GeneralPath gp = new GeneralPath(); + gp.moveTo(0, 290); + g.setColor(Color.RED); + for (int i = 0; i <= 100; i++) { + double ptSize = 290 / 100.0; + double pct = framePercentToRatio(i, ease); + //System.out.println("pct="+pct); + /*g.drawLine((int)Math.round(i*ptSize), 290-(int)Math.round(pct*ptSize), + (int)Math.round(i*ptSize), 290-(int)Math.round(pct*ptSize)); */ + gp.lineTo(i*ptSize, 290-pct*ptSize); + } + Graphics2D g2d = (Graphics2D)g; + g2d.draw(gp); + g.setColor(Color.black); + g.drawRect(0, 0, 290, 290); + } + + }); + } + + + + public static double framePercentToRatio(double framePercent, int ease) { + BezierEdge be = new BezierEdge(0,0,50,65535 / 2 + ease * 65535 / 100 / 2, 100,65535); + BezierEdge line = new BezierEdge(framePercent, 0, framePercent, 65535); + return be.getIntersections(line).get(0).getY(); + } + + public static double ratioToFramePercent(double ratio, int ease) { + BezierEdge be = new BezierEdge(0,0,50,50 + ease / 2.0, 100,65535); + BezierEdge line = new BezierEdge(0, ratio, 100, ratio); + return be.getIntersections(line).get(0).getX(); + } + + public static Integer getEaseFromShapeRatios(List ratios) { + if (ratios.isEmpty()) { + return null; + } + if (ratios.get(0) != 0) { + ratios.add(0, 0); + } + if (ratios.get(ratios.size() - 1) != 65535) { + ratios.add(65535); + } + + int ease = 100; + while(true) { + double minDist = Double.MAX_VALUE; + double maxDist = Double.MIN_VALUE; + + for (int f = 0; f < ratios.size(); f++) { + double framePct = f * 100 / (double)(ratios.size() - 1); + double tweenPct = ratios.get(f); + double tweenPctShouldBe = Math.round(framePercentToRatio(framePct, ease)); + double dist = tweenPctShouldBe - tweenPct; + + if (dist > maxDist) { + maxDist = dist; + } + if (dist < minDist) { + minDist = dist; + } + } + if (minDist > -5 && maxDist < 5) { + break; + } + if (ease == -100) { + return null; + } + ease--; + } + return ease; + } + + public static void main(String[] args) throws Exception { + + SWF swf = new SWF(new FileInputStream("c:\\flash_testdata\\morphshape_ease\\morphshape_ease.swf"), true, false); + List ratios = new ArrayList<>(); + for (Tag t : swf.getTags()) { + if (t instanceof PlaceObjectTypeTag) { + PlaceObjectTypeTag place = (PlaceObjectTypeTag) t; + int ratio = place.getRatio(); + if (ratio > -1) { + ratios.add(ratio); + } + } + } + + Integer ease = getEaseFromShapeRatios(ratios); + System.err.println("ease = " + ease); + + //System.setProperty("sun.java2d.uiScale", "1.0"); + //new Easing().setVisible(true); + } +} 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 cf9743705..5b70003b4 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 @@ -2463,7 +2463,7 @@ public class XFLConverter { } } - private static void convertFrame(Scene scene, boolean shapeTween, SoundStreamFrameRange soundStreamRange, StartSoundTag startSound, int frame, int duration, String actionScript, String elements, HashMap files, XFLXmlWriter writer) throws XMLStreamException { + private static void convertFrame(Scene scene, boolean shapeTween, SoundStreamFrameRange soundStreamRange, StartSoundTag startSound, int frame, int duration, String actionScript, String elements, HashMap files, XFLXmlWriter writer, Integer acceleration) throws XMLStreamException { DefineSoundTag sound = null; if (startSound != null) { SWF swf = startSound.getSwf(); @@ -2478,6 +2478,9 @@ public class XFLConverter { if (shapeTween) { writer.writeAttribute("tweenType", "shape"); writer.writeAttribute("keyMode", KEY_MODE_SHAPE_TWEEN); + if (acceleration != null) { + writer.writeAttribute("acceleration", acceleration); + } } else { writer.writeAttribute("keyMode", KEY_MODE_NORMAL); } @@ -2567,6 +2570,7 @@ public class XFLConverter { int ratio = -1; boolean shapeTween = false; MorphShapeTag shapeTweener = null; + List morphShapeRatios = new ArrayList<>(); int lastTweenRatio = -1; //Add ShowFrameTag to the end when there is one last missing @@ -2711,15 +2715,20 @@ public class XFLConverter { MorphShapeTag m = shapeTweener; XFLXmlWriter addLastWriter = new XFLXmlWriter(); SHAPEWITHSTYLE endShape = m.getShapeAtRatio(65535); //lastTweenRatio); - convertShape(swf, characters, matrix, m.getShapeNum() == 1 ? 3 : 4, endShape.shapeRecords, m.getFillStyles().getFillStylesAt(lastTweenRatio), m.getLineStyles().getLineStylesAt(m.getShapeNum(), lastTweenRatio), true, false, addLastWriter); - //duration--; - convertFrame(scene, true, null, null, frame - duration, duration, "", lastElements, files, writer2); + convertShape(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 = Easing.getEaseFromShapeRatios(morphShapeRatios); + Integer acceleration = null; + if (ease != null) { + acceleration = -ease; + } + convertFrame(scene, true, null, null, frame - duration, duration, "", lastElements, files, writer2, acceleration); duration = 1; lastElements = addLastWriter.toString(); lastCharacter = m; lastMatrix = matrix; shapeTweener = null; shapeTweenNow = true; + morphShapeRatios.clear(); } if (!shapeTweenNow) { if (character instanceof ShapeTag && standaloneShapeTweener != null) { @@ -2747,7 +2756,8 @@ public class XFLConverter { standaloneShapeTweener = m; standaloneShapeTweenerMatrix = matrix; convertSymbolInstance(instanceName, matrix, colorTransForm, cacheAsBitmap, blendMode, filters, isVisible, backGroundColor, clipActions, metadata, character, characters, tags, flaVersion, elementsWriter); - } else { + } else { + morphShapeRatios.add(ratio == -1 ? 0 : ratio); if (lastCharacter == m && Objects.equals(matrix, lastMatrix)) { elementsWriter.writeCharactersRaw(lastElements); } else { @@ -2781,7 +2791,7 @@ public class XFLConverter { frame++; String elements = elementsWriter.toString(); if (!elements.equals(lastElements) && frame > 0) { - convertFrame(scene, false, null, null, frame - duration, duration, "", lastElements, files, writer2); + convertFrame(scene, false, null, null, frame - duration, duration, "", lastElements, files, writer2, null); duration = 1; } else if (frame == 0) { duration = 1; @@ -2819,7 +2829,7 @@ public class XFLConverter { } if (!lastElements.isEmpty() || writer2.length() > 0) { frame++; - convertFrame(scene, false, null, null, (frame - duration < 0 ? 0 : frame - duration), duration, "", lastElements, files, writer2); + convertFrame(scene, false, null, null, (frame - duration < 0 ? 0 : frame - duration), duration, "", lastElements, files, writer2, null); } afterStr = "" + afterStr; @@ -3236,10 +3246,10 @@ public class XFLConverter { if (startFrame != 0) { // empty frames should be added - convertFrame(scene, false, null, null, 0, startFrame, "", "", files, writer); + convertFrame(scene, false, null, null, 0, startFrame, "", "", files, writer, null); } - convertFrame(scene, false, soundStreamRanges.get(i), null, startFrame, duration, "", "", files, writer); + convertFrame(scene, false, soundStreamRanges.get(i), null, startFrame, duration, "", "", files, writer, null); writer.writeEndElement(); writer.writeEndElement(); @@ -3254,10 +3264,10 @@ public class XFLConverter { if (startFrame != 0) { // empty frames should be added - convertFrame(scene, false, null, null, 0, startFrame, "", "", files, writer); + convertFrame(scene, false, null, null, 0, startFrame, "", "", files, writer, null); } - convertFrame(scene, false, null, startSounds.get(i), startFrame, duration, "", "", files, writer); + convertFrame(scene, false, null, startSounds.get(i), startFrame, duration, "", "", files, writer, null); writer.writeEndElement(); writer.writeEndElement(); diff --git a/libsrc/ffdec_lib/testdata/morphshape_ease/exp/morphshape_ease/DOMDocument.xml b/libsrc/ffdec_lib/testdata/morphshape_ease/exp/morphshape_ease/DOMDocument.xml new file mode 100644 index 000000000..f6c5bd73f --- /dev/null +++ b/libsrc/ffdec_lib/testdata/morphshape_ease/exp/morphshape_ease/DOMDocument.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libsrc/ffdec_lib/testdata/morphshape_ease/exp/morphshape_ease/PublishSettings.xml b/libsrc/ffdec_lib/testdata/morphshape_ease/exp/morphshape_ease/PublishSettings.xml new file mode 100644 index 000000000..40c6cbef7 --- /dev/null +++ b/libsrc/ffdec_lib/testdata/morphshape_ease/exp/morphshape_ease/PublishSettings.xml @@ -0,0 +1,206 @@ + + + + 1 + 1 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + morphshape_ease.swf + morphshape_ease.exe + morphshape_ease.app + morphshape_ease.html + morphshape_ease.gif + morphshape_ease.jpg + morphshape_ease.png + 1 + morphshape_ease.smil + morphshape_ease.swc + + + 0 + 12,0,0,0;11,2,0,0;11,1,0,0;10,3,0,0;10,2,153,0;10,1,52,0;9,0,124,0;8,0,24,0;7,0,14,0;6,0,79,0;5,0,58,0;4,0,32,0;3,0,8,0;2,0,1,12;1,0,0,1; + 1 + 1 + morphshape_ease_content.html + morphshape_ease_alternate.html + 0 + + 550.0 + 400.0 + 0 + 0 + 1 + 0 + 0 + 1 + 1 + 4 + 0 + 0 + 1 + 0 + + 1 + + + + + 0 + 0 + 0 + 80 + 0 + 0 + 7 + 0 + 7 + 0 + 15 + FlashPlayer11.2 + 2 + 1 + + . + CONFIG::FLASH_AUTHORING="true"; + 0 + + 1 + 0 + 1 + 0 + 0 + 0 + 0 + + 2 + 4 + 4096 + AS3 + 1 + 1 + 0 + 15 + 1 + 0 + 4102 + rsl + wrap + $(AppConfig)/ActionScript 3.0/rsls/loader_animation.swf + + + $(AppConfig)/ActionScript 3.0/libs + merge + + + $(AppConfig)/ActionScript 3.0/libs/11.0/textLayout.swc + rsl + http://fpdownload.adobe.com/pub/swz/tlf/2.0.0.232/textLayout_2.0.0.232.swz + http://fpdownload.adobe.com/pub/swz/crossdomain.xml + textLayout_2.0.0.232.swz + + + + + $(AppConfig)/ActionScript 3.0/libs/11.0/textLayout.swc + + http://fpdownload.adobe.com/pub/swz/tlf/2.0.0.232/textLayout_2.0.0.232.swz + http://fpdownload.adobe.com/pub/swz/crossdomain.xml + textLayout_2.0.0.232.swz + + + + + 550.0 + 400.0 + 0 + 4718592 + 0 + 80 + 1 + + + 1 + 0 + 1 + 0 + 0 + 100000 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + + + 550.0 + 400.0 + 0 + 1 + 1 + + 1 + 0 + 1 + 0 + 0 + + 128 + + + 255 + + + + 550.0 + 400.0 + 1 + 0 + 0 + 1 + 0 + 0 + 1 + + + + 24-bit with Alpha + 255 + + + + 550.0 + 400.0 + 1 + 0 + + + 00000000 + 0 + 0 + 0 + 0 + 1 + + + \ No newline at end of file diff --git a/libsrc/ffdec_lib/testdata/morphshape_ease/exp/morphshape_ease/morphshape_ease.xfl b/libsrc/ffdec_lib/testdata/morphshape_ease/exp/morphshape_ease/morphshape_ease.xfl new file mode 100644 index 000000000..860a820ec --- /dev/null +++ b/libsrc/ffdec_lib/testdata/morphshape_ease/exp/morphshape_ease/morphshape_ease.xfl @@ -0,0 +1 @@ +PROXY-CS5 \ No newline at end of file diff --git a/libsrc/ffdec_lib/testdata/morphshape_ease/morphshape_ease.html b/libsrc/ffdec_lib/testdata/morphshape_ease/morphshape_ease.html new file mode 100644 index 000000000..279a46285 --- /dev/null +++ b/libsrc/ffdec_lib/testdata/morphshape_ease/morphshape_ease.html @@ -0,0 +1,49 @@ + + + + morphshape_ease + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + Get Adobe Flash player + + + + + +
+ + diff --git a/libsrc/ffdec_lib/testdata/morphshape_ease/morphshape_ease.swf b/libsrc/ffdec_lib/testdata/morphshape_ease/morphshape_ease.swf new file mode 100644 index 000000000..ea90edbdf Binary files /dev/null and b/libsrc/ffdec_lib/testdata/morphshape_ease/morphshape_ease.swf differ diff --git a/libsrc/ffdec_lib/testdata/morphshape_ease/morphshape_ease/LIBRARY/Symbol 1.xml b/libsrc/ffdec_lib/testdata/morphshape_ease/morphshape_ease/LIBRARY/Symbol 1.xml new file mode 100644 index 000000000..e6d499950 --- /dev/null +++ b/libsrc/ffdec_lib/testdata/morphshape_ease/morphshape_ease/LIBRARY/Symbol 1.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libsrc/ffdec_lib/testdata/morphshape_ease/morphshape_ease/LIBRARY/Tween 1.xml b/libsrc/ffdec_lib/testdata/morphshape_ease/morphshape_ease/LIBRARY/Tween 1.xml new file mode 100644 index 000000000..e04e641d4 --- /dev/null +++ b/libsrc/ffdec_lib/testdata/morphshape_ease/morphshape_ease/LIBRARY/Tween 1.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libsrc/ffdec_lib/testdata/morphshape_ease/morphshape_ease/LIBRARY/Tween 2.xml b/libsrc/ffdec_lib/testdata/morphshape_ease/morphshape_ease/LIBRARY/Tween 2.xml new file mode 100644 index 000000000..818ccb782 --- /dev/null +++ b/libsrc/ffdec_lib/testdata/morphshape_ease/morphshape_ease/LIBRARY/Tween 2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libsrc/ffdec_lib/testdata/morphshape_ease/morphshape_ease/META-INF/metadata.xml b/libsrc/ffdec_lib/testdata/morphshape_ease/morphshape_ease/META-INF/metadata.xml new file mode 100644 index 000000000..dd7ab5950 --- /dev/null +++ b/libsrc/ffdec_lib/testdata/morphshape_ease/morphshape_ease/META-INF/metadata.xml @@ -0,0 +1,67 @@ + + + + + Adobe Flash Professional CS6 - build 481 + 2023-12-04T10:32:38-08:00 + 2023-12-09T04:33:48-08:00 + 2023-12-09T04:33:48-08:00 + + + application/vnd.adobe.fla + + + xmp.iid:FA0A2AA52D76EE119313910734F6A093 + xmp.did:FE0A2AA52D76EE119313910734F6A093 + xmp.did:FE0A2AA52D76EE119313910734F6A093 + + + + created + xmp.iid:FE0A2AA52D76EE119313910734F6A093 + 2023-12-04T10:32:38-08:00 + Adobe Flash Professional CS6 - build 481 + + + created + xmp.iid:D3DF0DBE6596EE118F9EDF8980AE5CDF + 2023-12-04T10:32:38-08:00 + Adobe Flash Professional CS6 - build 481 + + + created + xmp.iid:FA0A2AA52D76EE119313910734F6A093 + 2023-12-04T10:32:38-08:00 + Adobe Flash Professional CS6 - build 481 + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libsrc/ffdec_lib/testdata/morphshape_ease/morphshape_ease/MobileSettings.xml b/libsrc/ffdec_lib/testdata/morphshape_ease/morphshape_ease/MobileSettings.xml new file mode 100644 index 000000000..e69de29bb diff --git a/libsrc/ffdec_lib/testdata/morphshape_ease/morphshape_ease/PublishSettings.xml b/libsrc/ffdec_lib/testdata/morphshape_ease/morphshape_ease/PublishSettings.xml new file mode 100644 index 000000000..b6b2856c9 --- /dev/null +++ b/libsrc/ffdec_lib/testdata/morphshape_ease/morphshape_ease/PublishSettings.xml @@ -0,0 +1,206 @@ + + + + 1 + 1 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + morphshape_ease.swf + morphshape_ease.exe + morphshape_ease.app + morphshape_ease.html + morphshape_ease.gif + morphshape_ease.jpg + morphshape_ease.png + morphshape_ease.mov + morphshape_ease.smil + morphshape_ease.swc + + + 0 + 12,0,0,0;11,2,0,0;11,1,0,0;10,3,0,0;10,2,153,0;10,1,52,0;9,0,124,0;8,0,24,0;7,0,14,0;6,0,79,0;5,0,58,0;4,0,32,0;3,0,8,0;2,0,1,12;1,0,0,1; + 1 + 1 + morphshape_ease.xfl_content.html + morphshape_ease.xfl_alternate.html + 0 + + 550 + 400 + 0 + 0 + 1 + 0 + 0 + 1 + 1 + 4 + 0 + 0 + 1 + 0 + C:\Users\MyUser\AppData\Local\Adobe\Flash CS6\en_US\Configuration\HTML\Default.html + 1 + + + + + 0 + 0 + 0 + 80 + 0 + 0 + 7 + 0 + 7 + 0 + 15 + FlashPlayer11.2 + 2 + 1 + + . + CONFIG::FLASH_AUTHORING="true"; + 0 + + 1 + 0 + 1 + 0 + 0 + 0 + 0 + + 2 + 4 + 4096 + AS3 + 1 + 1 + 0 + 15 + 1 + 0 + 4102 + rsl + wrap + $(AppConfig)/ActionScript 3.0/rsls/loader_animation.swf + + + $(AppConfig)/ActionScript 3.0/libs + merge + + + $(AppConfig)/ActionScript 3.0/libs/11.0/textLayout.swc + rsl + http://fpdownload.adobe.com/pub/swz/tlf/2.0.0.232/textLayout_2.0.0.232.swz + http://fpdownload.adobe.com/pub/swz/crossdomain.xml + textLayout_2.0.0.232.swz + + + + + $(AppConfig)/ActionScript 3.0/libs/11.0/textLayout.swc + + http://fpdownload.adobe.com/pub/swz/tlf/2.0.0.232/textLayout_2.0.0.232.swz + http://fpdownload.adobe.com/pub/swz/crossdomain.xml + textLayout_2.0.0.232.swz + + + + + 550 + 400 + 0 + 4718592 + 0 + 80 + 1 + + + 1 + 0 + 1 + 0 + 0 + 100000 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + + + 550 + 400 + 0 + 1 + 1 + + 1 + 0 + 1 + 0 + 0 + + 128 + + + 255 + + + + 550 + 400 + 1 + 0 + 0 + 1 + 0 + 0 + 1 + + + + 24-bit with Alpha + 255 + + + + 550 + 400 + 1 + 0 + + + 00000000 + 0 + 0 + 0 + 0 + 1 + + + \ No newline at end of file diff --git a/libsrc/ffdec_lib/testdata/morphshape_ease/morphshape_ease/bin/SymDepend.cache b/libsrc/ffdec_lib/testdata/morphshape_ease/morphshape_ease/bin/SymDepend.cache new file mode 100644 index 000000000..cd1969a92 Binary files /dev/null and b/libsrc/ffdec_lib/testdata/morphshape_ease/morphshape_ease/bin/SymDepend.cache differ diff --git a/libsrc/ffdec_lib/testdata/morphshape_ease/morphshape_ease/morphshape_ease.xfl b/libsrc/ffdec_lib/testdata/morphshape_ease/morphshape_ease/morphshape_ease.xfl new file mode 100644 index 000000000..860a820ec --- /dev/null +++ b/libsrc/ffdec_lib/testdata/morphshape_ease/morphshape_ease/morphshape_ease.xfl @@ -0,0 +1 @@ +PROXY-CS5 \ No newline at end of file