Package org.jwildfire.create.tina.animate

Source Code of org.jwildfire.create.tina.animate.AnimationService$EnvelopePoints

/*
  JWildfire - an image and animation processor written in Java
  Copyright (C) 1995-2012 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.animate;

import static org.jwildfire.base.mathlib.MathLib.EPSILON;
import static org.jwildfire.base.mathlib.MathLib.fabs;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jwildfire.base.Prefs;
import org.jwildfire.base.Tools;
import org.jwildfire.base.mathlib.MathLib;
import org.jwildfire.create.tina.base.Flame;
import org.jwildfire.create.tina.base.Layer;
import org.jwildfire.create.tina.base.XForm;
import org.jwildfire.create.tina.base.motion.MotionCurve;
import org.jwildfire.create.tina.palette.RGBPalette;
import org.jwildfire.create.tina.render.FlameRenderer;
import org.jwildfire.create.tina.render.RenderInfo;
import org.jwildfire.create.tina.render.RenderMode;
import org.jwildfire.create.tina.render.RenderedFlame;
import org.jwildfire.create.tina.variation.Variation;
import org.jwildfire.create.tina.variation.VariationFunc;
import org.jwildfire.envelope.Envelope;
import org.jwildfire.envelope.Envelope.Interpolation;
import org.jwildfire.image.SimpleImage;

public class AnimationService {

  public static SimpleImage renderFrame(Flame flame, int pWidth, int pHeight, Prefs pPrefs) throws Exception {
    RenderInfo info = new RenderInfo(pWidth, pHeight, RenderMode.PRODUCTION);
    double wScl = (double) info.getImageWidth() / (double) flame.getWidth();
    double hScl = (double) info.getImageHeight() / (double) flame.getHeight();
    flame.setPixelsPerUnit((wScl + hScl) * 0.5 * flame.getPixelsPerUnit());
    flame.setWidth(info.getImageWidth());
    flame.setHeight(info.getImageHeight());
    FlameRenderer renderer = new FlameRenderer(flame, pPrefs, flame.isBGTransparency(), false);
    RenderedFlame res = renderer.renderFlame(info);
    return res.getImage();
  }

  public static Flame createFrameFlame(int pFrame, int pFrameCount, double pFPS, Flame pFlame, GlobalScript pGlobalScripts[], XFormScript[] pXFormScripts, int pMotionBlurLength, double pMotionBlurTimeStep, int pWidth, int pHeight, Prefs pPrefs) {
    Flame res = pFlame.makeCopy();
    for (GlobalScript script : pGlobalScripts) {
      AnimationService.addMotionCurve(res, script, pFrame, pFrameCount, pFPS);
    }
    for (XFormScript script : pXFormScripts) {
      AnimationService.addMotionCurve(res, script, pFrame, pFrameCount, pFPS);
    }
    res.setFrame(pFrame);
    res.setMotionBlurLength(pMotionBlurLength);
    res.setMotionBlurTimeStep(pMotionBlurTimeStep);
    return res;
  }

  public static <T> double getPropertyValue(T pSource, String pName) {
    @SuppressWarnings("unchecked")
    Class<T> cls = (Class<T>) pSource.getClass();
    Field field;
    try {
      field = cls.getDeclaredField(pName);
      field.setAccessible(true);
      Class<?> fieldCls = field.getType();
      if (fieldCls == double.class || fieldCls == Double.class) {
        Double res = field.getDouble(pSource);
        return res != null ? res.doubleValue() : 0.0;
      }
      else if (fieldCls == int.class || fieldCls == Integer.class) {
        Integer res = field.getInt(pSource);
        return res != null ? Double.valueOf(res.intValue()) : 0.0;
      }
      else if (fieldCls == boolean.class || fieldCls == Boolean.class) {
        Boolean res = field.getBoolean(pSource);
        return res ? 1.0 : 0.0;
      }
      else {
        throw new IllegalStateException(fieldCls.getName());
      }
    }
    catch (Throwable ex) {
      throw new RuntimeException(ex);
    }
  }

  public static <T> void setPropertyValue(T pDest, String pName, double pValue) {
    @SuppressWarnings("unchecked")
    Class<T> cls = (Class<T>) pDest.getClass();
    Field field;
    try {
      field = cls.getDeclaredField(pName);
      field.setAccessible(true);
      Class<?> fieldCls = field.getType();
      if (fieldCls == double.class || fieldCls == Double.class) {
        field.setDouble(pDest, pValue);
      }
      else if (fieldCls == int.class || fieldCls == Integer.class) {
        field.setInt(pDest, (int) MathLib.round(pValue));
      }
      else if (fieldCls == boolean.class || fieldCls == Boolean.class) {
        field.setBoolean(pDest, (int) MathLib.round(pValue) != 0);
      }
      else {
        throw new IllegalStateException(fieldCls.getName());
      }
    }
    catch (Throwable ex) {
      throw new RuntimeException(ex);
    }
  }

  public static <T> MotionCurve getPropertyCurve(T pSource, String pName) {
    @SuppressWarnings("unchecked")
    Class<T> cls = (Class<T>) pSource.getClass();
    Field field;
    try {
      field = cls.getDeclaredField(pName + Tools.CURVE_POSTFIX);
      field.setAccessible(true);
      Class<?> fieldCls = field.getType();
      if (fieldCls == MotionCurve.class) {
        return (MotionCurve) field.get(pSource);
      }
      else {
        throw new IllegalStateException(fieldCls.getName());
      }
    }
    catch (Throwable ex) {
      throw new RuntimeException(ex);
    }
  }

  public static Flame evalMotionCurves(Flame pFlame, double pFrame) {
    try {
      _evalMotionCurves(pFlame, pFrame);
      return pFlame;
    }
    catch (Throwable ex) {
      throw new RuntimeException(ex);
    }
  }

  private static void _evalMotionCurves(Object pObject, double pFrame) throws IllegalAccessException {
    Class<?> cls = pObject.getClass();
    for (Field field : cls.getDeclaredFields()) {
      field.setAccessible(true);
      if (field.getType() == MotionCurve.class && field.getName().endsWith(Tools.CURVE_POSTFIX)) {
        MotionCurve curve = (MotionCurve) field.get(pObject);
        if (curve.isEnabled()) {
          double value = evalCurve(pFrame, curve);
          String propName = field.getName().substring(0, field.getName().length() - Tools.CURVE_POSTFIX.length());
          curve.getChangeHandler().processValueChange(pObject, propName, value);
          if (pObject instanceof RGBPalette) {
            curve.getChangeHandler().processValueChange(pObject, "modified", 1.0);
          }
          //setPropertyValue(pObject, propName, value);
          //          System.out.println(propName + " " + value);
        }
      }
      else if (field.getType().isAssignableFrom(ArrayList.class)) {
        List<?> childs = (List<?>) field.get(pObject);
        for (Object child : childs) {
          _evalMotionCurves(child, pFrame);
        }
      }
      else if (field.getType().isAssignableFrom(RGBPalette.class)) {
        RGBPalette gradient = (RGBPalette) field.get(pObject);
        _evalMotionCurves(gradient, pFrame);
      }
    }
    if (pObject instanceof Variation) {
      Variation var = (Variation) pObject;
      VariationFunc func = var.getFunc();
      for (String name : func.getParameterNames()) {
        MotionCurve curve = var.getMotionCurve(name);
        if (curve != null && curve.isEnabled()) {
          double value = evalCurve(pFrame, curve);
          try {
            func.setParameter(name, value);
          }
          catch (Exception ex) {
            ex.printStackTrace();
          }
        }
      }
    }
  }

  public static Flame disableMotionCurves(Flame pFlame) {
    try {
      _disableMotionCurves(pFlame);
      return pFlame;
    }
    catch (Throwable ex) {
      throw new RuntimeException(ex);
    }
  }

  private static void _disableMotionCurves(Object pObject) throws IllegalAccessException {
    Class<?> cls = pObject.getClass();
    for (Field field : cls.getDeclaredFields()) {
      field.setAccessible(true);
      if (field.getType() == MotionCurve.class && field.getName().endsWith(Tools.CURVE_POSTFIX)) {
        MotionCurve curve = (MotionCurve) field.get(pObject);
        if (curve.isEnabled()) {
          curve.setEnabled(false);
        }
      }
      else if (field.getType().isAssignableFrom(ArrayList.class)) {
        List<?> childs = (List<?>) field.get(pObject);
        for (Object child : childs) {
          _disableMotionCurves(child);
        }
      }
      else if (field.getType().isAssignableFrom(RGBPalette.class)) {
        RGBPalette gradient = (RGBPalette) field.get(pObject);
        _disableMotionCurves(gradient);
      }
    }
    if (pObject instanceof Variation) {
      Variation var = (Variation) pObject;
      VariationFunc func = var.getFunc();
      for (String name : func.getParameterNames()) {
        MotionCurve curve = var.getMotionCurve(name);
        if (curve != null && curve.isEnabled()) {
          curve.setEnabled(false);
        }
      }
    }
  }

  private static double evalCurve(double pFrame, MotionCurve curve) {
    MotionCurve currCurve = curve;
    double value = 0.0;
    while (currCurve != null) {
      Envelope envelope = currCurve.toEnvelope();
      value += envelope.evaluate(pFrame);
      currCurve = currCurve.getParent();
    }
    return value;
  }

  public static class MotionCurveAttribute {
    private final String name;
    private final MotionCurve motionCurve;

    public MotionCurveAttribute(String pName, MotionCurve pMotionCurve) {
      name = pName;
      motionCurve = pMotionCurve;
    }

    public String getName() {
      return name;
    }

    public MotionCurve getMotionCurve() {
      return motionCurve;
    }
  }

  private static Map<Class<?>, List<Field>> motionCurvePropertyCache = new HashMap<Class<?>, List<Field>>();

  private static List<Field> getMotionCurveProperties(Object pObject) {
    Class<?> cls = pObject.getClass();
    List<Field> res = motionCurvePropertyCache.get(cls);
    if (res == null) {
      res = new ArrayList<Field>();
      motionCurvePropertyCache.put(cls, res);
      for (Field field : cls.getDeclaredFields()) {
        field.setAccessible(true);
        if (field.getType() == MotionCurve.class && field.getName().endsWith(Tools.CURVE_POSTFIX)) {
          res.add(field);
        }
      }
    }
    return res;
  }

  public static List<MotionCurveAttribute> getAllMotionCurves(Object pObject) {
    try {
      List<MotionCurveAttribute> res = new ArrayList<MotionCurveAttribute>();
      for (Field field : getMotionCurveProperties(pObject)) {
        MotionCurve curve = (MotionCurve) field.get(pObject);
        res.add(new MotionCurveAttribute(field.getName(), curve));
      }
      return res;
    }
    catch (Exception ex) {
      throw new RuntimeException(ex);
    }
  }

  public static enum EnvelopePointsShape {
    RAMP, SINE
  }

  public static class EnvelopePoints {
    private int envX[];
    private double envY[];

    public EnvelopePoints(SimpleScript pScript, int pFrameCount, double pFPS, EnvelopePointsShape pDefaultShape, double pAmplitude) {
      if (pScript.getAmplitudeCurve().isEnabled()) {
        int[] srcX = pScript.getAmplitudeCurve().getX();
        double[] srcY = pScript.getAmplitudeCurve().getY();
        if (srcX.length > 1) {
          envX = new int[srcX.length + 2];
          envY = new double[srcY.length + 2];
          for (int i = 0; i < srcX.length; i++) {
            envX[i + 1] = srcX[i];
            envY[i + 1] = (double) pFrameCount / (DFLT_DURATION * pFPS) * srcY[i];
          }
          final int DX = 50;
          double DY;

          DY = (envY[envY.length - 2] - envY[envY.length - 3]) / (double) (envX[envX.length - 2] - envX[envX.length - 3]) * DX;
          if (Double.isInfinite(DY) || Double.isNaN(DY))
            DY = 0.0;
          envX[envX.length - 1] = envX[envX.length - 2] + DX;
          envY[envY.length - 1] = envY[envY.length - 2] + DY;

          DY = (envY[2] - envY[1]) / (double) (envX[2] - envX[1]) * DX;
          if (Double.isInfinite(DY) || Double.isNaN(DY))
            DY = 0.0;

          envX[0] = envX[1] - DX;
          envY[0] = envY[1] - DY;
        }
        else {
          envX = new int[1];
          envY = new double[1];
          envX[0] = -10;
          envY[0] = (double) pFrameCount / (DFLT_DURATION * pFPS) * srcY[0];
        }
      }
      else {
        if (fabs(pScript.getAmplitude()) < EPSILON || fabs(pFPS) < EPSILON) {
          envX = new int[1];
          envY = new double[1];
          envX[0] = 0;
          envY[0] = 0.0;
        }
        else {
          switch (pDefaultShape) {
            case RAMP: {
              double amp = pAmplitude * (double) pFrameCount / (DFLT_DURATION * pFPS) * pScript.getAmplitude();
              envX = new int[2];
              envY = new double[2];
              final int DX = 10;
              final double DY = amp / (double) pFrameCount * (double) DX;
              envX[0] = -DX;
              envY[0] = -DY;
              envX[1] = pFrameCount + DX;
              envY[1] = amp + DY;
            }
              break;
            case SINE: {
              int phase = Tools.FTOI(DFLT_DURATION * pFPS / 2.0);
              int start = -phase;
              int cnt = 1;
              while (start <= pFrameCount + phase) {
                start += phase;
                cnt++;
              }
              envX = new int[cnt];
              envY = new double[cnt];

              start = -phase;
              int state = 1;
              for (int i = 0; i < cnt; i++) {
                envX[i] = start;
                switch (state++ % 4) {
                  case 1:
                    envY[i] = -pScript.getAmplitude();
                    break;
                  case 3:
                    envY[i] = pScript.getAmplitude();
                    break;
                  default:
                    envY[i] = 0.0;
                    break;
                }
                start += phase;
              }
            }
              break;
            default:
              throw new IllegalArgumentException(pDefaultShape.toString());
          }
        }
      }
    }

    public int[] getEnvX() {
      return envX;
    }

    public double[] getEnvY() {
      return envY;
    }
  }

  public static void addMotionCurve(Flame pFlame, GlobalScript pScript, int pFrame, int pFrameCount, double pFPS) {
    if (pScript != null && pScript.getScriptType() != null && !GlobalScriptType.NONE.equals(pScript.getScriptType()) && fabs(pScript.getAmplitude()) > EPSILON) {
      EnvelopePoints points;
      MotionCurve curve = null;
      switch (pScript.getScriptType()) {
        case ROTATE_PITCH:
          curve = pFlame.getCamPitchCurve();
          points = new EnvelopePoints(pScript, pFrameCount, pFPS, EnvelopePointsShape.RAMP, 360.0);
          break;
        case ROTATE_ROLL:
          curve = pFlame.getCamRollCurve();
          points = new EnvelopePoints(pScript, pFrameCount, pFPS, EnvelopePointsShape.RAMP, 360.0);
          break;
        case ROTATE_YAW:
          curve = pFlame.getCamYawCurve();
          points = new EnvelopePoints(pScript, pFrameCount, pFPS, EnvelopePointsShape.RAMP, 360.0);
          break;
        case MOVE_CAM_X:
          curve = pFlame.getCamPosXCurve();
          points = new EnvelopePoints(pScript, pFrameCount, pFPS, EnvelopePointsShape.SINE, 1.0);
          break;
        case MOVE_CAM_Y:
          curve = pFlame.getCamPosYCurve();
          points = new EnvelopePoints(pScript, pFrameCount, pFPS, EnvelopePointsShape.SINE, 1.0);
          break;
        case MOVE_CAM_Z:
          curve = pFlame.getCamPosZCurve();
          points = new EnvelopePoints(pScript, pFrameCount, pFPS, EnvelopePointsShape.SINE, 1.0);
          break;
        default:
          throw new IllegalArgumentException(pScript.toString());
      }
      addEnvelope(pFrameCount, curve, points.getEnvX(), points.getEnvY());
    }
  }

  private static void addEnvelope(int pFrameCount, MotionCurve curve, int[] envX, double[] envY) {
    Envelope envelope = new Envelope(envX, envY);
    envelope.setViewXMin(-10);
    envelope.setViewXMax(10 + pFrameCount);
    envelope.setViewYMin(-10000.0);
    envelope.setViewYMax(10000.0);
    envelope.setInterpolation(Interpolation.SPLINE);
    envelope.setSelectedIdx(0);

    if (!curve.isEnabled()) {
      curve.assignFromEnvelope(envelope);
      curve.setEnabled(true);
    }
    else {
      MotionCurve newParentCurve = new MotionCurve();
      newParentCurve.setEnabled(true);
      newParentCurve.assignFromEnvelope(envelope);
      while (curve.getParent() != null) {
        curve = curve.getParent();
      }
      curve.setParent(newParentCurve);
    }
  }

  public static double DFLT_DURATION = 6.0;

  public static void addMotionCurve(Flame pFlame, XFormScript pScript, int pFrame, int pFrameCount, double pFPS) {
    if (pScript != null && pScript.getScriptType() != null && !XFormScriptType.NONE.equals(pScript.getScriptType()) && fabs(pScript.getAmplitude()) > EPSILON) {
      for (Layer layer : pFlame.getLayers()) {
        switch (pScript.getScriptType()) {
          case ROTATE_FULL: {
            int idx = 0;
            for (XForm xForm : layer.getXForms()) {
              MotionCurve curve = xForm.getRotateCurve();
              EnvelopePoints points = new EnvelopePoints(pScript, pFrameCount, pFPS, EnvelopePointsShape.RAMP, idx++ % 2 == 0 ? 360.0 : -360.0);
              addEnvelope(pFrameCount, curve, points.getEnvX(), points.getEnvY());
            }
          }
            break;
          case ROTATE_POST_FULL: {
            int idx = 0;
            for (XForm xForm : layer.getXForms()) {
              MotionCurve curve = xForm.getPostRotateCurve();
              EnvelopePoints points = new EnvelopePoints(pScript, pFrameCount, pFPS, EnvelopePointsShape.RAMP, idx++ % 2 == 0 ? 360.0 : -360.0);
              addEnvelope(pFrameCount, curve, points.getEnvX(), points.getEnvY());
            }
          }
            break;
          case ROTATE_FIRST_XFORM:
          case ROTATE_2ND_XFORM:
          case ROTATE_3RD_XFORM:
          case ROTATE_4TH_XFORM:
          case ROTATE_5TH_XFORM:
          case ROTATE_LAST_XFORM:
          case ROTATE_FINAL_XFORM: {
            XForm xForm = null;
            xForm = getXForm(pScript.getScriptType(), layer, xForm);

            if (xForm != null) {
              EnvelopePoints points = new EnvelopePoints(pScript, pFrameCount, pFPS, EnvelopePointsShape.RAMP, 360.0);
              MotionCurve curve = xForm.getRotateCurve();
              addEnvelope(pFrameCount, curve, points.getEnvX(), points.getEnvY());
            }
          }
            break;
          case ROTATE_POST_FIRST_XFORM:
          case ROTATE_POST_2ND_XFORM:
          case ROTATE_POST_3RD_XFORM:
          case ROTATE_POST_4TH_XFORM:
          case ROTATE_POST_5TH_XFORM:
          case ROTATE_POST_LAST_XFORM:
          case ROTATE_POST_FINAL_XFORM: {
            XForm xForm = null;
            xForm = getXForm(pScript.getScriptType(), layer, xForm);

            if (xForm != null) {
              EnvelopePoints points = new EnvelopePoints(pScript, pFrameCount, pFPS, EnvelopePointsShape.RAMP, 360.0);
              MotionCurve curve = xForm.getPostRotateCurve();
              addEnvelope(pFrameCount, curve, points.getEnvX(), points.getEnvY());
            }
          }
            break;
          default:
            throw new IllegalArgumentException(pScript.toString());
        }
        break;
      }
    }
  }

  private static XForm getXForm(XFormScriptType pScript, Layer layer, XForm xForm) {
    switch (pScript) {
      case ROTATE_FIRST_XFORM:
      case ROTATE_POST_FIRST_XFORM:
        return layer.getXForms().size() > 0 ? layer.getXForms().get(0) : null;
      case ROTATE_2ND_XFORM:
      case ROTATE_POST_2ND_XFORM:
        return layer.getXForms().size() > 1 ? layer.getXForms().get(1) : null;
      case ROTATE_3RD_XFORM:
      case ROTATE_POST_3RD_XFORM:
        return layer.getXForms().size() > 2 ? layer.getXForms().get(2) : null;
      case ROTATE_4TH_XFORM:
      case ROTATE_POST_4TH_XFORM:
        return layer.getXForms().size() > 3 ? layer.getXForms().get(3) : null;
      case ROTATE_5TH_XFORM:
      case ROTATE_POST_5TH_XFORM:
        return layer.getXForms().size() > 4 ? layer.getXForms().get(4) : null;
      case ROTATE_LAST_XFORM:
      case ROTATE_POST_LAST_XFORM:
        return layer.getXForms().size() > 0 ? layer.getXForms().get(layer.getXForms().size() - 1) : null;
      case ROTATE_FINAL_XFORM:
      case ROTATE_POST_FINAL_XFORM:
        return layer.getFinalXForms().size() > 0 ? layer.getFinalXForms().get(0) : null;
      default:
        throw new IllegalArgumentException(pScript.toString());
    }
  }

}
TOP

Related Classes of org.jwildfire.create.tina.animate.AnimationService$EnvelopePoints

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.