caching changes

This commit is contained in:
bancika
2020-04-06 11:05:31 +02:00
parent 861fa87232
commit 652bb4514d
6 changed files with 94 additions and 37 deletions
@@ -60,5 +60,9 @@ public enum DrawOption {
/**
* Include extra space around the layout.
*/
EXTRA_SPACE;
EXTRA_SPACE,
/**
* Whether components should be cached or not.
*/
ENABLE_CACHING;
}
@@ -27,19 +27,20 @@ import org.apache.log4j.Logger;
import org.diylc.common.ComponentType;
import org.diylc.core.ComponentState;
import org.diylc.core.IDIYComponent;
import org.diylc.core.IDrawingObserver;
import org.diylc.core.Project;
/**
* A layer that injects itself between the provided {@link G2DWrapper} instance and the underlying {@link Graphics2D} instance.
* For all components that are enabled for caching, it stores a {@link BufferedImage} representing the component.
* The state of the component is recorded and compared next time it needs to be rendered to make sure that the cache is up to date.
* A layer that injects itself between the provided {@link G2DWrapper} instance and the underlying
* {@link Graphics2D} instance. For all components that are enabled for caching, it stores a
* {@link BufferedImage} representing the component. The state of the component is recorded and
* compared next time it needs to be rendered to make sure that the cache is up to date.
*
* @author bancika
*/
public class DrawingCache {
private Map<IDIYComponent<?>, CacheValue> imageCache = new HashMap<IDIYComponent<?>, CacheValue>();
private Map<IDIYComponent<?>, CacheValue> imageCache =
new HashMap<IDIYComponent<?>, CacheValue>();
private static final Logger LOG = Logger.getLogger(DrawingCache.class);
@@ -62,7 +63,8 @@ public class DrawingCache {
value = imageCache.get(component);
// only honor the cache if the component hasn't changed in the meantime
if (value == null || !value.getComponent().equalsTo(component) || value.getState() != componentState) {
if (value == null || !value.getComponent().equalsTo(component)
|| value.getState() != componentState || value.getZoom() != zoom) {
LOG.trace("Rendering " + component.getName() + " for cache.");
int width = (int) (Math.abs(firstPoint.x - lastPoint.x) * zoom) + 2;
int height = (int) (Math.abs(firstPoint.y - lastPoint.y) * zoom) + 2;
@@ -74,8 +76,14 @@ public class DrawingCache {
cg2d.setClip(0, 0, width, height);
// apply zoom
if (Math.abs(1.0 - zoom) > 1e-4) {
cg2d.scale(zoom, zoom);
}
// translate to make the top-left corner of the component match (0, 0)
cg2d.translate(-firstPoint.x, -firstPoint.y);
// wrap the graphics so we can track
G2DWrapper wrapper = new G2DWrapper(cg2d, zoom);
wrapper.startedDrawingComponent();
@@ -90,12 +98,32 @@ public class DrawingCache {
cg2d.dispose();
value = new CacheValue(component, image, wrapper, componentState);
// File outputfile = new File("d:\\image_" + component.getName() + ".png");
// try {
// ImageIO.write(image, "png", outputfile);
// } catch (IOException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
value = new CacheValue(component, image, wrapper, componentState, zoom);
imageCache.put(component, value);
}
// draw cached image
g2d.getCanvasGraphics().drawImage(value.getImage(), firstPoint.x, firstPoint.y, null);
// temporarily scale the graphic to compensate for the zoom, since we are rendering an image with the zoom appled
if (Math.abs(1.0 - zoom) > 1e-4) {
g2d.getCanvasGraphics().scale(1 / zoom, 1 / zoom);
}
try {
// draw cached image
g2d.getCanvasGraphics().drawImage(value.getImage(), (int) (firstPoint.x * zoom),
(int) (firstPoint.y * zoom), null);
} finally {
if (Math.abs(1.0 - zoom) > 1e-4) {
g2d.getCanvasGraphics().scale(zoom, zoom);
}
}
// copy over tracking area from the cache
g2d.merge(value.getWrapper());
@@ -105,13 +133,19 @@ public class DrawingCache {
}
}
public void clear() {
imageCache.clear();
}
private class CacheValue {
IDIYComponent<?> component;
BufferedImage image;
G2DWrapper wrapper;
ComponentState state;
double zoom;
public CacheValue(IDIYComponent<?> component, BufferedImage image, G2DWrapper wrapper, ComponentState state) {
public CacheValue(IDIYComponent<?> component, BufferedImage image, G2DWrapper wrapper,
ComponentState state, double zoom) {
super();
// take a copy of the component, so we can check if it changed in the meantime
try {
@@ -121,6 +155,7 @@ public class DrawingCache {
this.image = image;
this.wrapper = wrapper;
this.state = state;
this.zoom = zoom;
}
public IDIYComponent<?> getComponent() {
@@ -139,9 +174,13 @@ public class DrawingCache {
return state;
}
public double getZoom() {
return zoom;
}
@Override
public String toString() {
return component.getName() + ":" + state;
return component.getName() + ":" + state + ":" + zoom;
}
}
}
@@ -39,6 +39,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.apache.log4j.Logger;
import org.diylc.appframework.miscutils.ConfigurationManager;
@@ -138,6 +139,7 @@ public class DrawingManager {
IComponentFiler filter, Rectangle selectionRect, Collection<IDIYComponent<?>> selectedComponents,
Set<IDIYComponent<?>> lockedComponents, Set<IDIYComponent<?>> groupedComponents, List<Point> controlPointSlot,
List<IDIYComponent<?>> componentSlot, boolean dragInProgress, Double externalZoom) {
long start = System.nanoTime();
failedComponents.clear();
if (project == null) {
return failedComponents;
@@ -276,8 +278,12 @@ public class DrawingManager {
}
// Draw the component through the g2dWrapper.
try {
// component.draw(g2dWrapper, state, drawOptions.contains(DrawOption.OUTLINE_MODE), project, g2dWrapper);
DrawingCache.Instance.draw(component, g2dWrapper, state, drawOptions.contains(DrawOption.OUTLINE_MODE), project, zoom, trackArea);
if (drawOptions.contains(DrawOption.ENABLE_CACHING)) // go through the DrawingCache
DrawingCache.Instance.draw(component, g2dWrapper, state, drawOptions.contains(DrawOption.OUTLINE_MODE), project, zoom, trackArea);
else // go stragiht to the wrapper
component.draw(g2dWrapper, state, drawOptions.contains(DrawOption.OUTLINE_MODE), project, g2dWrapper);
if (g2dWrapper.isTrackingContinuityArea()) {
LOG.info("Component " + component.getName() + " of type " + component.getClass().getName() + " did not stop tracking continuity area.");
}
@@ -428,6 +434,11 @@ public class DrawingManager {
g2d.fill(extraSpaceArea);
}
long end = System.nanoTime();
long ms = TimeUnit.MILLISECONDS.convert(end - start, TimeUnit.NANOSECONDS);
LOG.trace(String.format("Render time = %d ms", ms));
return failedComponents;
}
@@ -284,6 +284,7 @@ public class Presenter implements IPlugInPort {
instantiationManager.fillWithDefaultProperties(project, null);
loadProject(project, true, null);
projectFileManager.startNewFile();
DrawingCache.Instance.clear();
} catch (Exception e) {
LOG.error("Could not create new file", e);
view.showMessage("Could not create a new file. Check the log for details.", "Error", IView.ERROR_MESSAGE);
@@ -309,6 +310,7 @@ public class Presenter implements IPlugInPort {
view.showMessage(builder.toString(), "Warning", IView.WARNING_MESSAGE);
}
addToRecentFiles(fileName);
DrawingCache.Instance.clear();
} catch (Exception ex) {
LOG.error("Could not load file", ex);
String errorMessage = "Could not open file " + fileName + ". Check the log for details.";
@@ -1,4 +1,4 @@
log4j.rootLogger = DEBUG, fileout, stdout
log4j.rootLogger = TRACE, fileout, stdout
log4j.appender.fileout = org.diylc.appframework.miscutils.NewLogForEachRunFileAppender
log4j.appender.fileout.layout.ConversionPattern = %d{ABSOLUTE} %5p [%t] %c{1} - %m%n
log4j.appender.fileout.layout = org.apache.log4j.PatternLayout
@@ -266,6 +266,7 @@ public class CanvasPanel extends JComponent implements Autoscroll {
if (ConfigurationManager.getInstance().readBoolean(IPlugInPort.EXTRA_SPACE_KEY, true)) {
drawOptions.add(DrawOption.EXTRA_SPACE);
}
drawOptions.add(DrawOption.ENABLE_CACHING);
plugInPort.draw(g2d, drawOptions, null, null);