/* JWildfire - an image and animation processor written in Java Copyright (C) 1995-2015 Andreas Maschke This is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This software 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this software; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jwildfire.create.tina.variation.iflames; import java.util.List; import java.util.Map; import org.jwildfire.base.Tools; import org.jwildfire.base.mathlib.GfxMathLib; import org.jwildfire.base.mathlib.MathLib; import org.jwildfire.create.tina.base.Layer; import org.jwildfire.create.tina.base.XForm; import org.jwildfire.create.tina.base.XYZPoint; import org.jwildfire.create.tina.base.motion.MotionCurve; import org.jwildfire.create.tina.random.AbstractRandomGenerator; import org.jwildfire.create.tina.random.MarsagliaRandomGenerator; import org.jwildfire.create.tina.variation.FlameTransformationContext; import org.jwildfire.create.tina.variation.RessourceManager; import org.jwildfire.create.tina.variation.RessourceType; import org.jwildfire.create.tina.variation.VariationFunc; import org.jwildfire.image.Pixel; import org.jwildfire.image.SimpleImage; public class IFlamesFunc extends VariationFunc { private static final long serialVersionUID = 1L; public static final int MAX_FLAME_COUNT = 6; private ImageParams imageParams = new ImageParams(); private MotionParams motionParams = new MotionParams(); private FlameParamsList flameParams = FlameParamsList.createFlameParams(MAX_FLAME_COUNT); private final String[] paramNames = flameParams.appendParamNames(motionParams.appendParamNames(imageParams.appendParamNames(new String[0]))); private final String[] ressourceNames = flameParams.appendRessourceNames(motionParams.appendRessourceNames(imageParams.appendRessourceNames(new String[0]))); // derived params private final Pixel toolPixel = new Pixel(); private int flameIdx; private AbstractRandomGenerator randGen; @Override public String[] getParameterNames() { return paramNames; } @Override public Object[] getParameterValues() { return flameParams.appendParamValues(motionParams.appendParamValues(imageParams.appendParamValues(new Object[0]))); } @Override public void setParameter(String pName, double pValue) { if (!imageParams.setParameter(pName, pValue) && !motionParams.setParameter(pName, pValue) && !flameParams.setParameter(pName, pValue)) throw new IllegalArgumentException(pName); } @SuppressWarnings("unchecked") @Override public synchronized void init(FlameTransformationContext pContext, Layer pLayer, XForm pXForm, double pAmount) { imageParams.init(pContext); String key = genImageKey(); flameList = (List<BaseFlame>) RessourceManager.getRessource(key); if (flameList == null) { System.out.println("FGET " + key); long t0 = System.currentTimeMillis(); RessourceManager.clearRessources(KEY_PREFIX + "#" + imageParams.getId()); flameList = new BaseFlameListCreator(flameParams, motionParams, imageParams).calcBaseFlameList(pContext, imageParams.getColorMap()); RessourceManager.putRessource(key, flameList); System.out.println("NPUT " + key); long t1 = System.currentTimeMillis(); if ((t1 - t0) > 500) { System.out.println("IFLAMES: " + flameList.size() + " flames created in " + (t1 - t0) / 1000.0 + "s"); } } String particleKey = genParticleKey(); String particleListKey = particleKey + "#" + Tools.doubleToString(motionParams.getTime()); particleLst = (List<Particle>) RessourceManager.getRessource(particleListKey); if (particleLst == null) { long t0 = System.currentTimeMillis(); IFlamesAnimatorMotionStore motionStore = getMotionStore(particleKey); particleLst = new ParticleListCreator(flameList, motionParams, collectMotionCurves(pXForm), motionStore).createParticleList((float) motionParams.getTime()); RessourceManager.putRessource(particleListKey, particleLst); long t1 = System.currentTimeMillis(); // if ((t1 - t0) > 500) { System.out.println("IFLAMES: " + flameList.size() + " flames animated in " + (t1 - t0) / 1000.0 + "s (t=" + motionParams.getTime() + ")"); // } } randGen = new MarsagliaRandomGenerator(); randGen.randomize(System.currentTimeMillis()); flameIdx = flameList != null && flameList.size() > 0 ? randGen.random(flameList.size()) : 0; } private IFlamesAnimatorMotionStore getMotionStore(String particleKey) { IFlamesAnimatorMotionStore motionStore; { String storeKey = particleKey + "#motionStore"; motionStore = (IFlamesAnimatorMotionStore) RessourceManager.getRessource(storeKey); if (motionStore == null) { motionStore = new IFlamesAnimatorMotionStore(); RessourceManager.putRessource(storeKey, motionStore); } } return motionStore; } private Map<String, MotionCurve> collectMotionCurves(XForm pXForm) { for (int i = 0; i < pXForm.getVariationCount(); i++) { if (pXForm.getVariation(i).getFunc() == this) { return pXForm.getVariation(i).getClonedMotionCurves(); } } throw new IllegalStateException("IFlames variation not found!"); } public final static String KEY_PREFIX = "IFLAME_BASE_FLAMES#"; private String genImageKey() { return flameParams.completeImageKey(motionParams.completeImageKey(imageParams.completeImageKey(KEY_PREFIX))); } private String genParticleKey() { return flameParams.completeParticleKey(motionParams.completeParticleKey(imageParams.completeParticleKey(KEY_PREFIX))); } private List<BaseFlame> flameList; private List<Particle> particleLst; @Override public String[] getRessourceNames() { return ressourceNames; } @Override public byte[][] getRessourceValues() { return flameParams.appendRessourceValues(motionParams.appendRessourceValues(imageParams.appendRessourceValues(new byte[0][]))); } @Override public void setRessource(String pName, byte[] pValue) { if (!imageParams.setRessource(pName, pValue) && !motionParams.setRessource(pName, pValue) && !flameParams.setRessource(pName, pValue)) throw new IllegalArgumentException(pName); } @Override public RessourceType getRessourceType(String pName) { RessourceType res; res = imageParams.getRessourceType(pName); if (res != null) { return res; } res = motionParams.getRessourceType(pName); if (res != null) { return res; } res = flameParams.getRessourceType(pName); if (res != null) { return res; } throw new IllegalArgumentException(pName); } @Override public String getName() { return "iflames_wf"; } @Override public void transform(FlameTransformationContext pContext, XForm pXForm, XYZPoint pAffineTP, XYZPoint pVarTP, double pAmount) { if (imageParams.getImage_brightness() < MathLib.EPSILON || randGen.random() < imageParams.getIFlame_density()) { if (flameList.size() == 0) { return; } // int idx = randGen.random(flameList.size()); int idx; if (randGen.random() < 0.5) { idx = randGen.random(flameList.size()); } else { idx = flameIdx++; if (flameIdx >= flameList.size()) { flameIdx = 0; } } BaseFlame baseFlame = flameList.get(idx); Particle particle = particleLst.get(idx); if (baseFlame.getIterator() != null) { if (motionParams.getPreview() == 1) { XYZPoint dst = new XYZPoint(); pVarTP.x += dst.x + particle.getPosition().getX(); pVarTP.y += dst.y + particle.getPosition().getY(); pVarTP.z += dst.z + particle.getPosition().getZ(); pVarTP.rgbColor = true; pVarTP.redColor = baseFlame.getPreviewColorR() * imageParams.getIFlame_brightness() * baseFlame.getBrightness(); pVarTP.greenColor = baseFlame.getPreviewColorG() * imageParams.getIFlame_brightness() * baseFlame.getBrightness(); pVarTP.blueColor = baseFlame.getPreviewColorB() * imageParams.getIFlame_brightness() * baseFlame.getBrightness(); } else { XYZPoint src = new XYZPoint(); XYZPoint dst = new XYZPoint(); baseFlame.getIterator().iterate(src, dst, baseFlame.getSize(), particle.getRotation().getX(), particle.getRotation().getY(), particle.getRotation().getZ()); pVarTP.x += dst.x + particle.getPosition().getX(); pVarTP.y += dst.y + particle.getPosition().getY(); pVarTP.z += dst.z + particle.getPosition().getZ(); pVarTP.color = dst.color; pVarTP.rgbColor = true; pVarTP.redColor = baseFlame.getR() * imageParams.getIFlame_brightness() * baseFlame.getBrightness(); pVarTP.greenColor = baseFlame.getG() * imageParams.getIFlame_brightness() * baseFlame.getBrightness(); pVarTP.blueColor = baseFlame.getB() * imageParams.getIFlame_brightness() * baseFlame.getBrightness(); } } else { addImage(pVarTP, randGen); } } else { addImage(pVarTP, randGen); } } private void addImage(XYZPoint pVarTP, AbstractRandomGenerator randGen) { double xCoord = randGen.random(imageParams.getImgWidth()) + (0.5 - randGen.random()); double yCoord = randGen.random(imageParams.getImgHeight()) + (0.5 - randGen.random()); double dx = xCoord * imageParams.getScaleX() / (double) (imageParams.getImgWidth() - 1) + imageParams.getOffsetX(); double dy = yCoord * imageParams.getScaleY() / (double) (imageParams.getImgHeight() - 1) + imageParams.getOffsetY(); double dz = imageParams.getOffsetZ(); pVarTP.x += dx; pVarTP.y += dy; pVarTP.z += dz; toolPixel.setARGBValue(((SimpleImage) imageParams.getColorMap()).getARGBValueIgnoreBounds((int) xCoord, (int) yCoord)); int luR = toolPixel.r; int luG = toolPixel.g; int luB = toolPixel.b; pVarTP.doHide = false; if (luR == 0 && luG == 0 && luB == 0) { pVarTP.doHide = true; return; } toolPixel.setARGBValue(((SimpleImage) imageParams.getColorMap()).getARGBValueIgnoreBounds(((int) xCoord) + 1, (int) yCoord)); int ruR = toolPixel.r; int ruG = toolPixel.g; int ruB = toolPixel.b; toolPixel.setARGBValue(((SimpleImage) imageParams.getColorMap()).getARGBValueIgnoreBounds((int) xCoord, ((int) yCoord) + 1)); int lbR = toolPixel.r; int lbG = toolPixel.g; int lbB = toolPixel.b; toolPixel.setARGBValue(((SimpleImage) imageParams.getColorMap()).getARGBValueIgnoreBounds(((int) xCoord) + 1, ((int) yCoord) + 1)); int rbR = toolPixel.r; int rbG = toolPixel.g; int rbB = toolPixel.b; double r = GfxMathLib.blerp(luR, ruR, lbR, rbR, MathLib.frac(xCoord), MathLib.frac(yCoord)); double g = GfxMathLib.blerp(luG, ruG, lbG, rbG, MathLib.frac(xCoord), MathLib.frac(yCoord)); double b = GfxMathLib.blerp(luB, ruB, lbB, rbB, MathLib.frac(xCoord), MathLib.frac(yCoord)); pVarTP.rgbColor = true; pVarTP.redColor = r * imageParams.getImage_brightness(); pVarTP.greenColor = g * imageParams.getImage_brightness(); pVarTP.blueColor = b * imageParams.getImage_brightness(); } public ImageParams getImageParams() { return imageParams; } public MotionParams getMotionParams() { return motionParams; } public FlameParams getFlameParams(int pIndex) { return flameParams.get(pIndex); } }