/*
JWildfire - an image and animation processor written in Java
Copyright (C) 1995-2015 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.iflames;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import org.jwildfire.base.mathlib.MathLib;
import org.jwildfire.create.tina.animate.AnimationService;
import org.jwildfire.create.tina.base.motion.MotionCurve;
public class IFlamesAnimator implements Serializable {
private static final long serialVersionUID = 1L;
private final List<Particle> particles;
private final MotionParams motionParams;
private final Map<String, MotionCurve> motionCurves;
private boolean useMotionStore = true;
private transient IFlamesAnimatorMotionStore motionStore;
private static final float DT = 0.0025f;
public IFlamesAnimator(List<Particle> pParticles, MotionParams pMotionParams, Map<String, MotionCurve> pMotionCurves, IFlamesAnimatorMotionStore pMotionStore) {
particles = pParticles;
motionParams = pMotionParams;
motionCurves = pMotionCurves;
motionStore = pMotionStore;
}
private Vector getForce(float pLocalTime) {
return new Vector(evalProperty((float) motionParams.getForceX0(), MotionParams.PARAM_FORCE_X0, pLocalTime),
evalProperty((float) motionParams.getForceY0(), MotionParams.PARAM_FORCE_Y0, pLocalTime),
evalProperty((float) motionParams.getForceZ0(), MotionParams.PARAM_FORCE_Z0, pLocalTime));
}
private Vector getForceCentre(float pLocalTime) {
return new Vector(evalProperty((float) motionParams.getForceCentreX(), MotionParams.PARAM_FORCE_CENTRE_X, pLocalTime),
evalProperty((float) motionParams.getForceCentreY(), MotionParams.PARAM_FORCE_CENTRE_Y, pLocalTime),
evalProperty((float) motionParams.getForceCentreZ(), MotionParams.PARAM_FORCE_CENTRE_Z, pLocalTime));
}
private float evalProperty(float pStaticValue, String pPropertyname, float pLocalTime) {
MotionCurve curve = motionCurves != null ? motionCurves.get(pPropertyname) : null;
if (curve != null && curve.isEnabled()) {
return (float) AnimationService.evalCurve(localTimeToFrame(pLocalTime), curve);
}
else {
return pStaticValue;
}
}
private float localTimeToFrame(float pLocalTime) {
return pLocalTime * 100.0f;
}
public void animate(float pLocalTime) {
float dt = DT;
float tMax = pLocalTime;
if (tMax < 0.0) {
tMax = 0.0f;
}
float t = motionStore.getMaxStoredMotionTime(tMax, dt);
if (t > MathLib.EPSILON) {
motionStore.readFromStore(t, dt, particles);
while (t < tMax) {
computeNextTimeStep(t, dt);
t += dt;
}
}
else {
for (Particle particle : particles) {
particle.reset();
}
while (t < tMax) {
computeNextTimeStep(t, dt);
t += dt;
}
}
}
private void computeNextTimeStep(float t, float dt) {
for (Particle particle : particles) {
Vector force = getForce(t);
particle.incSpeed(VectorMath.multiply(dt, force));
float radialAccel = particle.getRadialAcceleration() * dt;
float tangentAccel = particle.getTangentialAcceleration() * dt;
if (MathLib.fabs(radialAccel) > MathLib.EPSILON || MathLib.fabs(tangentAccel) > MathLib.EPSILON) {
Vector centre = getForceCentre(t);
Vector normal = VectorMath.normalize(VectorMath.normal(particle.getPosition(), centre));
if (MathLib.fabs(radialAccel) > MathLib.EPSILON) {
particle.incSpeed(VectorMath.multiply(radialAccel, normal));
}
if (MathLib.fabs(tangentAccel) > MathLib.EPSILON) {
Vector tangent = VectorMath.normalize(VectorMath.tangent(particle.getPosition(), centre));
particle.incSpeed(VectorMath.multiply(tangentAccel, tangent));
}
}
particle.incPosition(VectorMath.multiply(dt, particle.getSpeed()));
particle.incRotation(VectorMath.multiply(dt, particle.getRotationSpeed()));
particle.decLife(dt);
}
storeMotion(t, dt);
}
private void storeMotion(float t, float dt) {
if (useMotionStore) {
motionStore.storeMotion(t, dt, particles);
}
}
}