Home | History | Annotate | Download | only in animation
      1 package com.jme3.animation;
      2 
      3 import com.jme3.export.InputCapsule;
      4 import com.jme3.export.JmeExporter;
      5 import com.jme3.export.JmeImporter;
      6 import com.jme3.export.OutputCapsule;
      7 import com.jme3.math.Quaternion;
      8 import com.jme3.math.Vector3f;
      9 import com.jme3.scene.Spatial;
     10 import com.jme3.util.TempVars;
     11 import java.io.IOException;
     12 import java.util.Arrays;
     13 
     14 /**
     15  * This class represents the track for spatial animation.
     16  *
     17  * @author Marcin Roguski (Kaelthas)
     18  */
     19 public class SpatialTrack implements Track {
     20 
     21     /**
     22      * Translations of the track.
     23      */
     24     private CompactVector3Array translations;
     25 
     26     /**
     27      * Rotations of the track.
     28      */
     29     private CompactQuaternionArray rotations;
     30 
     31     /**
     32      * Scales of the track.
     33      */
     34     private CompactVector3Array scales;
     35 
     36     /**
     37      * The times of the animations frames.
     38      */
     39     private float[] times;
     40 
     41     public SpatialTrack() {
     42     }
     43 
     44     /**
     45      * Creates a spatial track for the given track data.
     46      *
     47      * @param times
     48      *            a float array with the time of each frame
     49      * @param translations
     50      *            the translation of the bone for each frame
     51      * @param rotations
     52      *            the rotation of the bone for each frame
     53      * @param scales
     54      *            the scale of the bone for each frame
     55      */
     56     public SpatialTrack(float[] times, Vector3f[] translations,
     57                         Quaternion[] rotations, Vector3f[] scales) {
     58         setKeyframes(times, translations, rotations, scales);
     59     }
     60 
     61     /**
     62      *
     63      * Modify the spatial which this track modifies.
     64      *
     65      * @param time
     66      *            the current time of the animation
     67      */
     68     public void setTime(float time, float weight, AnimControl control, AnimChannel channel, TempVars vars) {
     69         Spatial spatial = control.getSpatial();
     70 
     71         Vector3f tempV = vars.vect1;
     72         Vector3f tempS = vars.vect2;
     73         Quaternion tempQ = vars.quat1;
     74         Vector3f tempV2 = vars.vect3;
     75         Vector3f tempS2 = vars.vect4;
     76         Quaternion tempQ2 = vars.quat2;
     77 
     78         int lastFrame = times.length - 1;
     79         if (time < 0 || lastFrame == 0) {
     80             if (rotations != null)
     81                 rotations.get(0, tempQ);
     82             if (translations != null)
     83                 translations.get(0, tempV);
     84             if (scales != null) {
     85                 scales.get(0, tempS);
     86             }
     87         } else if (time >= times[lastFrame]) {
     88             if (rotations != null)
     89                 rotations.get(lastFrame, tempQ);
     90             if (translations != null)
     91                 translations.get(lastFrame, tempV);
     92             if (scales != null) {
     93                 scales.get(lastFrame, tempS);
     94             }
     95         } else {
     96             int startFrame = 0;
     97             int endFrame = 1;
     98             // use lastFrame so we never overflow the array
     99             for (int i = 0; i < lastFrame && times[i] < time; ++i) {
    100                 startFrame = i;
    101                 endFrame = i + 1;
    102             }
    103 
    104             float blend = (time - times[startFrame]) / (times[endFrame] - times[startFrame]);
    105 
    106             if (rotations != null)
    107                 rotations.get(startFrame, tempQ);
    108             if (translations != null)
    109                 translations.get(startFrame, tempV);
    110             if (scales != null) {
    111                 scales.get(startFrame, tempS);
    112             }
    113             if (rotations != null)
    114                 rotations.get(endFrame, tempQ2);
    115             if (translations != null)
    116                 translations.get(endFrame, tempV2);
    117             if (scales != null) {
    118                 scales.get(endFrame, tempS2);
    119             }
    120             tempQ.nlerp(tempQ2, blend);
    121             tempV.interpolate(tempV2, blend);
    122             tempS.interpolate(tempS2, blend);
    123         }
    124 
    125         if (translations != null)
    126             spatial.setLocalTranslation(tempV);
    127         if (rotations != null)
    128             spatial.setLocalRotation(tempQ);
    129         if (scales != null) {
    130             spatial.setLocalScale(tempS);
    131         }
    132     }
    133 
    134     /**
    135      * Set the translations, rotations and scales for this track.
    136      *
    137      * @param times
    138      *            a float array with the time of each frame
    139      * @param translations
    140      *            the translation of the bone for each frame
    141      * @param rotations
    142      *            the rotation of the bone for each frame
    143      * @param scales
    144      *            the scale of the bone for each frame
    145      */
    146     public void setKeyframes(float[] times, Vector3f[] translations,
    147                              Quaternion[] rotations, Vector3f[] scales) {
    148         if (times.length == 0) {
    149             throw new RuntimeException("BoneTrack with no keyframes!");
    150         }
    151 
    152         this.times = times;
    153         if (translations != null) {
    154             assert times.length == translations.length;
    155             this.translations = new CompactVector3Array();
    156             this.translations.add(translations);
    157             this.translations.freeze();
    158         }
    159         if (rotations != null) {
    160             assert times.length == rotations.length;
    161             this.rotations = new CompactQuaternionArray();
    162             this.rotations.add(rotations);
    163             this.rotations.freeze();
    164         }
    165         if (scales != null) {
    166             assert times.length == scales.length;
    167             this.scales = new CompactVector3Array();
    168             this.scales.add(scales);
    169             this.scales.freeze();
    170         }
    171     }
    172 
    173     /**
    174      * @return the array of rotations of this track
    175      */
    176     public Quaternion[] getRotations() {
    177             return rotations == null ? null : rotations.toObjectArray();
    178     }
    179 
    180     /**
    181      * @return the array of scales for this track
    182      */
    183     public Vector3f[] getScales() {
    184             return scales == null ? null : scales.toObjectArray();
    185     }
    186 
    187     /**
    188      * @return the arrays of time for this track
    189      */
    190     public float[] getTimes() {
    191             return times;
    192     }
    193 
    194     /**
    195      * @return the array of translations of this track
    196      */
    197     public Vector3f[] getTranslations() {
    198             return translations == null ? null : translations.toObjectArray();
    199     }
    200 
    201     /**
    202      * @return the length of the track
    203      */
    204     public float getLength() {
    205             return times == null ? 0 : times[times.length - 1] - times[0];
    206     }
    207 
    208     /**
    209      * This method creates a clone of the current object.
    210      * @return a clone of the current object
    211      */
    212     @Override
    213     public SpatialTrack clone() {
    214         int tablesLength = times.length;
    215 
    216         float[] timesCopy = this.times.clone();
    217         Vector3f[] translationsCopy = this.getTranslations() == null ? null : Arrays.copyOf(this.getTranslations(), tablesLength);
    218         Quaternion[] rotationsCopy = this.getRotations() == null ? null : Arrays.copyOf(this.getRotations(), tablesLength);
    219         Vector3f[] scalesCopy = this.getScales() == null ? null : Arrays.copyOf(this.getScales(), tablesLength);
    220 
    221         //need to use the constructor here because of the final fields used in this class
    222         return new SpatialTrack(timesCopy, translationsCopy, rotationsCopy, scalesCopy);
    223     }
    224 
    225     @Override
    226     public void write(JmeExporter ex) throws IOException {
    227         OutputCapsule oc = ex.getCapsule(this);
    228         oc.write(translations, "translations", null);
    229         oc.write(rotations, "rotations", null);
    230         oc.write(times, "times", null);
    231         oc.write(scales, "scales", null);
    232     }
    233 
    234     @Override
    235     public void read(JmeImporter im) throws IOException {
    236         InputCapsule ic = im.getCapsule(this);
    237         translations = (CompactVector3Array) ic.readSavable("translations", null);
    238         rotations = (CompactQuaternionArray) ic.readSavable("rotations", null);
    239         times = ic.readFloatArray("times", null);
    240         scales = (CompactVector3Array) ic.readSavable("scales", null);
    241     }
    242 }
    243