calculate only the necessary outlines while moving the mouse over the internal player area

This commit is contained in:
honfika@gmail.com
2016-02-06 09:23:50 +01:00
parent f9bdb8a35a
commit 09a7f68583
19 changed files with 204 additions and 204 deletions

View File

@@ -166,8 +166,10 @@ import com.jpexs.helpers.ProgressListener;
import com.jpexs.helpers.SerializableImage;
import com.jpexs.helpers.utf8.Utf8Helper;
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
@@ -2753,7 +2755,7 @@ public final class SWF implements SWFContainerItem, Timelined {
return exporter.getUniqueId("tag");
}
public static SerializableImage frameToImageGet(Timeline timeline, int frame, int time, DepthState stateUnderCursor, int mouseButton, RECT displayRect, Matrix transformation, ColorTransform colorTransform, Color backGroundColor, boolean useCache, double zoom) {
public static SerializableImage frameToImageGet(Timeline timeline, int frame, int time, Point cursorPosition, int mouseButton, RECT displayRect, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform, Color backGroundColor, boolean useCache, double zoom) {
SWF swf = timeline.swf;
String key = "frame_" + frame + "_" + time + "_" + timeline.id + "_" + swf.hashCode() + "_" + zoom;
SerializableImage image;
@@ -2784,9 +2786,9 @@ public final class SWF implements SWFContainerItem, Timelined {
m.translate(-rect.Xmin * zoom, -rect.Ymin * zoom);
m.scale(zoom);
RenderContext renderContext = new RenderContext();
renderContext.stateUnderCursor = stateUnderCursor;
renderContext.cursorPosition = cursorPosition;
renderContext.mouseButton = mouseButton;
frameToImage(timeline, frame, time, renderContext, image, m, colorTransform);
frameToImage(timeline, frame, time, renderContext, image, false, m, absoluteTransformation, colorTransform);
if (useCache) {
swf.putToCache(key, image);
}
@@ -2794,7 +2796,7 @@ public final class SWF implements SWFContainerItem, Timelined {
return image;
}
public static void framesToImage(Timeline timeline, List<SerializableImage> ret, int startFrame, int stopFrame, RenderContext renderContext, RECT displayRect, int totalFrameCount, Stack<Integer> visited, Matrix transformation, ColorTransform colorTransform, double zoom) {
public static void framesToImage(Timeline timeline, List<SerializableImage> ret, int startFrame, int stopFrame, RenderContext renderContext, RECT displayRect, int totalFrameCount, Stack<Integer> visited, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform, double zoom) {
RECT rect = displayRect;
for (int f = 0; f < timeline.getFrameCount(); f++) {
SerializableImage image = new SerializableImage((int) (rect.getWidth() / SWF.unitDivisor) + 1,
@@ -2802,12 +2804,12 @@ public final class SWF implements SWFContainerItem, Timelined {
image.fillTransparent();
Matrix m = new Matrix();
m.translate(-rect.Xmin, -rect.Ymin);
frameToImage(timeline, f, 0, renderContext, image, m, colorTransform);
frameToImage(timeline, f, 0, renderContext, image, false, m, absoluteTransformation, colorTransform);
ret.add(image);
}
}
public static void frameToImage(Timeline timeline, int frame, int time, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) {
public static void frameToImage(Timeline timeline, int frame, int time, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
double unzoom = SWF.unitDivisor;
if (timeline.getFrameCount() <= frame) {
return;
@@ -2841,8 +2843,9 @@ public final class SWF implements SWFContainerItem, Timelined {
}
CharacterTag character = timeline.swf.getCharacter(layer.characterId);
Matrix mat = new Matrix(layer.matrix);
mat = mat.preConcatenate(transformation);
Matrix layerMatrix = new Matrix(layer.matrix);
Matrix mat = transformation.concatenate(layerMatrix);
Matrix absMat = absoluteTransformation.concatenate(layerMatrix);
if (colorTransform == null) {
colorTransform = new ColorTransform();
@@ -2862,24 +2865,6 @@ public final class SWF implements SWFContainerItem, Timelined {
drawableFrameCount = 1;
}
int dframe;
if (timeline.fontFrameNum != -1) {
dframe = timeline.fontFrameNum;
} else {
dframe = time % drawableFrameCount;
}
if (character instanceof ButtonTag) {
dframe = ButtonTag.FRAME_UP;
if (renderContext.stateUnderCursor == layer) {
if (renderContext.mouseButton > 0) {
dframe = ButtonTag.FRAME_DOWN;
} else {
dframe = ButtonTag.FRAME_OVER;
}
}
}
RECT boundRect = drawable.getRect();
ExportRectangle rect = new ExportRectangle(boundRect);
rect = mat.transform(rect);
@@ -2926,11 +2911,34 @@ public final class SWF implements SWFContainerItem, Timelined {
img = renderContext.shapeCache.get(cacheKey);
}
int dframe;
if (timeline.fontFrameNum != -1) {
dframe = timeline.fontFrameNum;
} else {
dframe = time % drawableFrameCount;
}
if (character instanceof ButtonTag) {
dframe = ButtonTag.FRAME_UP;
if (renderContext.cursorPosition != null) {
Shape buttonShape = drawable.getOutline(ButtonTag.FRAME_HITTEST, time, layer.ratio, renderContext, absMat);
if (buttonShape.contains(renderContext.cursorPosition)) {
renderContext.mouseOverButton = (ButtonTag) character;
if (renderContext.mouseButton > 0) {
dframe = ButtonTag.FRAME_DOWN;
} else {
dframe = ButtonTag.FRAME_OVER;
}
}
}
}
int stateCount = renderContext.stateUnderCursor == null ? 0 : renderContext.stateUnderCursor.size();
if (img == null) {
img = new SerializableImage(newWidth, newHeight, SerializableImage.TYPE_INT_ARGB);
img.fillTransparent();
drawable.toImage(dframe, time, layer.ratio, renderContext, img, m, clrTrans);
drawable.toImage(dframe, time, layer.ratio, renderContext, img, isClip || layer.clipDepth > -1, m, absMat, clrTrans);
if (cacheKey != null) {
renderContext.shapeCache.put(cacheKey, img);
@@ -3031,6 +3039,27 @@ public final class SWF implements SWFContainerItem, Timelined {
g.setTransform(AffineTransform.getTranslateInstance(0, 0));
g.setClip(clip.shape);
} else {
if (renderContext.cursorPosition != null) {
if (drawable instanceof DefineSpriteTag) {
if (renderContext.stateUnderCursor.size() > stateCount) {
renderContext.stateUnderCursor.add(layer);
}
} else if (absMat.transform(new ExportRectangle(boundRect)).contains(renderContext.cursorPosition)) {
Shape shape = drawable.getOutline(dframe, time, layer.ratio, renderContext, absMat);
if (shape.contains(renderContext.cursorPosition)) {
renderContext.stateUnderCursor.add(layer);
}
}
}
if (renderContext.borderImage != null) {
Graphics2D g2 = (Graphics2D) renderContext.borderImage.getGraphics();
g2.setPaint(Color.red);
g2.setStroke(new BasicStroke(2));
Shape shape = drawable.getOutline(dframe, time, layer.ratio, renderContext, absMat.preConcatenate(Matrix.getScaleInstance(1 / SWF.unitDivisor)));
g2.draw(shape);
}
g.setTransform(trans);
g.drawImage(img.getBufferedImage(), 0, 0, null);
}
@@ -3039,9 +3068,10 @@ public final class SWF implements SWFContainerItem, Timelined {
}
if (showPlaceholder) {
mat.translateX /= unzoom;
mat.translateY /= unzoom;
AffineTransform trans = mat.toTransform();
Matrix mat2 = mat.clone();
mat2.translateX /= unzoom;
mat2.translateY /= unzoom;
AffineTransform trans = mat2.toTransform();
g.setTransform(trans);
BoundedTag b = (BoundedTag) character;
g.setPaint(new Color(255, 255, 255, 128));

View File

@@ -359,7 +359,7 @@ public class FrameExporter {
}
int fframe = fframes.get(pos++);
BufferedImage result = SWF.frameToImageGet(ftim, fframe, fframe, null, 0, ftim.displayRect, new Matrix(), new ColorTransform(), fbackgroundColor, false, settings.zoom).getBufferedImage();
BufferedImage result = SWF.frameToImageGet(ftim, fframe, fframe, null, 0, ftim.displayRect, new Matrix(), new Matrix(), new ColorTransform(), fbackgroundColor, false, settings.zoom).getBufferedImage();
if (evl != null) {
evl.handleExportedEvent("frame", pos, fframes.size(), tagName);

View File

@@ -122,7 +122,7 @@ public class ShapeExporter {
Matrix m = new Matrix();
m.translate(-rect.Xmin, -rect.Ymin);
m.scale(settings.zoom);
st.toImage(0, 0, 0, new RenderContext(), img, m, new CXFORMWITHALPHA());
st.toImage(0, 0, 0, new RenderContext(), img, false, m, m, new CXFORMWITHALPHA());
if (settings.mode == ShapeExportMode.PNG) {
ImageHelper.write(img.getBufferedImage(), ImageFormat.PNG, file);
} else {

View File

@@ -17,6 +17,7 @@
package com.jpexs.decompiler.flash.exporters.commonshape;
import com.jpexs.decompiler.flash.types.RECT;
import java.awt.Point;
import java.awt.geom.Rectangle2D;
/**
@@ -62,6 +63,12 @@ public class ExportRectangle {
return yMax - yMin;
}
public boolean contains(Point point) {
int x = point.x;
int y = point.y;
return xMin <= x && xMax >= x && yMin <= y && yMax >= y;
}
@Override
public int hashCode() {
long bits = Double.doubleToLongBits(xMin);

View File

@@ -916,7 +916,7 @@ public class DefineEditTextTag extends TextTag {
}
@Override
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) {
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
render(TextRenderMode.BITMAP, image, null, null, transformation, colorTransform, 1);
}

View File

@@ -366,8 +366,8 @@ public class DefineSpriteTag extends CharacterTag implements DrawableTag, Timeli
}
@Override
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) {
SWF.frameToImage(getTimeline(), frame, time, renderContext, image, transformation, colorTransform);
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
SWF.frameToImage(getTimeline(), frame, time, renderContext, image, isClip, transformation, absoluteTransformation, colorTransform);
}
@Override

View File

@@ -92,8 +92,8 @@ public abstract class ButtonTag extends CharacterTag implements DrawableTag, Tim
}
@Override
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) {
SWF.frameToImage(getTimeline(), frame, time, renderContext, image, transformation, colorTransform);
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
SWF.frameToImage(getTimeline(), frame, time, renderContext, image, isClip, transformation, absoluteTransformation, colorTransform);
}
@Override

View File

@@ -39,7 +39,7 @@ public interface DrawableTag extends BoundedTag {
public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation);
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform);
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform);
public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, double zoom) throws IOException;

View File

@@ -323,7 +323,7 @@ public abstract class FontTag extends CharacterTag implements AloneTag, Drawable
}
@Override
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) {
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
SHAPERECORD.shapeListToImage(swf, getGlyphShapeTable(), image, frame, Color.black, colorTransform);
}

View File

@@ -283,7 +283,7 @@ public abstract class ImageTag extends CharacterTag implements DrawableTag {
}
@Override
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) {
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
BitmapExporter.export(swf, getShape(), null, image, transformation, colorTransform);
}

View File

@@ -279,7 +279,7 @@ public abstract class MorphShapeTag extends CharacterTag implements DrawableTag
}
@Override
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) {
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
SHAPEWITHSTYLE shape = getShapeAtRatio(ratio);
// morphShape using shapeNum=3, morphShape2 using shapeNum=4
// todo: Currently the generated image is not cached, because the cache

View File

@@ -18,7 +18,9 @@ package com.jpexs.decompiler.flash.tags.base;
import com.jpexs.decompiler.flash.timeline.DepthState;
import com.jpexs.helpers.SerializableImage;
import java.awt.Point;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
@@ -27,9 +29,15 @@ import java.util.Map;
*/
public class RenderContext {
public DepthState stateUnderCursor;
public Point cursorPosition;
public List<DepthState> stateUnderCursor;
public int mouseButton;
public ButtonTag mouseOverButton;
public Map<String, SerializableImage> shapeCache = new HashMap<>();
public SerializableImage borderImage;
}

View File

@@ -132,7 +132,7 @@ public abstract class ShapeTag extends CharacterTag implements DrawableTag, Lazy
}
@Override
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) {
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
BitmapExporter.export(swf, getShapes(), null, image, transformation, colorTransform);
if (Configuration.debugMode.get()) { // show control points
List<GeneralPath> paths = PathExporter.export(swf, getShapes());

View File

@@ -654,7 +654,7 @@ public abstract class StaticTextTag extends TextTag {
}
@Override
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) {
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
staticTextToImage(swf, textRecords, getTextNum(), image, textMatrix, transformation, colorTransform);
/*try {
TextTag originalTag = (TextTag) getOriginalTag();

View File

@@ -45,6 +45,7 @@ import com.jpexs.decompiler.flash.types.MATRIX;
import com.jpexs.decompiler.flash.types.RECT;
import com.jpexs.decompiler.flash.types.filters.FILTER;
import com.jpexs.helpers.SerializableImage;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.Area;
@@ -529,8 +530,8 @@ public class Timeline {
return modified;
}
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) {
SWF.frameToImage(this, frame, time, renderContext, image, transformation, colorTransform);
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
SWF.frameToImage(this, frame, time, renderContext, image, isClip, transformation, absoluteTransformation, colorTransform);
}
public void toHtmlCanvas(StringBuilder result, double unitDivisor, List<Integer> frames) {
@@ -568,7 +569,7 @@ public class Timeline {
}
}
public void getObjectsOutlines(int frame, int time, int ratio, DepthState stateUnderCursor, int mouseButton, Matrix transformation, List<DepthState> objs, List<Shape> outlines) {
public void getObjectsOutlines(int frame, int time, int ratio, Point cursorPosition, int mouseButton, Matrix transformation, List<DepthState> objs, List<Shape> outlines) {
Frame fr = getFrame(frame);
Stack<Clip> clips = new Stack<>();
for (int d = maxDepth; d >= 0; d--) {
@@ -592,8 +593,7 @@ public class Timeline {
CharacterTag character = swf.getCharacter(layer.characterId);
if (character instanceof DrawableTag) {
DrawableTag drawable = (DrawableTag) character;
Matrix m = new Matrix(layer.matrix);
m = m.preConcatenate(transformation);
Matrix m = transformation.concatenate(new Matrix(layer.matrix));
int drawableFrameCount = drawable.getNumFrames();
if (drawableFrameCount == 0) {
@@ -616,7 +616,7 @@ public class Timeline {
}
RenderContext renderContext = new RenderContext();
renderContext.stateUnderCursor = stateUnderCursor;
renderContext.cursorPosition = cursorPosition;
renderContext.mouseButton = mouseButton;
Shape cshape = ((DrawableTag) character).getOutline(dframe, layer.time + time, layer.ratio, renderContext, m);
@@ -634,7 +634,7 @@ public class Timeline {
outlines.add(addArea);
}
if (character instanceof Timelined) {
((Timelined) character).getTimeline().getObjectsOutlines(dframe, time + layer.time, layer.ratio, stateUnderCursor, mouseButton, m, objs, outlines);
((Timelined) character).getTimeline().getObjectsOutlines(dframe, time + layer.time, layer.ratio, cursorPosition, mouseButton, m, objs, outlines);
}
}
}
@@ -672,12 +672,14 @@ public class Timeline {
if (drawableFrameCount == 0) {
drawableFrameCount = 1;
}
int dframe = (time + layer.time) % drawableFrameCount;
if (character instanceof Timelined) {
if (character instanceof ButtonTag) {
ButtonTag bt = (ButtonTag) character;
dframe = ButtonTag.FRAME_UP;
if (renderContext.stateUnderCursor == layer) {
if (character instanceof ButtonTag) {
dframe = ButtonTag.FRAME_UP;
if (renderContext.cursorPosition != null) {
ButtonTag buttonTag = (ButtonTag) character;
Shape buttonShape = buttonTag.getOutline(ButtonTag.FRAME_HITTEST, time, layer.ratio, renderContext, m);
if (buttonShape.contains(renderContext.cursorPosition)) {
if (renderContext.mouseButton > 0) {
dframe = ButtonTag.FRAME_DOWN;
} else {
@@ -688,13 +690,13 @@ public class Timeline {
}
Shape cshape = ((DrawableTag) character).getOutline(dframe, time + layer.time, layer.ratio, renderContext, m);
Area addArea = new Area(cshape);
if (currentClip != null) {
Area a = new Area(new Rectangle(displayRect.Xmin, displayRect.Ymin, displayRect.getWidth(), displayRect.getHeight()));
a.subtract(new Area(currentClip.shape));
addArea.subtract(a);
}
if (layer.clipDepth > -1) {
Clip clip = new Clip(addArea, layer.clipDepth);
clips.push(clip);

View File

@@ -1824,7 +1824,7 @@ public class Graph {
pos++;
continue;
}*/
//if (p != defaultPart)
//if (p != defaultPart)
{
if (vis.contains(p)) {
valueMappings.add(caseCommands.size() - 1);
@@ -1849,7 +1849,7 @@ public class Graph {
if (next != p) {
//if (p == defaultPart && !defaultCommands.isEmpty()) {
//ignore
//} else
//} else
{
TranslateStack s2 = (TranslateStack) stack.clone();
s2.clear();
@@ -1890,7 +1890,7 @@ public class Graph {
}
}
}
//remove last break from last section
//remove last break from last section
if (!caseCommands.isEmpty()) {
List<GraphTargetItem> lastc = caseCommands.get(caseCommands.size() - 1);
if (!lastc.isEmpty() && (lastc.get(lastc.size() - 1) instanceof BreakItem)) {