/* JWildfire - an image and animation processor written in Java Copyright (C) 1995-2014 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.base; import static org.jwildfire.base.mathlib.MathLib.EPSILON; import static org.jwildfire.base.mathlib.MathLib.fabs; import java.io.Serializable; import java.util.List; import org.jwildfire.create.tina.animate.AnimAware; import org.jwildfire.create.tina.edit.Assignable; import org.jwildfire.create.tina.palette.RGBPalette; import org.jwildfire.create.tina.variation.FlameTransformationContext; import org.jwildfire.create.tina.variation.Variation; public class Layer implements Assignable<Layer>, Serializable { private Flame owner; private static final long serialVersionUID = 1L; private boolean visible = true; @AnimAware private double weight = 1.0; @AnimAware private RGBPalette palette = new RGBPalette(); @AnimAware private final List<XForm> xForms = new XFormList(this); @AnimAware private final List<XForm> finalXForms = new XFormList(this); private String name = ""; private String gradientMapFilename = ""; private double gradientMapHorizOffset = 0.0; private double gradientMapHorizScale = 1.0; private double gradientMapVertOffset = 0.0; private double gradientMapVertScale = 1.0; private double gradientMapLocalColorAdd = 0.8; private double gradientMapLocalColorScale = 0.2; private boolean smoothGradient = false; public List<XForm> getXForms() { return xForms; } public List<XForm> getFinalXForms() { return finalXForms; } public RGBPalette getPalette() { return palette; } public void setPalette(RGBPalette pPalette) { if (pPalette == null || pPalette.getSize() != RGBPalette.PALETTE_SIZE) throw new IllegalArgumentException(pPalette != null ? pPalette.toString() + " " + pPalette.getSize() : "NULL"); palette = pPalette; } public void distributeColors() { int cnt = getXForms().size(); if (cnt > 1) { for (int i = 0; i < getXForms().size(); i++) { XForm xForm = getXForms().get(i); xForm.setColor((double) i / (double) (cnt - 1)); } } } public void randomizeColors() { for (int i = 0; i < getXForms().size(); i++) { XForm xForm = getXForms().get(i); xForm.setColor(Math.random()); } } public void randomizeColorSpeed() { for (int i = 0; i < getXForms().size(); i++) { XForm xForm = getXForms().get(i); xForm.setColorSymmetry(Math.random()); } } public void refreshModWeightTables(FlameTransformationContext pFlameTransformationContext) { double tp[] = new double[Constants.MAX_MOD_WEIGHT_COUNT]; int n = getXForms().size(); { for (XForm xForm : this.getXForms()) { xForm.initTransform(); for (Variation var : xForm.getVariations()) { var.getFunc().init(pFlameTransformationContext, this, xForm, var.getAmount()); } } } { for (XForm xForm : this.getFinalXForms()) { xForm.initTransform(); for (Variation var : xForm.getVariations()) { var.getFunc().init(pFlameTransformationContext, this, xForm, var.getAmount()); } } } for (int k = 0; k < n; k++) { XForm xform = getXForms().get(k); double totValue = 0; for (int i = 0; i < n; i++) { tp[i] = getXForms().get(i).getWeight() * getXForms().get(k).getModifiedWeights()[i]; totValue = totValue + tp[i]; } if (totValue > 0) { double loopValue = 0; for (int i = 0; i < xform.getNextAppliedXFormTable().length; i++) { double totalProb = 0; int j = -1; do { j++; totalProb = totalProb + tp[j]; } while (!((totalProb > loopValue) || (j == n - 1))); xform.getNextAppliedXFormTable()[i] = getXForms().get(j); loopValue = loopValue + totValue / (double) xform.getNextAppliedXFormTable().length; } } else { for (int i = 0; i < xform.getNextAppliedXFormTable().length; i++) { xform.getNextAppliedXFormTable()[i] = null; } } } } @Override public void assign(Layer pSrc) { weight = pSrc.weight; visible = pSrc.visible; name = pSrc.name; gradientMapFilename = pSrc.gradientMapFilename; gradientMapHorizOffset = pSrc.gradientMapHorizOffset; gradientMapHorizScale = pSrc.gradientMapHorizScale; gradientMapVertOffset = pSrc.gradientMapVertOffset; gradientMapVertScale = pSrc.gradientMapVertScale; gradientMapLocalColorAdd = pSrc.gradientMapLocalColorAdd; gradientMapLocalColorScale = pSrc.gradientMapLocalColorScale; smoothGradient = pSrc.smoothGradient; palette = pSrc.palette.makeCopy(); xForms.clear(); for (XForm xForm : pSrc.getXForms()) { xForms.add(xForm.makeCopy()); } finalXForms.clear(); for (XForm xForm : pSrc.getFinalXForms()) { finalXForms.add(xForm.makeCopy()); } } @Override public Layer makeCopy() { Layer res = new Layer(); res.assign(this); return res; } @Override public boolean isEqual(Layer pSrc) { if ((fabs(weight - pSrc.weight) > EPSILON) || (fabs(gradientMapHorizOffset - pSrc.gradientMapHorizOffset) > EPSILON) || (fabs(gradientMapHorizScale - pSrc.gradientMapHorizScale) > EPSILON) || (fabs(gradientMapVertOffset - pSrc.gradientMapVertOffset) > EPSILON) || (fabs(gradientMapVertScale - pSrc.gradientMapVertScale) > EPSILON) || (fabs(gradientMapLocalColorAdd - pSrc.gradientMapLocalColorAdd) > EPSILON) || (fabs(gradientMapLocalColorScale - pSrc.gradientMapLocalColorScale) > EPSILON) || !name.equals(pSrc.name) || !gradientMapFilename.equals(pSrc.gradientMapFilename) || smoothGradient != pSrc.smoothGradient || !palette.isEqual(pSrc.palette) || (visible != pSrc.visible) || (xForms.size() != pSrc.xForms.size()) || (finalXForms.size() != pSrc.finalXForms.size())) { return false; } for (int i = 0; i < xForms.size(); i++) { if (!xForms.get(i).isEqual(pSrc.xForms.get(i))) { return false; } } for (int i = 0; i < finalXForms.size(); i++) { if (!finalXForms.get(i).isEqual(pSrc.finalXForms.get(i))) { return false; } } return true; } public double getWeight() { return weight; } public void setWeight(double pWeight) { weight = pWeight; } public boolean isVisible() { return visible; } public void setVisible(boolean pVisible) { visible = pVisible; } public boolean isRenderable() { return isVisible() && getWeight() > -EPSILON && getXForms().size() > 0; } public String getName() { return name; } public void setName(String name) { this.name = name != null ? name : ""; } public String getGradientMapFilename() { return gradientMapFilename; } public void setGradientMapFilename(String gradientMapFilename) { this.gradientMapFilename = gradientMapFilename != null ? gradientMapFilename : ""; } public void setOwner(Flame pOwner) { owner = pOwner; } public Flame getOwner() { return owner; } public boolean isSmoothGradient() { return smoothGradient; } public void setSmoothGradient(boolean pSmoothGradient) { smoothGradient = pSmoothGradient; } public double getGradientMapHorizOffset() { return gradientMapHorizOffset; } public void setGradientMapHorizOffset(double pGradientMapHorizOffset) { gradientMapHorizOffset = pGradientMapHorizOffset; } public double getGradientMapHorizScale() { return gradientMapHorizScale; } public void setGradientMapHorizScale(double pGradientMapHorizScale) { gradientMapHorizScale = pGradientMapHorizScale; } public double getGradientMapVertOffset() { return gradientMapVertOffset; } public void setGradientMapVertOffset(double pGradientMapVertOffset) { gradientMapVertOffset = pGradientMapVertOffset; } public double getGradientMapVertScale() { return gradientMapVertScale; } public void setGradientMapVertScale(double pGradientMapVertScale) { gradientMapVertScale = pGradientMapVertScale; } public double getGradientMapLocalColorAdd() { return gradientMapLocalColorAdd; } public void setGradientMapLocalColorAdd(double pGradientMapLocalColorAdd) { gradientMapLocalColorAdd = pGradientMapLocalColorAdd; } public double getGradientMapLocalColorScale() { return gradientMapLocalColorScale; } public void setGradientMapLocalColorScale(double pGradientMapLocalColorScale) { gradientMapLocalColorScale = pGradientMapLocalColorScale; } }