/* JWildfire - an image and animation processor written in Java Copyright (C) 1995-2016 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; import org.jwildfire.base.Tools; 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; public class CheckerboardWFFunc extends VariationFunc { private static final long serialVersionUID = 1L; private static final String PARAM_POSITION = "position"; private static final String PARAM_SIZE = "size"; private static final String PARAM_AXIS = "axis"; private static final String PARAM_DISPL_AMOUNT = "displ_amount"; private static final String PARAM_CHECKER_COLOR1 = "checker_color1"; private static final String PARAM_CHECKER_COLOR2 = "checker_color2"; private static final String PARAM_SIDE_COLOR = "side_color"; private static final String PARAM_CHECKER_SIZE = "checker_size"; private static final String PARAM_WITH_SIDES = "with_sides"; private static final String[] paramNames = { PARAM_POSITION, PARAM_SIZE, PARAM_AXIS, PARAM_CHECKER_SIZE, PARAM_DISPL_AMOUNT, PARAM_CHECKER_COLOR1, PARAM_CHECKER_COLOR2, PARAM_SIDE_COLOR, PARAM_WITH_SIDES }; private static final int AXIS_XY = 0; private static final int AXIS_YZ = 1; private static final int AXIS_ZX = 2; private double position = 3.0; private double size = 10.0; private int axis = AXIS_ZX; private double displ_amount = 0.05; private double checker_color1 = Math.random() * 0.5; private double checker_color2 = Math.random() * 0.5 + 0.5; private double side_color = Math.random() * 0.75; private double checker_size = 0.1 + Math.random() * 0.2; private int with_sides = 1; @Override public void transform(FlameTransformationContext pContext, XForm pXForm, XYZPoint pAffineTP, XYZPoint pVarTP, double pAmount) { double x, y, z; if (with_sides == 0 || MathLib.fabs(displ_amount) < MathLib.EPSILON) { x = pContext.random(); y = pContext.random(); z = getDisplacement(x, y); pVarTP.color = getColor(x, y); } else { if (_max_checks > 0 && pContext.random() < _side_prob) { pVarTP.color = side_color; if (pContext.random() < 0.5) { x = pContext.random(_max_checks + 1) * checker_size; y = pContext.random(); } else { x = pContext.random(); y = pContext.random(_max_checks + 1) * checker_size; } z = displ_amount * pContext.random(); } else { x = pContext.random(); y = pContext.random(); z = getDisplacement(x, y); pVarTP.color = getColor(x, y); } } x = (x - 0.5) * size; y = (y - 0.5) * size; z = z * size + position; switch (axis) { case AXIS_XY: pVarTP.x += pAmount * x; pVarTP.y += pAmount * y; pVarTP.z += pAmount * z; break; case AXIS_YZ: pVarTP.y += pAmount * x; pVarTP.z += pAmount * y; pVarTP.x += pAmount * z; break; default: case AXIS_ZX: pVarTP.z += pAmount * x; pVarTP.x += pAmount * y; pVarTP.y += pAmount * z; break; } } private double getColor(double u, double v) { double color = MathLib.fmod(MathLib.floor(u / checker_size) + MathLib.floor(v / checker_size), 2) < 1 ? checker_color1 : checker_color2; if (color < 0.0) color = 0.0; else if (color > 1.0) color = 1.0; return color; } private double getDisplacement(double u, double v) { return MathLib.fmod(MathLib.floor(u / checker_size) + MathLib.floor(v / checker_size), 2) < 1 ? displ_amount : 0.0; } @Override public String[] getParameterNames() { return paramNames; } @Override public Object[] getParameterValues() { return new Object[] { position, size, axis, checker_size, displ_amount, checker_color1, checker_color2, side_color, with_sides }; } @Override public void setParameter(String pName, double pValue) { if (PARAM_POSITION.equalsIgnoreCase(pName)) { position = pValue; } else if (PARAM_SIZE.equalsIgnoreCase(pName)) { size = pValue; } else if (PARAM_AXIS.equalsIgnoreCase(pName)) { axis = limitIntVal(Tools.FTOI(pValue), AXIS_XY, AXIS_ZX); } else if (PARAM_DISPL_AMOUNT.equalsIgnoreCase(pName)) { displ_amount = pValue; } else if (PARAM_CHECKER_COLOR1.equalsIgnoreCase(pName)) { checker_color1 = limitVal(pValue, 0.0, 1.0); } else if (PARAM_CHECKER_COLOR2.equalsIgnoreCase(pName)) { checker_color2 = limitVal(pValue, 0.0, 1.0); } else if (PARAM_SIDE_COLOR.equalsIgnoreCase(pName)) { side_color = limitVal(pValue, 0.0, 1.0); } else if (PARAM_CHECKER_SIZE.equalsIgnoreCase(pName)) { checker_size = pValue; } else if (PARAM_WITH_SIDES.equalsIgnoreCase(pName)) { with_sides = limitIntVal(Tools.FTOI(pValue), 0, 1); } else throw new IllegalArgumentException(pName); } @Override public String getName() { return "checkerboard_wf"; } private double _side_prob; private int _max_checks; @Override public void init(FlameTransformationContext pContext, Layer pLayer, XForm pXForm, double pAmount) { double side_area = 4.0 * displ_amount; _side_prob = side_area / (1.0 + side_area); _max_checks = Tools.FTOI(1.0 / checker_size); if ((_max_checks) * checker_size >= 1.0) { _max_checks--; } } }