Package org.jwildfire.create.tina.dance.model

Source Code of org.jwildfire.create.tina.dance.model.AnimationModelService

/*
  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.dance.model;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;

import org.jwildfire.base.Tools;
import org.jwildfire.create.tina.animate.AnimAware;
import org.jwildfire.create.tina.base.Flame;
import org.jwildfire.create.tina.base.Layer;
import org.jwildfire.create.tina.base.ShadingInfo;
import org.jwildfire.create.tina.base.XForm;
import org.jwildfire.create.tina.palette.RGBPalette;
import org.jwildfire.create.tina.transform.XFormTransformService;
import org.jwildfire.create.tina.variation.Variation;
import org.jwildfire.create.tina.variation.VariationFunc;

public class AnimationModelService {

  private static boolean isPrimitiveProperty(Class<?> pCls) {
    return pCls == Integer.class || pCls == int.class || pCls == Double.class || pCls == double.class || pCls == Boolean.class || pCls == boolean.class;
  }

  private static interface PropertyVisitor {
    public boolean accept(Object pOwner, Field pField, PlainProperty pProperty);

    public boolean accept(VariationFunc pVarFunc, PlainProperty pProperty);

    public boolean accept(XForm pXForm, String pPropName, PlainProperty pProperty);

    public boolean finishOnAccept();
  }

  public static PropertyModel createModel(Flame pFlame) {
    PropertyModel res = new PropertyModel(null, "flame", pFlame.getClass());
    visitModel(res, pFlame, null);
    return res;
  }

  private static class VisitState {
    private final PropertyVisitor visitor;
    private boolean accepted;

    public VisitState(PropertyVisitor pVisitor) {
      visitor = pVisitor;
    }

    public boolean isCancelSignalled() {
      return accepted && visitor != null && visitor.finishOnAccept();
    }

    public void updateState(boolean pAccept) {
      accepted = pAccept;
    }

  }

  @SuppressWarnings("unchecked")
  public static void visitModel(PropertyModel res, Flame pFlame, PropertyVisitor pVisitor) {
    VisitState state = new VisitState(pVisitor);
    Class<?> cls = pFlame.getClass();
    for (Field field : cls.getDeclaredFields()) {
      if (state.isCancelSignalled()) {
        return;
      }
      field.setAccessible(true);
      if (field.getAnnotation(AnimAware.class) != null) {
        Class<?> fCls = field.getType();
        if (isPrimitiveProperty(fCls)) {
          PlainProperty property = new PlainProperty(res, field.getName(), cls);
          res.getProperties().add(property);
          if (pVisitor != null) {
            state.updateState(pVisitor.accept(pFlame, field, property));
          }
        }
        else if (fCls == RGBPalette.class) {
          try {
            RGBPalette palette = (RGBPalette) field.get(pFlame);
            addGradientToModel(res, palette, pVisitor, state);
          }
          catch (Exception e) {
            e.printStackTrace();
          }
        }
        else if (fCls == ShadingInfo.class) {
          try {
            ShadingInfo shadingInfo = (ShadingInfo) field.get(pFlame);
            addShadingInfoToModel(res, shadingInfo, pVisitor, state);
          }
          catch (Exception e) {
            e.printStackTrace();
          }
        }
        else if (fCls == List.class) {
          ParameterizedType listType = (ParameterizedType) field.getGenericType();
          Class<?> listSubClass = (Class<?>) listType.getActualTypeArguments()[0];
          if (listSubClass.isAssignableFrom(Layer.class)) {
            List<Layer> layers;
            try {
              layers = (List<Layer>) field.get(pFlame);
            }
            catch (Exception e) {
              layers = null;
              e.printStackTrace();
            }
            if (layers != null) {
              int idx = 0;
              for (Layer layer : layers) {
                addLayerToModel(res, idx++, layer, pVisitor, state);
              }
            }
          }
        }
      }
    }
  }

  private static void addShadingInfoToModel(PropertyModel pNode, ShadingInfo pShadingInfo, PropertyVisitor pVisitor, VisitState pState) {
    Class<?> cls = pShadingInfo.getClass();
    String fieldname = PROPNAME_SHADING;
    PropertyModel shadingNode = new PropertyModel(pNode, fieldname, cls);
    pNode.getChields().add(shadingNode);
    for (Field field : cls.getDeclaredFields()) {
      if (pState.isCancelSignalled()) {
        return;
      }
      field.setAccessible(true);
      if (field.getAnnotation(AnimAware.class) != null) {
        Class<?> fCls = field.getType();
        if (isPrimitiveProperty(fCls)) {
          PlainProperty property = new PlainProperty(shadingNode, field.getName(), cls);
          shadingNode.getProperties().add(property);
          if (pVisitor != null) {
            pState.updateState(pVisitor.accept(pShadingInfo, field, property));
          }
        }
      }
    }
  }

  private static void addGradientToModel(PropertyModel pNode, RGBPalette pPalette, PropertyVisitor pVisitor, VisitState pState) {
    Class<?> cls = pPalette.getClass();
    String fieldname = PROPNAME_GRADIENT;
    PropertyModel gradientNode = new PropertyModel(pNode, fieldname, cls);
    pNode.getChields().add(gradientNode);
    for (Field field : cls.getDeclaredFields()) {
      if (pState.isCancelSignalled()) {
        return;
      }
      field.setAccessible(true);
      if (field.getAnnotation(AnimAware.class) != null) {
        Class<?> fCls = field.getType();
        if (isPrimitiveProperty(fCls)) {
          PlainProperty property = new PlainProperty(gradientNode, field.getName(), cls);
          gradientNode.getProperties().add(property);
          if (pVisitor != null) {
            pState.updateState(pVisitor.accept(pPalette, field, property));
          }
        }
      }
    }
  }

  public final static String PROPNAME_LAYER = "layer";
  public final static String PROPNAME_XFORM = "transform";
  public final static String PROPNAME_FINALXFORM = "finalTransform";
  public final static String PROPNAME_GRADIENT = "gradient";
  public final static String PROPNAME_SHADING = "shading";
  public final static String PROPNAME_ORIGIN_X = "originX";
  public final static String PROPNAME_ORIGIN_Y = "originY";
  public final static String PROPNAME_ANGLE = "angle";
  public final static String PROPNAME_ZOOM = "zoom";
  public final static String PROPNAME_POST_ORIGIN_X = "postOriginX";
  public final static String PROPNAME_POST_ORIGIN_Y = "postOriginY";
  public final static String PROPNAME_POST_ANGLE = "postAngle";
  public final static String PROPNAME_POST_ZOOM = "postZoom";

  private final static String[] ADD_XFORM_PROPS = { PROPNAME_ORIGIN_X, PROPNAME_ORIGIN_Y, PROPNAME_ANGLE, PROPNAME_ZOOM, PROPNAME_POST_ORIGIN_X, PROPNAME_POST_ORIGIN_Y, PROPNAME_POST_ANGLE, PROPNAME_POST_ZOOM };

  @SuppressWarnings("unchecked")
  private static void addXFormToModel(PropertyModel pNode, boolean pIsFinal, int pIndex, XForm pXForm, PropertyVisitor pVisitor, VisitState pState) {
    Class<?> cls = pXForm.getClass();
    String fieldname = pIsFinal ? PROPNAME_FINALXFORM : PROPNAME_XFORM;
    PropertyModel xFormNode = new PropertyModel(pNode, fieldname + (pIndex + 1), cls);
    pNode.getChields().add(xFormNode);
    for (String propName : ADD_XFORM_PROPS) {
      if (pState.isCancelSignalled()) {
        return;
      }
      PlainProperty property = new PlainProperty(xFormNode, propName, Double.class);
      xFormNode.getProperties().add(property);
      if (pVisitor != null) {
        pState.updateState(pVisitor.accept(pXForm, propName, property));
      }
    }
    for (Field field : cls.getDeclaredFields()) {
      if (pState.isCancelSignalled()) {
        return;
      }
      field.setAccessible(true);
      if (field.getAnnotation(AnimAware.class) != null) {
        Class<?> fCls = field.getType();
        if (isPrimitiveProperty(fCls)) {
          PlainProperty property = new PlainProperty(xFormNode, field.getName(), cls);
          xFormNode.getProperties().add(property);
          if (pVisitor != null) {
            pState.updateState(pVisitor.accept(pXForm, field, property));
          }
        }
        else if (fCls == List.class) {
          ParameterizedType listType = (ParameterizedType) field.getGenericType();
          Class<?> listSubClass = (Class<?>) listType.getActualTypeArguments()[0];
          if (listSubClass.isAssignableFrom(Variation.class)) {
            List<Variation> variations;
            try {
              variations = (List<Variation>) field.get(pXForm);
            }
            catch (Exception e) {
              variations = null;
              e.printStackTrace();
            }
            if (variations != null) {
              for (Variation variation : variations) {
                addVariationToModel(xFormNode, variation, pVisitor, pState);
              }
            }
          }
        }
      }
    }
  }

  @SuppressWarnings("unchecked")
  private static void addLayerToModel(PropertyModel pNode, int pIndex, Layer pLayer, PropertyVisitor pVisitor, VisitState pState) {
    Class<?> cls = pLayer.getClass();
    PropertyModel layerNode = new PropertyModel(pNode, PROPNAME_LAYER + (pIndex + 1), cls);
    pNode.getChields().add(layerNode);
    for (Field field : cls.getDeclaredFields()) {
      if (pState.isCancelSignalled()) {
        return;
      }
      field.setAccessible(true);
      if (field.getAnnotation(AnimAware.class) != null) {
        Class<?> fCls = field.getType();
        if (isPrimitiveProperty(fCls)) {
          PlainProperty property = new PlainProperty(layerNode, field.getName(), cls);
          layerNode.getProperties().add(property);
          if (pVisitor != null) {
            pState.updateState(pVisitor.accept(pLayer, field, property));
          }
        }
        else if (fCls == List.class) {
          ParameterizedType listType = (ParameterizedType) field.getGenericType();
          Class<?> listSubClass = (Class<?>) listType.getActualTypeArguments()[0];
          if (listSubClass.isAssignableFrom(XForm.class)) {
            List<XForm> xForms;
            try {
              xForms = (List<XForm>) field.get(pLayer);
            }
            catch (Exception e) {
              xForms = null;
              e.printStackTrace();
            }
            if (xForms != null) {
              int idx = 0;
              for (XForm xForm : xForms) {
                addXFormToModel(layerNode, field.getName().indexOf("final") == 0, idx++, xForm, pVisitor, pState);
              }
            }
          }
        }
      }
    }
  }

  private static void addVariationToModel(PropertyModel pXFormNode, Variation pVariation, PropertyVisitor pVisitor, VisitState pState) {
    Class<?> cls = pVariation.getClass();
    PropertyModel variationNode = new PropertyModel(pXFormNode, pVariation.getFunc().getName(), cls);
    pXFormNode.getChields().add(variationNode);
    for (Field field : cls.getDeclaredFields()) {
      if (pState.isCancelSignalled()) {
        return;
      }
      field.setAccessible(true);
      if (field.getAnnotation(AnimAware.class) != null) {
        Class<?> fCls = field.getType();
        if (isPrimitiveProperty(fCls)) {
          PlainProperty property = new PlainProperty(variationNode, field.getName(), cls);
          variationNode.getProperties().add(property);
          if (pVisitor != null) {
            pState.updateState(pVisitor.accept(pVariation, field, property));
          }
        }
      }
    }
    VariationFunc varFunc = pVariation.getFunc();
    String[] params = varFunc.getParameterNames();
    Object[] vals = varFunc.getParameterValues();
    if (params != null) {
      for (int i = 0; i < params.length; i++) {
        if (pState.isCancelSignalled()) {
          return;
        }
        Object val = vals[i];
        if (val instanceof Double) {
          PlainProperty property = new PlainProperty(variationNode, params[i], Double.class);
          variationNode.getProperties().add(property);
          if (pVisitor != null) {
            pState.updateState(pVisitor.accept(varFunc, property));
          }
        }
        else if (val instanceof Integer) {
          PlainProperty property = new PlainProperty(variationNode, params[i], Integer.class);
          variationNode.getProperties().add(property);
          if (pVisitor != null) {
            pState.updateState(pVisitor.accept(varFunc, property));
          }
        }
      }
    }
  }

  public static List<String> createFlamePropertyPath(String pProperty) {
    List<String> res = new ArrayList<String>();
    res.add(pProperty);
    return res;
  }

  public static List<String> createXFormPropertyPath(int pLayerIdx, int pXFormIndex, String pProperty) {
    List<String> res = new ArrayList<String>();
    res.add(PROPNAME_LAYER + (pLayerIdx + 1));
    res.add(PROPNAME_XFORM + (pXFormIndex + 1));
    res.add(pProperty);
    return res;
  }

  public static List<String> createFinalXFormPropertyPath(int pLayerIdx, int pXFormIndex, String pProperty) {
    List<String> res = new ArrayList<String>();
    res.add(PROPNAME_LAYER + (pLayerIdx + 1));
    res.add(PROPNAME_FINALXFORM + (pXFormIndex + 1));
    res.add(pProperty);
    return res;
  }

  private enum ModifyPropMode {
    SET, ADD
  }

  private static class ModifyPropertyVisitor implements PropertyVisitor {
    private final List<String> path;
    protected double value;
    private boolean hasFound = false;
    protected ModifyPropMode mode = ModifyPropMode.SET;

    public ModifyPropertyVisitor(FlamePropertyPath pPath, double pValue) {
      path = pPath.getPathComponents();
      value = pValue;
    }

    public boolean accept(PlainProperty pProperty) {
      AbstractProperty currNode = pProperty;
      hasFound = currNode.getDepth() == path.size();
      for (int i = path.size() - 1; hasFound && i >= 0; i--) {
        if (!currNode.getName().equals(path.get(i))) {
          hasFound = false;
          break;
        }
        currNode = currNode.getParent();
      }
      return hasFound;
    }

    public boolean isHasFound() {
      return hasFound;
    }

    @Override
    public boolean finishOnAccept() {
      return true;
    }

    @Override
    public boolean accept(Object pOwner, Field pField, PlainProperty pProperty) {
      boolean accepted = accept(pProperty);
      if (accepted) {
        if (pField.getType() == Double.class || pField.getType() == double.class) {
          try {
            switch (mode) {
              case SET:
                pField.setDouble(pOwner, value);
                break;
              case ADD:
                Double o = pField.getDouble(pOwner);
                if (o == null) {
                  o = 0.0;
                }
                o += value;
                pField.setDouble(pOwner, o);
                break;
            }
          }
          catch (IllegalArgumentException e) {
            throw new RuntimeException(e);
          }
          catch (IllegalAccessException e) {
            throw new RuntimeException(e);
          }
        }
        else if (pField.getType() == Integer.class || pField.getType() == int.class) {
          try {
            switch (mode) {
              case SET:
                pField.setInt(pOwner, Tools.FTOI(value));
                break;
              case ADD:
                Integer o = pField.getInt(pOwner);
                if (o == null) {
                  o = 0;
                }
                o += Tools.FTOI(value);
                System.out.println(o);
                pField.setInt(pOwner, o);
                break;
            }
          }
          catch (IllegalArgumentException e) {
            throw new RuntimeException(e);
          }
          catch (IllegalAccessException e) {
            throw new RuntimeException(e);
          }
        }
        else if (pField.getType() == Boolean.class || pField.getType() == boolean.class) {
          try {
            switch (mode) {
              case SET:
                pField.setBoolean(pOwner, Tools.FTOI(value) != 0);
                break;
            }
          }
          catch (IllegalArgumentException e) {
            throw new RuntimeException(e);
          }
          catch (IllegalAccessException e) {
            throw new RuntimeException(e);
          }
        }
        else {
          throw new RuntimeException("Unsupporded property type <" + pField.getType() + ">");
        }
      }
      return accepted;
    }

    @Override
    public boolean accept(VariationFunc pVarFunc, PlainProperty pProperty) {
      boolean accepted = accept(pProperty);
      if (accepted) {
        pVarFunc.setParameter(pProperty.getName(), value);
      }
      return accepted;
    }

    @Override
    public boolean accept(XForm pXForm, String pPropName, PlainProperty pProperty) {
      boolean accepted = accept(pProperty);
      if (accepted) {
        if (pPropName.equals(PROPNAME_ORIGIN_X)) {
          XFormTransformService.localTranslate(pXForm, value, 0, false);
        }
        else if (pPropName.equals(PROPNAME_ORIGIN_Y)) {
          XFormTransformService.localTranslate(pXForm, 0, value, false);
        }
        else if (pPropName.equals(PROPNAME_ANGLE)) {
          XFormTransformService.rotate(pXForm, value, false);
        }
        else if (pPropName.equals(PROPNAME_ZOOM)) {
          XFormTransformService.scale(pXForm, value, true, true, false);
        }
        else if (pPropName.equals(PROPNAME_POST_ORIGIN_X)) {
          XFormTransformService.localTranslate(pXForm, value, 0, true);
        }
        else if (pPropName.equals(PROPNAME_POST_ORIGIN_Y)) {
          XFormTransformService.localTranslate(pXForm, 0, value, true);
        }
        else if (pPropName.equals(PROPNAME_POST_ANGLE)) {
          XFormTransformService.rotate(pXForm, value, true);
        }
        else if (pPropName.equals(PROPNAME_POST_ZOOM)) {
          XFormTransformService.scale(pXForm, value, true, true, true);
        }
        else {
          throw new RuntimeException("Virtual property <" + pPropName + "> not supported");
        }
      }
      return accepted;
    }

  }

  public static void setFlameProperty(Flame pFlame, FlamePropertyPath pPath, double pValue) {
    PropertyModel res = new PropertyModel(null, "flame", pFlame.getClass());
    ModifyPropertyVisitor visitor = new ModifyPropertyVisitor(pPath, pValue);
    visitModel(res, pFlame, visitor);
    if (!visitor.isHasFound()) {
      throw new RuntimeException("Property <" + pPath.getPath() + "> not found");
    }
  }

}
TOP

Related Classes of org.jwildfire.create.tina.dance.model.AnimationModelService

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.