/**************************************************************************
* Copyright 2013 by Trixt0r
* (https://github.com/Trixt0r, Heinrich Reich, e-mail: trixter16@web.de)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
package com.brashmonkey.spriter.mergers;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import com.brashmonkey.spriter.SpriterCalculator;
import com.brashmonkey.spriter.animation.SpriterAnimation;
import com.brashmonkey.spriter.animation.SpriterKeyFrame;
import com.brashmonkey.spriter.interpolation.SpriterLinearInterpolator;
import com.brashmonkey.spriter.objects.SpriterAbstractObject;
//import com.brashmonkey.spriter.converters.SpriterObjectConverter;
import com.brashmonkey.spriter.objects.SpriterBone;
import com.brashmonkey.spriter.objects.SpriterObject;
import com.discobeard.spriter.dom.Animation;
//import com.discobeard.spriter.dom.AnimationObject;
import com.discobeard.spriter.dom.AnimationObjectRef;
import com.discobeard.spriter.dom.BoneRef;
import com.discobeard.spriter.dom.Key;
import com.discobeard.spriter.dom.MainLine;
import com.discobeard.spriter.dom.TimeLine;
public class SpriterAnimationBuilder {
final private SpriterBoneMerger boneMerger = new SpriterBoneMerger();
final private SpriterObjectMerger objectMerger = new SpriterObjectMerger();
//final private SpriterObjectConverter objectConverter = new SpriterObjectConverter();
HashMap<SpriterBone, Integer> bonesToTween;
HashMap<SpriterObject, Integer> objectsToTween;
public SpriterAnimation buildAnimation(Animation animation){
MainLine mainline = animation.getMainline();
List<TimeLine> timeLines = animation.getTimeline();
List<Key> keyFrames = mainline.getKey();
bonesToTween = new HashMap<SpriterBone, Integer>();
objectsToTween = new HashMap<SpriterObject, Integer>();
SpriterAnimation spriterAnimation = new SpriterAnimation(animation.getId(), animation.getName(), animation.getLength());
for(int k=0;k<keyFrames.size();k++){
Key mainlineKey = keyFrames.get(k);
List<SpriterObject> tempObjects = new ArrayList<SpriterObject>();
List<SpriterBone> tempBones = new ArrayList<SpriterBone>();
SpriterKeyFrame frame = new SpriterKeyFrame();
frame.setTime(mainlineKey.getTime());
frame.setId(mainlineKey.getId());
for(BoneRef boneRef : mainlineKey.getBoneRef()){
TimeLine timeline = timeLines.get(boneRef.getTimeline());
Key timelineKey = timeline.getKey().get(boneRef.getKey());
SpriterBone bone = boneMerger.merge(boneRef, timelineKey);
bone.setName(timeline.getName());
if(mainlineKey.getTime() != timelineKey.getTime()) bonesToTween.put(bone, k);
else tempBones.add(bone);
/*if(key.getTime() == timeLines.get(boneRef.getTimeline()).getKey().get(boneRef.getKey()).getTime()){
if(bone.hasParent()){
SpriterBone parent = null;
for(int i = 0; i< spriterAnimation.frames() && parent == null; i++){
parent = this.searchForParentBone(spriterAnimation.frames.get(i), bone.getParentId());
bone.setParent(parent);
}
}*/
//}
}
for(AnimationObjectRef objectRef : mainlineKey.getObjectRef()){
TimeLine timeline = timeLines.get(objectRef.getTimeline());
Key timelineKey = timeline.getKey().get(objectRef.getKey());
SpriterObject object = objectMerger.merge(objectRef, timelineKey);
object.setName(timeline.getName());
if(mainlineKey.getTime() != timelineKey.getTime()) objectsToTween.put(object, k);
else tempObjects.add(object);
/*if(key.getTime() == timeLines.get(objectRef.getTimeline()).getKey().get(objectRef.getKey()).getTime()){
if(object.hasParent()){
SpriterBone parent = null;
for(int i = 0; i< spriterAnimation.frames() && parent == null; i++){
parent = this.searchForParentBone(spriterAnimation.frames.get(i), object.getParentId());
object.setParent(parent);
}
}*/
//}
}
/*for(AnimationObject object : key.getObject()){
tempObjects.add(objectConverter.convert(object));
}*/
frame.setObjects(tempObjects.toArray(new SpriterObject[tempObjects.size()]));
frame.setBones(tempBones.toArray(new SpriterBone[tempBones.size()]));
spriterAnimation.frames.add(frame);
}
this.tweenBones(spriterAnimation);
this.tweenObjects(spriterAnimation);
return spriterAnimation;
}
public void tweenBones(SpriterAnimation animation){
for(Entry<SpriterBone, Integer> entry: bonesToTween.entrySet()){
SpriterBone toTween = entry.getKey();
SpriterKeyFrame frame = animation.frames.get(entry.getValue());
long time = frame.getTime();
SpriterKeyFrame currentFrame = animation.getPreviousFrameForBone(toTween, time);
SpriterKeyFrame nextFrame = animation.getNextFrameFor(toTween, currentFrame, 1);
if(nextFrame != currentFrame){
SpriterBone bone1 = currentFrame.getBoneFor(toTween), bone2 = nextFrame.getBoneFor(toTween);
this.interpolateAbstractObject(toTween, bone1, bone2, currentFrame.getTime(), nextFrame.getTime(), time);
}
SpriterBone[] bones = new SpriterBone[frame.getBones().length+1];
for(int i = 0; i < bones.length-1; i++)
bones[i] = frame.getBones()[i];
bones[bones.length-1] = toTween;
frame.setBones(bones);
}
}
public void tweenObjects(SpriterAnimation animation){
for(Entry<SpriterObject, Integer> entry: objectsToTween.entrySet()){
SpriterObject toTween = entry.getKey();
SpriterKeyFrame frame = animation.frames.get(entry.getValue());
long time = frame.getTime();
SpriterKeyFrame currentFrame = animation.getPreviousFrameForObject(toTween, time);
SpriterKeyFrame nextFrame = animation.getNextFrameFor(toTween, currentFrame, 1);
if(nextFrame != currentFrame){
SpriterObject object1 = currentFrame.getObjectFor(toTween), object2 = nextFrame.getObjectFor(toTween);
this.interpolateSpriterObject(toTween, object1, object2, currentFrame.getTime(), nextFrame.getTime(), time);
}
SpriterObject[] objects = new SpriterObject[frame.getObjects().length+1];
for(int i = 0; i < objects.length-1; i++)
objects[i] = frame.getObjects()[i];
objects[objects.length-1] = toTween;
frame.setObjects(objects);
}
}
private void interpolateAbstractObject(SpriterAbstractObject target, SpriterAbstractObject obj1, SpriterAbstractObject obj2, float startTime, float endTime, float frame){
if(obj2 == null) return;
target.setX(this.interpolate(obj1.getX(), obj2.getX(), startTime, endTime, frame));
target.setY(this.interpolate(obj1.getY(), obj2.getY(), startTime, endTime, frame));
target.setScaleX(this.interpolate(obj1.getScaleX(), obj2.getScaleX(), startTime, endTime, frame));
target.setScaleY(this.interpolate(obj1.getScaleY(), obj2.getScaleY(), startTime, endTime, frame));
target.setAngle(this.interpolateAngle(obj1.getAngle(), obj2.getAngle(), startTime, endTime, frame));
}
private void interpolateSpriterObject(SpriterObject target, SpriterObject obj1, SpriterObject obj2, float startTime, float endTime, float frame){
if(obj2 == null) return;
this.interpolateAbstractObject(target, obj1, obj2, startTime, endTime, frame);
target.setPivotX(this.interpolate(obj1.getPivotX(), obj2.getPivotX(), startTime, endTime, frame));
target.setPivotY(this.interpolate(obj1.getPivotY(), obj2.getPivotY(), startTime, endTime, frame));
target.setAlpha(this.interpolateAngle(obj1.getAlpha(), obj2.getAlpha(), startTime, endTime, frame));
}
/**
* See {@link SpriterCalculator#calculateInterpolation(float, float, float, float, long)}
* Can be inherited, to handle other interpolation techniques. Standard is linear interpolation.
*/
protected float interpolate(float a, float b, float timeA, float timeB, float currentTime){
return SpriterLinearInterpolator.interpolator.interpolate(a, b, timeA, timeB, currentTime);
}
/**
* See {@link SpriterCalculator#calculateInterpolation(float, float, float, float, long)}
* Can be inherited, to handle other interpolation techniques. Standard is linear interpolation.
*/
protected float interpolateAngle(float a, float b, float timeA, float timeB, float currentTime){
return SpriterLinearInterpolator.interpolator.interpolateAngle(a, b, timeA, timeB, currentTime);
}
/*private SpriterBone searchForParentBone(SpriterKeyFrame frame, Integer parentId){
if(frame == null) return null;
for(SpriterBone bone: frame.getBones())
if(bone.getParentId().equals(parentId)) return bone;
return null;
}*/
}