/*
JWildfire - an image and animation processor written in Java
Copyright (C) 1995-2011 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.
*/
/*
* Truchet Plugin by TyrantWave, see http://tyrantwave.deviantart.com/art/Truchet-Plugin-107982844
*/
package org.jwildfire.create.tina.variation;
import static org.jwildfire.base.mathlib.MathLib.SMALL_EPSILON;
import static org.jwildfire.base.mathlib.MathLib.cos;
import static org.jwildfire.base.mathlib.MathLib.fabs;
import static org.jwildfire.base.mathlib.MathLib.floor;
import static org.jwildfire.base.mathlib.MathLib.fmod;
import static org.jwildfire.base.mathlib.MathLib.pow;
import static org.jwildfire.base.mathlib.MathLib.round;
import static org.jwildfire.base.mathlib.MathLib.sin;
import static org.jwildfire.base.mathlib.MathLib.sqrt;
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;
public class TruchetFunc extends VariationFunc {
private static final long serialVersionUID = 1L;
private static final String PARAM_EXTENDED = "extended";
private static final String PARAM_EXPONENT = "exponent";
private static final String PARAM_ARC_WIDTH = "arc_width";
private static final String PARAM_ROTATION = "rotation";
private static final String PARAM_SIZE = "size";
private static final String PARAM_SEED = "seed";
private static final String PARAM_DIRECT_COLOR = "direct_color";
private static final String[] paramNames = { PARAM_EXTENDED, PARAM_EXPONENT, PARAM_ARC_WIDTH, PARAM_ROTATION, PARAM_SIZE, PARAM_SEED, PARAM_DIRECT_COLOR };
private int extended = 0;
private double exponent = 2.0;
private double arc_width = 0.5;
private double rotation = 0.0;
private double size = 1.0;
private double seed = 50.0;
private int direct_color = 0;
@Override
public void transform(FlameTransformationContext pContext, XForm pXForm, XYZPoint pAffineTP, XYZPoint pVarTP, double pAmount) {
//APO VARIABLES
double n = exponent;
double onen = 1.0 / exponent;
double tdeg = rotation;
double width = arc_width;
double seed = fabs(this.seed);
double seed2 = sqrt(seed + (seed / 2) + SMALL_EPSILON) / ((seed * 0.5) + SMALL_EPSILON) * 0.25;
//VARIABLES
double x, y;
int intx = 0;
int inty = 0;
double r = -tdeg;
double r0 = 0.0;
double r1 = 0.0;
double rmax = 0.5 * (pow(2.0, 1.0 / n) - 1.0) * width;
double scale = (cos(r) - sin(r)) / pAmount;
double tiletype = 0.0;
double randint = 0.0;
double modbase = 65535.0;
double multiplier = 32747.0;//1103515245;
double offset = 12345.0;
double niter = 0.0;
int randiter = 0;
//INITIALISATION
x = pAffineTP.x * scale;
y = pAffineTP.y * scale;
intx = (int) round(x);
inty = (int) round(y);
r = x - intx;
if (r < 0.0) {
x = 1.0 + r;
}
else {
x = r;
}
r = y - inty;
if (r < 0.0) {
y = 1.0 + r;
}
else {
y = r;
}
//CALCULATE THE TILE TYPE
if (seed == 0.0) {
tiletype = 0.0;
}
else if (seed == 1.0) {
tiletype = 1.0;
}
else {
if (extended == 0) {
double xrand = round(pAffineTP.x);
double yrand = round(pAffineTP.y);
xrand = xrand * seed2;
yrand = yrand * seed2;
niter = xrand + yrand + xrand * yrand;
randint = (niter + seed) * seed2 / 2.0;
randint = fmod((randint * multiplier + offset), modbase);
}
else {
seed = floor(seed);
int xrand = (int) round(pAffineTP.x);
int yrand = (int) round(pAffineTP.y);
niter = fabs(xrand + yrand + xrand * yrand);
if (niter > 1000)
niter = 1000;
randint = seed + niter;
randiter = 0;
while (randiter < niter) {
randiter += 1;
randint = fmod((randint * multiplier + offset), modbase);
}
}
tiletype = fmod(randint, 2.0);//randint%2;
}
//DRAWING THE POINTS
if (extended == 0) { //Fast drawmode
if (tiletype < 1.0) {
r0 = pow((pow(fabs(x), n) + pow(fabs(y), n)), onen);
r1 = pow((pow(fabs(x - 1.0), n) + pow(fabs(y - 1.0), n)), onen);
}
else {
r0 = pow((pow(fabs(x - 1.0), n) + pow(fabs(y), n)), onen);
r1 = pow((pow(fabs(x), n) + pow(fabs(y - 1.0), n)), onen);
}
}
else {
if (tiletype == 1.0) { //Slow drawmode
r0 = pow((pow(fabs(x), n) + pow(fabs(y), n)), onen);
r1 = pow((pow(fabs(x - 1.0), n) + pow(fabs(y - 1.0), n)), onen);
}
else {
r0 = pow((pow(fabs(x - 1.0), n) + pow(fabs(y), n)), onen);
r1 = pow((pow(fabs(x), n) + pow(fabs(y - 1.0), n)), onen);
}
}
r = fabs(r0 - 0.5) / rmax;
if (r < 1.0) {
if (direct_color == 1) {
pVarTP.color = limitVal(r0, 0.0, 1.0);
}
pVarTP.x += size * (x + floor(pAffineTP.x));
pVarTP.y += size * (y + floor(pAffineTP.y));
}
r = fabs(r1 - 0.5) / rmax;
if (r < 1.0) {
if (direct_color == 1) {
pVarTP.color = limitVal(1.0 - r1, 0.0, 1.0);
}
pVarTP.x += size * (x + floor(pAffineTP.x));
pVarTP.y += size * (y + floor(pAffineTP.y));
if (pContext.isPreserveZCoordinate()) {
pVarTP.z += pAmount * pAffineTP.z;
}
}
}
@Override
public String[] getParameterNames() {
return paramNames;
}
@Override
public Object[] getParameterValues() {
return new Object[] { extended, exponent, arc_width, rotation, size, seed, direct_color };
}
@Override
public void setParameter(String pName, double pValue) {
if (PARAM_EXTENDED.equalsIgnoreCase(pName))
extended = limitIntVal(Tools.FTOI(pValue), 0, 1);
else if (PARAM_EXPONENT.equalsIgnoreCase(pName))
exponent = pValue;
else if (PARAM_ARC_WIDTH.equalsIgnoreCase(pName))
arc_width = pValue;
else if (PARAM_ROTATION.equalsIgnoreCase(pName))
rotation = pValue;
else if (PARAM_SIZE.equalsIgnoreCase(pName))
size = pValue;
else if (PARAM_SEED.equalsIgnoreCase(pName))
seed = pValue;
else if (PARAM_DIRECT_COLOR.equalsIgnoreCase(pName))
direct_color = limitIntVal(Tools.FTOI(pValue), 0, 1);
else
throw new IllegalArgumentException(pName);
}
@Override
public String getName() {
return "truchet";
}
@Override
public void init(FlameTransformationContext pContext, Layer pLayer, XForm pXForm, double pAmount) {
if (extended < 0) {
extended = 0;
}
else if (extended > 1) {
extended = 1;
}
if (exponent < 0.001) {
exponent = 0.001;
}
else if (exponent > 2.0) {
exponent = 2.0;
}
if (arc_width < 0.001) {
arc_width = 0.001;
}
else if (arc_width > 1.0) {
arc_width = 1.0;
}
if (size < 0.001) {
size = 0.001;
}
else if (size > 10.0) {
size = 10.0;
}
}
}