mirror of
https://github.com/bancika/diy-layout-creator
synced 2026-11-10 17:22:09 +10:00
caching changes
This commit is contained in:
@@ -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,20 +27,21 @@ 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);
|
||||
|
||||
public static DrawingCache Instance = new DrawingCache();
|
||||
@@ -52,7 +53,7 @@ public class DrawingCache {
|
||||
.extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) component.getClass());
|
||||
|
||||
if (type.getEnableCache()) {
|
||||
// if we need to apply caching
|
||||
// if we need to apply caching
|
||||
Point firstPoint = component.getControlPoint(0);
|
||||
Point lastPoint = component.getControlPoint(component.getControlPointCount() - 1);
|
||||
|
||||
@@ -60,58 +61,91 @@ public class DrawingCache {
|
||||
CacheValue value = null;
|
||||
if (imageCache.containsKey(component))
|
||||
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;
|
||||
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D cg2d = image.createGraphics();
|
||||
|
||||
// copy over rendering settings
|
||||
// copy over rendering settings
|
||||
cg2d.setRenderingHints(g2d.getRenderingHints());
|
||||
|
||||
|
||||
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);
|
||||
G2DWrapper wrapper = new G2DWrapper(cg2d, zoom);
|
||||
|
||||
// wrap the graphics so we can track
|
||||
G2DWrapper wrapper = new G2DWrapper(cg2d, zoom);
|
||||
|
||||
wrapper.startedDrawingComponent();
|
||||
if (!trackArea) {
|
||||
wrapper.stopTracking();
|
||||
}
|
||||
|
||||
|
||||
// now draw the component to the buffer image
|
||||
component.draw(wrapper, componentState, outlineMode, project, wrapper);
|
||||
|
||||
|
||||
wrapper.finishedDrawingComponent();
|
||||
|
||||
cg2d.dispose();
|
||||
|
||||
cg2d.dispose();
|
||||
|
||||
// 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);
|
||||
|
||||
value = new CacheValue(component, image, wrapper, componentState);
|
||||
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());
|
||||
} else {
|
||||
// no caching, just draw as usual
|
||||
component.draw(g2d, componentState, outlineMode, project, g2d);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
imageCache.clear();
|
||||
}
|
||||
|
||||
private class CacheValue {
|
||||
IDIYComponent<?> component;
|
||||
BufferedImage image;
|
||||
G2DWrapper wrapper;
|
||||
G2DWrapper wrapper;
|
||||
ComponentState state;
|
||||
|
||||
public CacheValue(IDIYComponent<?> component, BufferedImage image, G2DWrapper wrapper, ComponentState state) {
|
||||
double zoom;
|
||||
|
||||
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,8 +155,9 @@ public class DrawingCache {
|
||||
this.image = image;
|
||||
this.wrapper = wrapper;
|
||||
this.state = state;
|
||||
this.zoom = zoom;
|
||||
}
|
||||
|
||||
|
||||
public IDIYComponent<?> getComponent() {
|
||||
return component;
|
||||
}
|
||||
@@ -130,18 +165,22 @@ public class DrawingCache {
|
||||
public BufferedImage getImage() {
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
public G2DWrapper getWrapper() {
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
|
||||
public ComponentState getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public double getZoom() {
|
||||
return zoom;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return component.getName() + ":" + state;
|
||||
public String toString() {
|
||||
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.");
|
||||
}
|
||||
@@ -427,6 +433,11 @@ public class DrawingManager {
|
||||
g2d.setColor(theme.getOutlineColor());
|
||||
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.";
|
||||
|
||||
Reference in New Issue
Block a user