/* * JAME 6.2.1 * http://jame.sourceforge.net * * Copyright 2001, 2016 Andrea Medeghini * * This file is part of JAME. * * JAME is an application for creating fractals and other graphics artifacts. * * JAME is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * JAME 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with JAME. If not, see <http://www.gnu.org/licenses/>. * */ package net.sf.jame.twister.renderer; import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Graphics2D; import java.util.HashMap; import java.util.Map; import net.sf.jame.core.util.IntegerVector2D; import net.sf.jame.core.util.Surface; import net.sf.jame.core.util.SurfacePool; import net.sf.jame.core.util.Tile; import net.sf.jame.twister.TwisterRuntime; import net.sf.jame.twister.frame.FrameRuntimeElement; import net.sf.jame.twister.frameFilter.FrameFilterRuntimeElement; import net.sf.jame.twister.image.ImageRuntimeElement; import net.sf.jame.twister.layer.GroupLayerRuntimeElement; import net.sf.jame.twister.layer.ImageLayerRuntimeElement; import net.sf.jame.twister.layer.LayerRuntimeElement; import net.sf.jame.twister.layerFilter.LayerFilterRuntimeElement; /** * @author Andrea Medeghini */ public class DefaultTwisterRenderer implements TwisterRenderer { private static final Color TRANSPARENT_COLOR = new Color(0, 0, 0, 0); private Map<Object, Object> hints = new HashMap<Object, Object>(); private TwisterRuntime runtime; private SurfacePool surfacePool; private Surface currentSurface; private Surface previousSurface; private IntegerVector2D bufferSize; private Tile tile; private Color color; private boolean isDynamic; /** * @param context * @param runtime */ public DefaultTwisterRenderer(final TwisterRuntime runtime) { this.runtime = runtime; } /** * @see java.lang.Object#finalize() */ @Override protected void finalize() throws Throwable { dispose(); super.finalize(); } /** * @see net.sf.jame.twister.renderer.TwisterRenderer#drawImage(java.awt.Graphics2D) */ public void drawImage(final Graphics2D g) { if ((runtime == null) || (tile == null)) { return; } if (runtime.getFrameElement() != null) { final Graphics2D g2d = currentSurface.getGraphics2D(); g2d.setComposite(AlphaComposite.SrcOver); g2d.setColor(color); g2d.fillRect(0, 0, currentSurface.getWidth(), currentSurface.getHeight()); currentSurface = drawFrame(runtime.getFrameElement(), currentSurface); g.setClip(tile.getTileOffset().getX(), tile.getTileOffset().getY(), tile.getTileSize().getX() + 1, tile.getTileSize().getY() + 1); // g.setColor(Color.RED); // g.fillRect(tile.getTileOffset().getX(), tile.getTileOffset().getY(), tile.getTileSize().getX(), tile.getTileSize().getY()); g.drawImage(currentSurface.getImage(), tile.getTileOffset().getX() - tile.getTileBorder().getX(), tile.getTileOffset().getY() - tile.getTileBorder().getY(), null); g.setClip(null); final Surface tmpSurface = currentSurface; currentSurface = previousSurface; previousSurface = tmpSurface; } } /** * @see net.sf.jame.twister.renderer.TwisterRenderer#drawImage(java.awt.Graphics2D, int, int) */ public void drawImage(final Graphics2D g, final int x, final int y) { if ((runtime == null) || (tile == null)) { return; } if (runtime.getFrameElement() != null) { final Graphics2D g2d = currentSurface.getGraphics2D(); g2d.setComposite(AlphaComposite.SrcOver); g2d.setColor(color); g2d.fillRect(0, 0, currentSurface.getWidth(), currentSurface.getHeight()); currentSurface = drawFrame(runtime.getFrameElement(), currentSurface); g.setClip(x + tile.getTileOffset().getX(), y + tile.getTileOffset().getY(), tile.getTileSize().getX() + 1, tile.getTileSize().getY() + 1); // g.setColor(Color.RED); // g.fillRect(tile.getTileOffset().getX(), tile.getTileOffset().getY(), tile.getTileSize().getX(), tile.getTileSize().getY()); g.drawImage(currentSurface.getImage(), x + tile.getTileOffset().getX() - tile.getTileBorder().getX(), y + tile.getTileOffset().getY() - tile.getTileBorder().getY(), null); g.setClip(null); final Surface tmpSurface = currentSurface; currentSurface = previousSurface; previousSurface = tmpSurface; } } /** * @see net.sf.jame.twister.renderer.TwisterRenderer#drawImage(java.awt.Graphics2D, int, int, int, int) */ public void drawImage(final Graphics2D g, final int x, final int y, final int w, final int h) { if ((runtime == null) || (tile == null)) { return; } if (runtime.getFrameElement() != null) { final Graphics2D g2d = currentSurface.getGraphics2D(); g2d.setComposite(AlphaComposite.SrcOver); g2d.setColor(color); g2d.fillRect(0, 0, currentSurface.getWidth(), currentSurface.getHeight()); currentSurface = drawFrame(runtime.getFrameElement(), currentSurface); final double sx = w / (double) tile.getTileSize().getX(); final double sy = h / (double) tile.getTileSize().getY(); final int dw = (int) Math.rint(bufferSize.getX() * sx); final int dh = (int) Math.rint(bufferSize.getY() * sy); g.setClip(x, y, dw, dh); // g.setColor(Color.RED); // g.fillRect(x, y, dw, dh); g.drawImage(currentSurface.getImage(), x - tile.getTileBorder().getX(), y - tile.getTileBorder().getY(), dw, dh, null); g.setClip(null); final Surface tmpSurface = currentSurface; currentSurface = previousSurface; previousSurface = tmpSurface; } } /** * @see net.sf.jame.twister.renderer.TwisterRenderer#drawImage(java.awt.Graphics2D, int, int, int, int, int, int) */ public void drawImage(final Graphics2D g, final int x, final int y, final int w, final int h, final int bx, final int by) { if ((runtime == null) || (tile == null)) { return; } if (runtime.getFrameElement() != null) { final Graphics2D g2d = currentSurface.getGraphics2D(); g2d.setComposite(AlphaComposite.SrcOver); g2d.setColor(color); g2d.fillRect(0, 0, currentSurface.getWidth(), currentSurface.getHeight()); currentSurface = drawFrame(runtime.getFrameElement(), currentSurface); final double sx = w / (double) tile.getTileSize().getX(); final double sy = h / (double) tile.getTileSize().getY(); final int dw = (int) Math.rint(bufferSize.getX() * sx); final int dh = (int) Math.rint(bufferSize.getY() * sy); g.setClip(x + bx, y + by, dw - 2 * bx, dh - 2 * by); // g.setColor(Color.RED); // g.fillRect(x, y, dw, dh); g.drawImage(currentSurface.getImage(), x - tile.getTileBorder().getX(), y - tile.getTileBorder().getY(), dw, dh, null); g.setClip(null); final Surface tmpSurface = currentSurface; currentSurface = previousSurface; previousSurface = tmpSurface; } } /** * @see net.sf.jame.twister.renderer.TwisterRenderer#startRenderer() */ public void startRenderer() { if (runtime == null) { return; } startLayers(runtime.getFrameElement()); } /** * @see net.sf.jame.twister.renderer.TwisterRenderer#stopRenderer() */ public void stopRenderer() { if (runtime == null) { return; } try { abortLayers(runtime.getFrameElement()); joinLayers(runtime.getFrameElement()); } catch (final InterruptedException e) { Thread.currentThread().interrupt(); } } /** * @see net.sf.jame.twister.renderer.TwisterRenderer#stopRenderer() */ public void abortRenderer() { if (runtime == null) { return; } abortLayers(runtime.getFrameElement()); } /** * @see net.sf.jame.twister.renderer.TwisterRenderer#stopRenderer() */ public void joinRenderer() { if (runtime == null) { return; } try { joinLayers(runtime.getFrameElement()); } catch (final InterruptedException e) { Thread.currentThread().interrupt(); } } private void startLayers(final FrameRuntimeElement frame) { final int layerCount = frame.getLayerCount(); for (int i = 0; i < layerCount; i++) { this.startLayer(frame.getLayer(i)); } startFilter(frame); } private void startLayer(final ImageLayerRuntimeElement layer) { if ((layer.getImage() != null) && (layer.getImage().getImageRuntime() != null)) { layer.getImage().getImageRuntime().setRenderingHints(hints); layer.getImage().getImageRuntime().setTile(tile); try { layer.getImage().getImageRuntime().startRenderer(); } catch (final Exception e) { e.printStackTrace(); } } startFilter(layer); } private void startLayer(final GroupLayerRuntimeElement layer) { final int sublayerCount = layer.getLayerCount(); for (int j = 0; j < sublayerCount; j++) { this.startLayer(layer.getLayer(j)); } startFilter(layer); } private void abortLayers(final FrameRuntimeElement frame) { final int layerCount = frame.getLayerCount(); for (int i = 0; i < layerCount; i++) { this.abortLayer(frame.getLayer(i)); } } private void abortLayer(final ImageLayerRuntimeElement layer) { if ((layer.getImage() != null) && (layer.getImage().getImageRuntime() != null)) { layer.getImage().getImageRuntime().abortRenderer(); } } private void abortLayer(final GroupLayerRuntimeElement layer) { final int sublayerCount = layer.getLayerCount(); for (int j = 0; j < sublayerCount; j++) { this.abortLayer(layer.getLayer(j)); } } private void joinLayers(final FrameRuntimeElement frame) throws InterruptedException { final int layerCount = frame.getLayerCount(); for (int i = 0; i < layerCount; i++) { this.joinLayer(frame.getLayer(i)); } } private void joinLayer(final ImageLayerRuntimeElement layer) throws InterruptedException { if ((layer.getImage() != null) && (layer.getImage().getImageRuntime() != null)) { layer.getImage().getImageRuntime().joinRenderer(); } } private void joinLayer(final GroupLayerRuntimeElement layer) throws InterruptedException { final int sublayerCount = layer.getLayerCount(); for (int j = 0; j < sublayerCount; j++) { this.joinLayer(layer.getLayer(j)); } } private void prepareLayers(final FrameRuntimeElement frame, final boolean isDynamicRequired) { isDynamic = false; final int layerCount = frame.getLayerCount(); for (int i = 0; i < layerCount; i++) { this.prepareLayer(frame.getLayer(i), isDynamicRequired); } final int filterCount = frame.getFilterCount(); for (int i = 0; i < filterCount; i++) { if (frame.getFilter(i).getFilterRuntime() != null) { frame.getFilter(i).getFilterRuntime().prepareFilter(isDynamic); } } } private void prepareLayer(final ImageLayerRuntimeElement layer, final boolean isDynamicRequired) { if ((layer.getImage() != null) && (layer.getImage().getImageRuntime() != null)) { layer.getImage().getImageRuntime().setRenderingHints(hints); layer.getImage().getImageRuntime().setTile(tile); layer.getImage().getImageRuntime().prepareImage(isDynamicRequired); isDynamic |= layer.getImage().getImageRuntime().isDynamic(); } final int filterCount = layer.getFilterCount(); for (int i = 0; i < filterCount; i++) { if (layer.getFilter(i).getFilterRuntime() != null) { layer.getFilter(i).getFilterRuntime().prepareFilter(); } } } private void prepareLayer(final GroupLayerRuntimeElement layer, final boolean isDynamicRequired) { final int sublayerCount = layer.getLayerCount(); for (int j = 0; j < sublayerCount; j++) { this.prepareLayer(layer.getLayer(j), isDynamicRequired); } final int filterCount = layer.getFilterCount(); for (int i = 0; i < filterCount; i++) { if (layer.getFilter(i).getFilterRuntime() != null) { layer.getFilter(i).getFilterRuntime().prepareFilter(); } } } private void startFilter(final LayerRuntimeElement layer) { final int filterCount = layer.getFilterCount(); for (int i = 0; i < filterCount; i++) { final LayerFilterRuntimeElement filter = layer.getFilter(i); if (filter.getFilterRuntime() != null) { filter.getFilterRuntime().setTile(tile); } } } private void startFilter(final FrameRuntimeElement frame) { final int filterCount = frame.getFilterCount(); for (int i = 0; i < filterCount; i++) { final FrameFilterRuntimeElement filter = frame.getFilter(i); if (filter.getFilterRuntime() != null) { filter.getFilterRuntime().setTile(tile); } } } private void drawImage(final ImageRuntimeElement image, final Surface tmpSurface0, final float opacity) { final Graphics2D g2d = tmpSurface0.getGraphics2D(); g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity)); if ((image != null) && (image.getImageRuntime() != null)) { image.getImageRuntime().drawImage(g2d); } else { // g2d.setColor(Color.BLACK); // g2d.fillRect(0, 0, tmpSurface0.getWidth(), tmpSurface0.getHeight()); } } private Surface filterImage(final LayerRuntimeElement layer, Surface tmpSurface0) { final int filterCount = layer.getFilterCount(); for (int i = 0; i < filterCount; i++) { final LayerFilterRuntimeElement filter = layer.getFilter(i); if ((filter.getFilterRuntime() != null) && filter.isEnabled()) { final Surface tmpSurface1 = surfacePool.getSurface(); filter.getFilterRuntime().renderImage(tmpSurface0, tmpSurface1); surfacePool.putSurface(tmpSurface0); tmpSurface0 = tmpSurface1; } } return tmpSurface0; } private void drawLayers(final FrameRuntimeElement frame, final Surface tmpSurface0, final float opacity) { final int layerCount = frame.getLayerCount(); for (int i = 0; i < layerCount; i++) { final GroupLayerRuntimeElement layer = frame.getLayer(i); if (layer.isVisible()) { this.drawLayer(layer, tmpSurface0, opacity); } } } private void drawLayer(final ImageLayerRuntimeElement layer, final Surface tmpSurface0, final float opacity) { if (layer.getFilterCount() > 0) { final Surface tmpSurface1 = surfacePool.getSurface(); final Graphics2D g2d0 = tmpSurface0.getGraphics2D(); final Graphics2D g2d1 = tmpSurface1.getGraphics2D(); g2d1.setComposite(AlphaComposite.Src); g2d1.setColor(TRANSPARENT_COLOR); g2d1.fillRect(0, 0, tmpSurface1.getWidth(), tmpSurface1.getHeight()); this.drawImage(layer.getImage(), tmpSurface1, 1f); final Surface tmpSurface2 = filterImage(layer, tmpSurface1); g2d0.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity * layer.getOpacity())); g2d0.drawImage(tmpSurface2.getImage(), 0, 0, null); surfacePool.putSurface(tmpSurface2); } else { this.drawImage(layer.getImage(), tmpSurface0, opacity * layer.getOpacity()); } } private void drawLayer(final GroupLayerRuntimeElement layer, final Surface tmpSurface0, final float opacity) { if (layer.getFilterCount() > 0) { final Surface tmpSurface1 = surfacePool.getSurface(); final int sublayerCount = layer.getLayerCount(); for (int j = 0; j < sublayerCount; j++) { final ImageLayerRuntimeElement sublayer = layer.getLayer(j); if (sublayer.isVisible()) { this.drawLayer(sublayer, tmpSurface1, 1f); } } final Surface tmpSurface2 = filterImage(layer, tmpSurface1); final Graphics2D g2d = tmpSurface0.getGraphics2D(); g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity * layer.getOpacity())); g2d.drawImage(tmpSurface2.getImage(), 0, 0, null); surfacePool.putSurface(tmpSurface2); } else { final int sublayerCount = layer.getLayerCount(); for (int j = 0; j < sublayerCount; j++) { final ImageLayerRuntimeElement sublayer = layer.getLayer(j); if (sublayer.isVisible()) { this.drawLayer(sublayer, tmpSurface0, opacity * layer.getOpacity()); } } } } private Surface drawFrame(final FrameRuntimeElement frame, Surface tmpSurface0) { drawLayers(frame, tmpSurface0, 1f); final int filterCount = frame.getFilterCount(); for (int i = 0; i < filterCount; i++) { final FrameFilterRuntimeElement filter = frame.getFilter(i); if ((filter.getFilterRuntime() != null) && filter.isEnabled()) { final Surface tmpSurface1 = surfacePool.getSurface(); filter.getFilterRuntime().renderImage(tmpSurface0, tmpSurface1, previousSurface); surfacePool.putSurface(tmpSurface0); tmpSurface0 = tmpSurface1; } } return tmpSurface0; } /** * @see net.sf.jame.twister.renderer.TwisterRenderer#getRuntime() */ public TwisterRuntime getRuntime() { return runtime; } /** * @see net.sf.jame.twister.renderer.TwisterRenderer#setRenderingHints(java.util.Map) */ public void setRenderingHints(final Map<Object, Object> hints) { this.hints = hints; } /** * @see net.sf.jame.twister.renderer.TwisterRenderer#getTile() */ public Tile getTile() { return tile; } /** * @see net.sf.jame.twister.renderer.TwisterRenderer#setTile(net.sf.jame.core.util.Tile) */ public void setTile(final Tile tile) { this.tile = tile; bufferSize = new IntegerVector2D(tile.getTileSize().getX() + tile.getTileBorder().getX() * 2, tile.getTileSize().getY() + tile.getTileBorder().getY() * 2); if ((surfacePool == null) || (surfacePool.getWidth() != bufferSize.getX()) || (surfacePool.getHeight() != bufferSize.getY())) { if (currentSurface != null) { currentSurface.dispose(); currentSurface = null; } if (previousSurface != null) { previousSurface.dispose(); previousSurface = null; } if (surfacePool != null) { surfacePool.dispose(); surfacePool = null; } surfacePool = new SurfacePool(bufferSize.getX(), bufferSize.getY()); currentSurface = surfacePool.getSurface(); previousSurface = surfacePool.getSurface(); } } /** * @see net.sf.jame.twister.renderer.TwisterRenderer#render() */ public void render() throws InterruptedException { if (runtime == null) { return; } if (runtime.getFrameElement() != null) { // abortLayers(runtime.getFrameElement()); // joinLayers(runtime.getFrameElement()); startLayers(runtime.getFrameElement()); joinLayers(runtime.getFrameElement()); } } /** * @see net.sf.jame.twister.renderer.TwisterRenderer#prepareImage() */ public void prepareImage(final boolean isDynamicRequired) { if (runtime == null) { return; } if (runtime.getFrameElement() != null) { prepareLayers(runtime.getFrameElement(), isDynamicRequired); } color = new Color(runtime.getBackground().getARGB(), true); } /** * @see net.sf.jame.twister.renderer.TwisterRenderer#dispose() */ public void dispose() { stopRenderer(); if (runtime != null) { runtime.dispose(); runtime = null; } tile = null; if (hints != null) { hints.clear(); hints = null; } bufferSize = null; currentSurface = null; previousSurface = null; if (surfacePool != null) { surfacePool.dispose(); surfacePool = null; } } /** * @see net.sf.jame.twister.renderer.TwisterRenderer#drawSurface(java.awt.Graphics2D) */ public void drawSurface(final Graphics2D g) { drawSurface(g, 0, 0); } /** * @param g * @param x * @param y */ public void drawSurface(final Graphics2D g, final int x, final int y) { if ((runtime == null) || (tile == null)) { return; } if (runtime.getFrameElement() != null) { final Graphics2D g2d = currentSurface.getGraphics2D(); g2d.setComposite(AlphaComposite.SrcOver); g2d.setColor(color); g2d.fillRect(0, 0, currentSurface.getWidth(), currentSurface.getHeight()); currentSurface = drawFrame(runtime.getFrameElement(), currentSurface); g.drawImage(currentSurface.getImage(), x, y, currentSurface.getWidth(), currentSurface.getHeight(), null); final Surface tmpSurface = currentSurface; currentSurface = previousSurface; previousSurface = tmpSurface; } } /** * @see net.sf.jame.twister.renderer.TwisterRenderer#loadSurface(net.sf.jame.core.util.Surface) */ public void loadSurface(final Surface surface) { // final int[] previousData = ((DataBufferInt) previousSurface.getImage().getRaster().getDataBuffer()).getData(); // final int[] data = ((DataBufferInt) surface.getImage().getRaster().getDataBuffer()).getData(); // System.arraycopy(data, 0, previousData, 0, data.length); previousSurface.getGraphics2D().setComposite(AlphaComposite.SrcOver); previousSurface.getGraphics2D().drawImage(surface.getImage(), 0, 0, null); } }