diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/DisplayObjectCacheKey.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/DisplayObjectCacheKey.java new file mode 100644 index 000000000..7b8c91ac1 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/DisplayObjectCacheKey.java @@ -0,0 +1,54 @@ +package com.jpexs.decompiler.flash.tags.base; + +import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle; +import java.util.Objects; + +/** + * + * @author JPEXS + */ +public class DisplayObjectCacheKey { + public PlaceObjectTypeTag placeObject; + public double zoom; + public ExportRectangle viewRect; + + public DisplayObjectCacheKey(PlaceObjectTypeTag placeObject, double zoom, ExportRectangle viewRect) { + this.placeObject = placeObject; + this.zoom = zoom; + this.viewRect = viewRect; + } + + @Override + public int hashCode() { + int hash = 3; + hash = 79 * hash + Objects.hashCode(this.placeObject); + hash = 79 * hash + (int) (Double.doubleToLongBits(this.zoom) ^ (Double.doubleToLongBits(this.zoom) >>> 32)); + hash = 79 * hash + Objects.hashCode(this.viewRect); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final DisplayObjectCacheKey other = (DisplayObjectCacheKey) obj; + if (Double.doubleToLongBits(this.zoom) != Double.doubleToLongBits(other.zoom)) { + return false; + } + if (!Objects.equals(this.placeObject, other.placeObject)) { + return false; + } + if (!Objects.equals(this.viewRect, other.viewRect)) { + return false; + } + return true; + } + +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/RenderContext.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/RenderContext.java index c2fed029b..a1763ebfa 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/RenderContext.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/RenderContext.java @@ -12,7 +12,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.flash.tags.base; import com.jpexs.decompiler.flash.timeline.DepthState; @@ -37,5 +38,13 @@ public class RenderContext { public SerializableImage borderImage; - public Cache displayObjectCache; + public Cache displayObjectCache; + + public void clearPlaceObjectCache(PlaceObjectTypeTag placeObject) { + for (DisplayObjectCacheKey k : displayObjectCache.keys()) { + if (k.placeObject == placeObject) { + displayObjectCache.remove(k); + } + } + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java index 16ca7816c..3d0c3d56a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java @@ -39,6 +39,7 @@ import com.jpexs.decompiler.flash.tags.base.BoundedTag; 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.DisplayObjectCacheKey; import com.jpexs.decompiler.flash.tags.base.DrawableTag; import com.jpexs.decompiler.flash.tags.base.ImageTag; import com.jpexs.decompiler.flash.tags.base.MorphShapeTag; @@ -662,6 +663,7 @@ public class Timeline { strokeTransform = strokeTransform.concatenate(layerMatrix); boolean cacheAsBitmap = layer.cacheAsBitmap() && layer.placeObjectTag != null && drawable.isSingleFrame(); + /* // draw bounds AffineTransform trans = mat.preConcatenate(Matrix.getScaleInstance(1 / SWF.unitDivisor)).toTransform(); g.setTransform(trans); @@ -679,7 +681,8 @@ public class Timeline { SerializableImage img = null; if (cacheAsBitmap && renderContext.displayObjectCache != null) { - img = renderContext.displayObjectCache.get(layer.placeObjectTag); + DisplayObjectCacheKey key = new DisplayObjectCacheKey(layer.placeObjectTag, unzoom, viewRect); + img = renderContext.displayObjectCache.get(key); } int stateCount = renderContext.stateUnderCursor == null ? 0 : renderContext.stateUnderCursor.size(); @@ -690,6 +693,8 @@ public class Timeline { dframe = time % drawableFrameCount; } + ExportRectangle viewRect2 = new ExportRectangle(viewRect); + if (filters != null && filters.size() > 0) { // calculate size after applying the filters double deltaXMax = 0; @@ -704,12 +709,16 @@ public class Timeline { rect.xMax += deltaXMax * unzoom * SWF.unitDivisor; rect.yMin -= deltaYMax * unzoom * SWF.unitDivisor; rect.yMax += deltaYMax * unzoom * SWF.unitDivisor; + viewRect2.xMin -= deltaXMax * SWF.unitDivisor; + viewRect2.xMax += deltaXMax * SWF.unitDivisor; + viewRect2.yMin -= deltaXMax * SWF.unitDivisor; + viewRect2.yMax += deltaXMax * SWF.unitDivisor; } rect.xMin -= SWF.unitDivisor; rect.yMin -= SWF.unitDivisor; - rect.xMin = Math.max(0, rect.xMin); - rect.yMin = Math.max(0, rect.yMin); + /*rect.xMin = Math.max(0, rect.xMin); + rect.yMin = Math.max(0, rect.yMin);*/ drawMatrix.translate(rect.xMin, rect.yMin); drawMatrix.translateX /= SWF.unitDivisor; drawMatrix.translateY /= SWF.unitDivisor; @@ -795,7 +804,7 @@ public class Timeline { } if (!(drawable instanceof ImageTag) || (swf.isAS3() && layer.hasImage)) { - drawable.toImage(dframe, time, ratio, renderContext, img, isClip || clipDepth > -1, m, strokeTransform, absMat, mfull, clrTrans2, unzoom, sameImage, viewRect, scaleStrokes, drawMode); + drawable.toImage(dframe, time, ratio, renderContext, img, isClip || clipDepth > -1, m, strokeTransform, absMat, mfull, clrTrans2, unzoom, sameImage, viewRect2, scaleStrokes, drawMode); } else { // todo: show one time warning } @@ -812,7 +821,8 @@ public class Timeline { } if (!sameImage && cacheAsBitmap && renderContext.displayObjectCache != null) { - renderContext.displayObjectCache.put(layer.placeObjectTag, img); + renderContext.clearPlaceObjectCache(layer.placeObjectTag); + renderContext.displayObjectCache.put(new DisplayObjectCacheKey(layer.placeObjectTag, unzoom, viewRect), img); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/helpers/Cache.java b/libsrc/ffdec_lib/src/com/jpexs/helpers/Cache.java index 1e6f24680..9e1159bd7 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/helpers/Cache.java +++ b/libsrc/ffdec_lib/src/com/jpexs/helpers/Cache.java @@ -12,7 +12,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.helpers; import com.jpexs.decompiler.flash.helpers.Freed; @@ -21,8 +22,11 @@ import java.io.IOException; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.TreeSet; import java.util.WeakHashMap; /** @@ -169,4 +173,10 @@ public class Cache implements Freed { ((Freed) cache).free(); } } + + public Set keys() { + Set ret = new HashSet<>(); + ret.addAll(cache.keySet()); + return ret; + } } diff --git a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java index bd4a8e6f4..d855b3ff3 100644 --- a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java +++ b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java @@ -48,6 +48,7 @@ import com.jpexs.decompiler.flash.types.SOUNDINFO; import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle; import com.jpexs.decompiler.flash.tags.DefineButton2Tag; import com.jpexs.decompiler.flash.tags.DefineButtonTag; +import com.jpexs.decompiler.flash.tags.base.DisplayObjectCacheKey; import com.jpexs.decompiler.flash.types.BUTTONCONDACTION; import com.jpexs.helpers.ByteArrayRange; import com.jpexs.helpers.Cache; @@ -142,7 +143,7 @@ public final class ImagePanel extends JPanel implements MediaDisplay { private final List soundPlayers = new ArrayList<>(); - private final Cache displayObjectCache = Cache.getInstance(false, false, "displayObject"); + private final Cache displayObjectCache = Cache.getInstance(false, false, "displayObject"); private final IconPanel iconPanel;