/* JWildfire - an image and animation processor written in Java Copyright (C) 1995-2021 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.create.tina.base.Layer; import org.jwildfire.create.tina.base.XForm; import org.jwildfire.create.tina.base.XYZPoint; import static org.jwildfire.base.mathlib.MathLib.*; public class PostPointSymmetryWFFunc extends VariationFunc implements SupportsGPU { private static final long serialVersionUID = 1L; public static final String PARAM_CENTRE_X = "centre_x"; public static final String PARAM_CENTRE_Y = "centre_y"; public static final String PARAM_CENTRE_Z = "centre_z"; public static final String PARAM_PLANE = "plane"; public static final String PARAM_ORDER = "order"; private static final String PARAM_COLORSHIFT = "colorshift"; private static final String[] paramNames = {PARAM_CENTRE_X, PARAM_CENTRE_Y, PARAM_CENTRE_Z, PARAM_PLANE, PARAM_ORDER, PARAM_COLORSHIFT}; private double centre_x = 0.25; private double centre_y = 0.5; private double centre_z = 0.0; private int plane = 0; private int order = 3; private double colorshift = 0; @Override public void transform(FlameTransformationContext pContext, XForm pXForm, XYZPoint pAffineTP, XYZPoint pVarTP, double pAmount) { double dx = (pVarTP.x - centre_x) * pAmount; double dy = (pVarTP.y - centre_y) * pAmount; double dz = (pVarTP.z - centre_z) * pAmount; int idx = pContext.random(order); if (plane == 0) { pVarTP.x = centre_x + dx * _cosa[idx] + dy * _sina[idx]; pVarTP.y = centre_y + dy * _cosa[idx] - dx * _sina[idx]; } else if (plane == 1) { pVarTP.y = centre_y + dy * _cosa[idx] + dz * _sina[idx]; pVarTP.z = centre_z + dz * _cosa[idx] - dy * _sina[idx]; } else if (plane == 2) { pVarTP.z = centre_z + dz * _cosa[idx] + dx * _sina[idx]; pVarTP.x = centre_x + dx * _cosa[idx] - dz * _sina[idx]; } pVarTP.color = fmod(pVarTP.color + idx * colorshift, 1.0); } @Override public String[] getParameterNames() { return paramNames; } @Override public Object[] getParameterValues() { return new Object[]{centre_x, centre_y, centre_z, plane, order, colorshift}; } @Override public void setParameter(String pName, double pValue) { if (PARAM_CENTRE_X.equalsIgnoreCase(pName)) centre_x = pValue; else if (PARAM_CENTRE_Y.equalsIgnoreCase(pName)) centre_y = pValue; else if (PARAM_CENTRE_Z.equalsIgnoreCase(pName)) centre_z = pValue; else if (PARAM_PLANE.equalsIgnoreCase(pName)) plane = limitIntVal(Tools.FTOI(pValue), 0, 2); else if (PARAM_ORDER.equalsIgnoreCase(pName)) order = limitIntVal(Tools.FTOI(pValue), 1, Integer.MAX_VALUE); else if (PARAM_COLORSHIFT.equalsIgnoreCase(pName)) colorshift = pValue; else throw new IllegalArgumentException(pName); } @Override public String getName() { return "post_point_symmetry_wf"; } @Override public int getPriority() { return 1; } private double _sina[], _cosa[]; @Override public void init(FlameTransformationContext pContext, Layer pLayer, XForm pXForm, double pAmount) { _sina = new double[order]; _cosa = new double[order]; double da = M_2PI / (double) order; double angle = 0.0; for (int i = 0; i < order; i++) { _sina[i] = sin(angle); _cosa[i] = cos(angle); angle += da; } } @Override public VariationFuncType[] getVariationTypes() { return new VariationFuncType[]{VariationFuncType.VARTYPE_2D, VariationFuncType.VARTYPE_DC, VariationFuncType.VARTYPE_POST, VariationFuncType.VARTYPE_SUPPORTS_GPU}; } @Override public String getGPUCode(FlameTransformationContext context) { return "int order = lroundf(__post_point_symmetry_wf_order);\n" + "if(order>36) order=36;\n" +"float _sina[36];\n" + "float _cosa[36];\n" + " float da = (2.0f*PI) / (float) order;\n" + " float angle = 0.0;\n" + " for (int i = 0; i < order; i++) {\n" + " _sina[i] = sinf(angle);\n" + " _cosa[i] = cosf(angle);\n" + " angle += da;\n" + " }\n" + " float dx = (__px - __post_point_symmetry_wf_centre_x) * __post_point_symmetry_wf;\n" + " float dy = (__py - __post_point_symmetry_wf_centre_y) * __post_point_symmetry_wf;\n" + " float dz = (__pz - __post_point_symmetry_wf_centre_z) * __post_point_symmetry_wf;\n" + " int idx = lroundf(RANDFLOAT() * (order-1));\n" + " if (__post_point_symmetry_wf_plane == 0) {\n" + " __px = __post_point_symmetry_wf_centre_x + dx * _cosa[idx] + dy * _sina[idx];\n" + " __py = __post_point_symmetry_wf_centre_y + dy * _cosa[idx] - dx * _sina[idx];\n" + " } else if (__post_point_symmetry_wf_plane == 0) {\n" + " __py = __post_point_symmetry_wf_centre_y + dy * _cosa[idx] + dz * _sina[idx];\n" + " __pz = __post_point_symmetry_wf_centre_z + dz * _cosa[idx] - dy * _sina[idx];\n" + " } else if (__post_point_symmetry_wf_plane == 0) {\n" + " __pz = __post_point_symmetry_wf_centre_z + dz * _cosa[idx] + dx * _sina[idx];\n" + " __px = __post_point_symmetry_wf_centre_x + dx * _cosa[idx] - dz * _sina[idx];\n" + " }\n" + " __pal = fmodf(__pal + idx * __post_point_symmetry_wf_colorshift, 1.0);\n"; } }