public static KeyframeSet ofFloat(float... values) {
   int numKeyframes = values.length;
   FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes, 2)];
   if (numKeyframes == 1) {
     keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f);
     keyframes[1] = (FloatKeyframe) Keyframe.ofFloat(1f, values[0]);
   } else {
     keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f, values[0]);
     for (int i = 1; i < numKeyframes; ++i) {
       keyframes[i] = (FloatKeyframe) Keyframe.ofFloat((float) i / (numKeyframes - 1), values[i]);
     }
   }
   return new FloatKeyframeSet(keyframes);
 }
 public KeyframeSet(Keyframe... keyframes) {
   mNumKeyframes = keyframes.length;
   mKeyframes = new ArrayList<Keyframe>();
   mKeyframes.addAll(Arrays.asList(keyframes));
   mFirstKeyframe = mKeyframes.get(0);
   mLastKeyframe = mKeyframes.get(mNumKeyframes - 1);
   mInterpolator = mLastKeyframe.getInterpolator();
 }
 /**
  * Internal function (called from ObjectAnimator) to set up the setter and getter prior to running
  * the animation. If the setter has not been manually set for this object, it will be derived
  * automatically given the property name, target object, and types of values supplied. If no
  * getter has been set, it will be supplied iff any of the supplied values was null. If there is a
  * null value, then the getter (supplied or derived) will be called to set those null values to
  * the current value of the property on the target object.
  *
  * @param target The object on which the setter (and possibly getter) exist.
  */
 void setupSetterAndGetter(Object target) {
   // if (mProperty != null) {
   //    // check to make sure that mProperty is on the class of target
   //    try {
   //        Object testValue = mProperty.get(target);
   //        for (Keyframe kf : mKeyframeSet.mKeyframes) {
   //            if (!kf.hasValue()) {
   //                kf.setValue(mProperty.get(target));
   //            }
   //        }
   //        return;
   //    } catch (ClassCastException e) {
   //        Log.e("PropertyValuesHolder","No such property (" + mProperty.getName() +
   //                ") on target object " + target + ". Trying reflection instead");
   //        mProperty = null;
   //    }
   // }
   Class targetClass = target.getClass();
   if (mSetter == null) {
     setupSetter(targetClass);
   }
   for (Keyframe kf : mKeyframeSet.mKeyframes) {
     if (!kf.hasValue()) {
       if (mGetter == null) {
         setupGetter(targetClass);
       }
       try {
         kf.setValue(mGetter.invoke(target));
       } catch (InvocationTargetException e) {
         Log.e("PropertyValuesHolder", e.toString());
       } catch (IllegalAccessException e) {
         Log.e("PropertyValuesHolder", e.toString());
       }
     }
   }
 }
 /**
  * Utility function to set the value stored in a particular Keyframe. The value used is whatever
  * the value is for the property name specified in the keyframe on the target object.
  *
  * @param target The target object from which the current value should be extracted.
  * @param kf The keyframe which holds the property name and value.
  */
 private void setupValue(Object target, Keyframe kf) {
   // if (mProperty != null) {
   //    kf.setValue(mProperty.get(target));
   // }
   try {
     if (mGetter == null) {
       Class targetClass = target.getClass();
       setupGetter(targetClass);
     }
     kf.setValue(mGetter.invoke(target));
   } catch (InvocationTargetException e) {
     Log.e("PropertyValuesHolder", e.toString());
   } catch (IllegalAccessException e) {
     Log.e("PropertyValuesHolder", e.toString());
   }
 }
  /**
   * Gets the animated value, given the elapsed fraction of the animation (interpolated by the
   * animation's interpolator) and the evaluator used to calculate in-between values. This function
   * maps the input fraction to the appropriate keyframe interval and a fraction between them and
   * returns the interpolated value. Note that the input fraction may fall outside the [0-1] bounds,
   * if the animation's interpolator made that happen (e.g., a spring interpolation that might send
   * the fraction past 1.0). We handle this situation by just using the two keyframes at the
   * appropriate end when the value is outside those bounds.
   *
   * @param fraction The elapsed fraction of the animation
   * @return The animated value.
   */
  public Object getValue(float fraction) {

    // Special-case optimization for the common case of only two keyframes
    if (mNumKeyframes == 2) {
      if (mInterpolator != null) {
        fraction = mInterpolator.getInterpolation(fraction);
      }
      return mEvaluator.evaluate(fraction, mFirstKeyframe.getValue(), mLastKeyframe.getValue());
    }
    if (fraction <= 0f) {
      final Keyframe nextKeyframe = mKeyframes.get(1);
      final TimeInterpolator interpolator = nextKeyframe.getInterpolator();
      if (interpolator != null) {
        fraction = interpolator.getInterpolation(fraction);
      }
      final float prevFraction = mFirstKeyframe.getFraction();
      float intervalFraction =
          (fraction - prevFraction) / (nextKeyframe.getFraction() - prevFraction);
      return mEvaluator.evaluate(
          intervalFraction, mFirstKeyframe.getValue(), nextKeyframe.getValue());
    } else if (fraction >= 1f) {
      final Keyframe prevKeyframe = mKeyframes.get(mNumKeyframes - 2);
      final TimeInterpolator interpolator = mLastKeyframe.getInterpolator();
      if (interpolator != null) {
        fraction = interpolator.getInterpolation(fraction);
      }
      final float prevFraction = prevKeyframe.getFraction();
      float intervalFraction =
          (fraction - prevFraction) / (mLastKeyframe.getFraction() - prevFraction);
      return mEvaluator.evaluate(
          intervalFraction, prevKeyframe.getValue(), mLastKeyframe.getValue());
    }
    Keyframe prevKeyframe = mFirstKeyframe;
    for (int i = 1; i < mNumKeyframes; ++i) {
      Keyframe nextKeyframe = mKeyframes.get(i);
      if (fraction < nextKeyframe.getFraction()) {
        final TimeInterpolator interpolator = nextKeyframe.getInterpolator();
        if (interpolator != null) {
          fraction = interpolator.getInterpolation(fraction);
        }
        final float prevFraction = prevKeyframe.getFraction();
        float intervalFraction =
            (fraction - prevFraction) / (nextKeyframe.getFraction() - prevFraction);
        return mEvaluator.evaluate(
            intervalFraction, prevKeyframe.getValue(), nextKeyframe.getValue());
      }
      prevKeyframe = nextKeyframe;
    }
    // shouldn't reach here
    return mLastKeyframe.getValue();
  }
  public Animation read(FileHandle handle) {
    XmlReader rdr = new XmlReader();
    try {

      Element root = rdr.parse(handle);
      int frameRate = Integer.parseInt(root.getChildByName("FrameRate").getText());
      int loopFrame = Integer.parseInt(root.getChildByName("LoopFrame").getText());

      Animation anim = new Animation();
      anim.FrameRate = frameRate;
      anim.LoopFrame = loopFrame;
      anim.Textures = new ArrayList<TextureEntry>();
      anim.Loop = loopFrame != -1;
      anim.Keyframes = new ArrayList<Keyframe>();

      for (int i = 0; i < root.getChildCount(); ++i) {
        Element ch = root.getChild(i);
        if (ch.getName().equals("Texture")) {
          TextureRegion reg = imgSrc.getImage(ch.getText());
          if (reg != null) {
            TextureAtlas.AtlasRegion r = (TextureAtlas.AtlasRegion) reg;
            anim.Textures.add(
                new TextureEntry(
                    reg,
                    new TextureBounds(
                        new Rectangle(0, 0, r.originalWidth, r.originalHeight),
                        new Vector2(r.originalWidth / 2, r.originalHeight / 2))));
          } else {
            throw new Exception("Unable to resolve image: " + ch.getText());
          }
        }
      }

      for (int i = 0; i < root.getChildCount(); ++i) {
        Element ch = root.getChild(i);
        if (ch.getName().equals("Keyframe")) {
          Keyframe frame = new Keyframe();
          frame.Bones = new ArrayList<Bone>();
          frame.FrameNumber = ch.getIntAttribute("frame");
          frame.Trigger = ch.getAttribute("trigger", "");
          frame.FlipHorizontally = ch.getAttribute("hflip", "False").equals("True");
          frame.FlipVertically = ch.getAttribute("vflip", "False").equals("True");

          for (int j = 0; j < ch.getChildCount(); ++j) {
            Element bone = ch.getChild(j);
            if (bone.getName().equals("Bone")) {
              Element posElem = bone.getChildByName("Position");
              Element sclElem = bone.getChildByName("Scale");
              Vector2 pos = new Vector2();
              Vector2 scl = new Vector2();

              pos.x = Float.parseFloat(posElem.getChildByName("X").getText());
              pos.y = Float.parseFloat(posElem.getChildByName("Y").getText());

              scl.x = Float.parseFloat(sclElem.getChildByName("X").getText());
              scl.y = Float.parseFloat(sclElem.getChildByName("Y").getText());

              Bone b = new Bone();
              b.Hidden = bone.getChildByName("Hidden").getText().equals("True");
              b.Name = bone.getAttribute("name");
              b.TextureFlipHorizontal =
                  bone.getChildByName("TextureFlipHorizontal").getText().equals("True");
              b.TextureFlipVertical =
                  bone.getChildByName("TextureFlipVertical").getText().equals("True");
              b.ParentIndex = Integer.parseInt(bone.getChildByName("ParentIndex").getText());
              b.TextureIndex = Integer.parseInt(bone.getChildByName("TextureIndex").getText());
              b.Rotation = Float.parseFloat(bone.getChildByName("Rotation").getText());

              b.Position = pos;
              b.Scale = scl;
              b.SelfIndex = j;

              frame.Bones.add(b);
            }
          }

          frame.SortBones();
          anim.Keyframes.add(frame);
        }

        float fr = 1.0f / anim.FrameRate;
        anim.LoopTime = anim.LoopFrame * anim.FrameRate;
        anim.Loop = anim.LoopFrame != -1;
        for (Keyframe kf : anim.Keyframes) {
          kf.FrameTime = fr * kf.FrameNumber;
        }
      }

      return anim;
    } catch (Exception ex) {
      Gdx.app.log("AnimationReader", "read", ex);
      return null;
    }
  }