/* 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 static org.jwildfire.base.mathlib.MathLib.sqrt; import java.util.HashMap; import java.util.Map; 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; import org.jwildfire.create.tina.palette.RenderColor; public class PlaneWFFunc 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_DIRECT_COLOR = "direct_color"; private static final String PARAM_COLOR_MODE = "color_mode"; private static final String PARAM_BLEND_COLORMAP = "blend_colormap"; private static final String PARAM_DISPL_AMOUNT = "displ_amount"; private static final String PARAM_BLEND_DISPLMAP = "blend_displ_map"; private static final String PARAM_CALC_COLORIDX = "calc_color_idx"; private static final String PARAM_RECEIVE_ONLY_SHADOWS = "receive_only_shadows"; private static final String RESSOURCE_COLORMAP_FILENAME = "colormap_filename"; private static final String RESSOURCE_DISPL_MAP_FILENAME = "displ_map_filename"; private static final String[] paramNames = { PARAM_POSITION, PARAM_SIZE, PARAM_AXIS, PARAM_DIRECT_COLOR, PARAM_COLOR_MODE, PARAM_BLEND_COLORMAP, PARAM_DISPL_AMOUNT, PARAM_BLEND_DISPLMAP, PARAM_CALC_COLORIDX, PARAM_RECEIVE_ONLY_SHADOWS }; private static final String[] ressourceNames = { RESSOURCE_COLORMAP_FILENAME, RESSOURCE_DISPL_MAP_FILENAME }; private static final int AXIS_XY = 0; private static final int AXIS_YZ = 1; private static final int AXIS_ZX = 2; private static final int CM_COLORMAP = 0; private static final int CM_U = 1; private static final int CM_V = 2; private static final int CM_UV = 3; private double position = 3.0; private double size = 10.0; private int axis = AXIS_ZX; private int direct_color = 1; private int color_mode = CM_UV; private int calc_color_idx = 0; private int receive_only_shadows = 0; private ColorMapHolder colorMapHolder = new ColorMapHolder(); private DisplacementMapHolder displacementMapHolder = new DisplacementMapHolder(); @Override public void transform(FlameTransformationContext pContext, XForm pXForm, XYZPoint pAffineTP, XYZPoint pVarTP, double pAmount) { double x = 0.0, y = 0.0, z = 0.0; switch (axis) { case AXIS_XY: x = 0.5 - pContext.random(); y = 0.5 - pContext.random(); z = position + getDisplacement(x, y); setColor(pVarTP, x, y); x *= size; y *= size; break; case AXIS_YZ: y = 0.5 - pContext.random(); z = 0.5 - pContext.random(); x = position + getDisplacement(y, z); setColor(pVarTP, y, z); y *= size; z *= size; break; case AXIS_ZX: x = 0.5 - pContext.random(); z = 0.5 - pContext.random(); y = position + getDisplacement(z, x); setColor(pVarTP, z, x); x *= size; z *= size; break; default: // nothing to do break; } pVarTP.x += pAmount * x; pVarTP.y += pAmount * y; pVarTP.z += pAmount * z; } private double getDisplacement(double u, double v) { if (displacementMapHolder.isActive()) { double iu = (u + 0.5) * displacementMapHolder.getDisplacementMapWidth(); double iv = (v + 0.5) * displacementMapHolder.getDisplacementMapHeight(); int ix = (int) MathLib.trunc(iu); int iy = (int) MathLib.trunc(iv); return displacementMapHolder.calculateImageDisplacement(ix, iy, iu, iv) / 255.0 * displacementMapHolder.getDispl_amount(); } return 0.0; } private void setColor(XYZPoint pVarTP, double u, double v) { if (direct_color > 0) { switch (color_mode) { case CM_V: pVarTP.color = v + 0.5; break; case CM_UV: pVarTP.color = (v + 0.5) * (u + 0.5); break; case CM_COLORMAP: { double iu = (u + 0.5) * colorMapHolder.getColorMapWidth(); double iv = (v + 0.5) * colorMapHolder.getColorMapHeight(); int ix = (int) MathLib.trunc(iu); int iy = (int) MathLib.trunc(iv); colorMapHolder.applyImageColor(pVarTP, ix, iy, iu, iv); if (calc_color_idx == 1) { pVarTP.color = getUVColorIdx(Tools.FTOI(pVarTP.redColor), Tools.FTOI(pVarTP.greenColor), Tools.FTOI(pVarTP.blueColor)); } } break; case CM_U: default: pVarTP.color = u + 0.5; break; } if (pVarTP.color < 0.0) pVarTP.color = 0.0; else if (pVarTP.color > 1.0) pVarTP.color = 1.0; } if (receive_only_shadows == 1) { pVarTP.receiveOnlyShadows = true; } } @Override public String[] getParameterNames() { return paramNames; } @Override public Object[] getParameterValues() { return new Object[] { position, size, axis, direct_color, color_mode, colorMapHolder.getBlend_colormap(), displacementMapHolder.getDispl_amount(), displacementMapHolder.getBlend_displ_map(), calc_color_idx, receive_only_shadows }; } @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_DIRECT_COLOR.equalsIgnoreCase(pName)) { direct_color = limitIntVal(Tools.FTOI(pValue), 0, 1); } else if (PARAM_COLOR_MODE.equalsIgnoreCase(pName)) { color_mode = limitIntVal(Tools.FTOI(pValue), CM_COLORMAP, CM_UV); } else if (PARAM_BLEND_COLORMAP.equalsIgnoreCase(pName)) { colorMapHolder.setBlend_colormap(limitIntVal(Tools.FTOI(pValue), 0, 1)); } else if (PARAM_BLEND_DISPLMAP.equalsIgnoreCase(pName)) { displacementMapHolder.setBlend_displ_map(limitIntVal(Tools.FTOI(pValue), 0, 1)); } else if (PARAM_DISPL_AMOUNT.equalsIgnoreCase(pName)) { displacementMapHolder.setDispl_amount(pValue); } else if (PARAM_CALC_COLORIDX.equalsIgnoreCase(pName)) { calc_color_idx = limitIntVal(Tools.FTOI(pValue), 0, 1); } else if (PARAM_RECEIVE_ONLY_SHADOWS.equalsIgnoreCase(pName)) { receive_only_shadows = limitIntVal(Tools.FTOI(pValue), 0, 1); } else throw new IllegalArgumentException(pName); } @Override public String getName() { return "plane_wf"; } @Override public String[] getRessourceNames() { return ressourceNames; } @Override public byte[][] getRessourceValues() { return new byte[][] { (colorMapHolder.getColormap_filename() != null ? colorMapHolder.getColormap_filename().getBytes() : null), (displacementMapHolder.getDispl_map_filename() != null ? displacementMapHolder.getDispl_map_filename().getBytes() : null) }; } @Override public void setRessource(String pName, byte[] pValue) { if (RESSOURCE_COLORMAP_FILENAME.equalsIgnoreCase(pName)) { colorMapHolder.setColormap_filename(pValue != null ? new String(pValue) : ""); } else if (RESSOURCE_DISPL_MAP_FILENAME.equalsIgnoreCase(pName)) { displacementMapHolder.setDispl_map_filename(pValue != null ? new String(pValue) : ""); } else throw new IllegalArgumentException(pName); } @Override public RessourceType getRessourceType(String pName) { if (RESSOURCE_COLORMAP_FILENAME.equalsIgnoreCase(pName)) { return RessourceType.IMAGE_FILENAME; } else if (RESSOURCE_DISPL_MAP_FILENAME.equalsIgnoreCase(pName)) { return RessourceType.IMAGE_FILENAME; } else throw new IllegalArgumentException(pName); } @Override public void init(FlameTransformationContext pContext, Layer pLayer, XForm pXForm, double pAmount) { colorMapHolder.init(); uvColors = pLayer.getPalette().createRenderPalette(pContext.getFlameRenderer().getFlame().getWhiteLevel()); displacementMapHolder.init(); } private RenderColor[] uvColors; protected Map<RenderColor, Double> uvIdxMap = new HashMap<RenderColor, Double>(); private double getUVColorIdx(int pR, int pG, int pB) { RenderColor pColor = new RenderColor(pR, pG, pB); Double res = uvIdxMap.get(pColor); if (res == null) { int nearestIdx = 0; RenderColor color = uvColors[0]; double dr, dg, db; dr = (color.red - pR); dg = (color.green - pG); db = (color.blue - pB); double nearestDist = sqrt(dr * dr + dg * dg + db * db); for (int i = 1; i < uvColors.length; i++) { color = uvColors[i]; dr = (color.red - pR); dg = (color.green - pG); db = (color.blue - pB); double dist = sqrt(dr * dr + dg * dg + db * db); if (dist < nearestDist) { nearestDist = dist; nearestIdx = i; } } res = (double) nearestIdx / (double) (uvColors.length - 1); uvIdxMap.put(pColor, res); } return res; } }