Home | History | Annotate | Download | only in animation
      1 /*
      2  * Copyright (c) 2009-2010 jMonkeyEngine
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are
      7  * met:
      8  *
      9  * * Redistributions of source code must retain the above copyright
     10  *   notice, this list of conditions and the following disclaimer.
     11  *
     12  * * Redistributions in binary form must reproduce the above copyright
     13  *   notice, this list of conditions and the following disclaimer in the
     14  *   documentation and/or other materials provided with the distribution.
     15  *
     16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
     17  *   may be used to endorse or promote products derived from this software
     18  *   without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 package com.jme3.animation;
     33 
     34 import java.lang.reflect.Array;
     35 import java.util.HashMap;
     36 import java.util.Map;
     37 
     38 /**
     39  * Object is indexed and stored in primitive float[]
     40  * @author Lim, YongHoon
     41  * @param <T>
     42  */
     43 public abstract class CompactArray<T> {
     44 
     45     private Map<T, Integer> indexPool = new HashMap<T, Integer>();
     46     protected int[] index;
     47     protected float[] array;
     48     private boolean invalid;
     49 
     50     /**
     51      * Creates a compact array
     52      */
     53     public CompactArray() {
     54     }
     55 
     56     /**
     57      * create array using serialized data
     58      * @param compressedArray
     59      * @param index
     60      */
     61     public CompactArray(float[] compressedArray, int[] index) {
     62         this.array = compressedArray;
     63         this.index = index;
     64     }
     65 
     66     /**
     67      * Add objects.
     68      * They are serialized automatically when get() method is called.
     69      * @param objArray
     70      */
     71     public void add(T... objArray) {
     72         if (objArray == null || objArray.length == 0) {
     73             return;
     74         }
     75         invalid = true;
     76         int base = 0;
     77         if (index == null) {
     78             index = new int[objArray.length];
     79         } else {
     80             if (indexPool.isEmpty()) {
     81                 throw new RuntimeException("Internal is already fixed");
     82             }
     83             base = index.length;
     84 
     85             int[] tmp = new int[base + objArray.length];
     86             System.arraycopy(index, 0, tmp, 0, index.length);
     87             index = tmp;
     88             //index = Arrays.copyOf(index, base+objArray.length);
     89         }
     90         for (int j = 0; j < objArray.length; j++) {
     91             T obj = objArray[j];
     92             if (obj == null) {
     93                 index[base + j] = -1;
     94             } else {
     95                 Integer i = indexPool.get(obj);
     96                 if (i == null) {
     97                     i = indexPool.size();
     98                     indexPool.put(obj, i);
     99                 }
    100                 index[base + j] = i;
    101             }
    102         }
    103     }
    104 
    105     /**
    106      * release objects.
    107      * add() method call is not allowed anymore.
    108      */
    109     public void freeze() {
    110         serialize();
    111         indexPool.clear();
    112     }
    113 
    114     /**
    115      * @param index
    116      * @param value
    117      */
    118     public final void set(int index, T value) {
    119         int j = getCompactIndex(index);
    120         serialize(j, value);
    121     }
    122 
    123     /**
    124      * returns the object for the given index
    125      * @param index the index
    126      * @param store an object to store the result
    127      * @return
    128      */
    129     public final T get(int index, T store) {
    130         serialize();
    131         int j = getCompactIndex(index);
    132         return deserialize(j, store);
    133     }
    134 
    135     /**
    136      * return a float array of serialized data
    137      * @return
    138      */
    139     public final float[] getSerializedData() {
    140         serialize();
    141         return array;
    142     }
    143 
    144     /**
    145      * serialize this compact array
    146      */
    147     public final void serialize() {
    148         if (invalid) {
    149             int newSize = indexPool.size() * getTupleSize();
    150             if (array == null || Array.getLength(array) < newSize) {
    151                 array = ensureCapacity(array, newSize);
    152                 for (Map.Entry<T, Integer> entry : indexPool.entrySet()) {
    153                     int i = entry.getValue();
    154                     T obj = entry.getKey();
    155                     serialize(i, obj);
    156                 }
    157             }
    158             invalid = false;
    159         }
    160     }
    161 
    162     /**
    163      * @return compacted array's primitive size
    164      */
    165     protected final int getSerializedSize() {
    166         return Array.getLength(getSerializedData());
    167     }
    168 
    169     /**
    170      * Ensure the capacity for the given array and the given size
    171      * @param arr the array
    172      * @param size the size
    173      * @return
    174      */
    175     protected float[] ensureCapacity(float[] arr, int size) {
    176         if (arr == null) {
    177             return new float[size];
    178         } else if (arr.length >= size) {
    179             return arr;
    180         } else {
    181             float[] tmp = new float[size];
    182             System.arraycopy(arr, 0, tmp, 0, arr.length);
    183             return tmp;
    184             //return Arrays.copyOf(arr, size);
    185         }
    186     }
    187 
    188     /**
    189      * retrun an array of indices for the given objects
    190      * @param objArray
    191      * @return
    192      */
    193     public final int[] getIndex(T... objArray) {
    194         int[] index = new int[objArray.length];
    195         for (int i = 0; i < index.length; i++) {
    196             T obj = objArray[i];
    197             index[i] = obj != null ? indexPool.get(obj) : -1;
    198         }
    199         return index;
    200     }
    201 
    202     /**
    203      * returns the corresponding index in the compact array
    204      * @param objIndex
    205      * @return object index in the compacted object array
    206      */
    207     public int getCompactIndex(int objIndex) {
    208         return index != null ? index[objIndex] : objIndex;
    209     }
    210 
    211     /**
    212      * @return uncompressed object size
    213      */
    214     public final int getTotalObjectSize() {
    215         assert getSerializedSize() % getTupleSize() == 0;
    216         return index != null ? index.length : getSerializedSize() / getTupleSize();
    217     }
    218 
    219     /**
    220      * @return compressed object size
    221      */
    222     public final int getCompactObjectSize() {
    223         assert getSerializedSize() % getTupleSize() == 0;
    224         return getSerializedSize() / getTupleSize();
    225     }
    226 
    227     /**
    228      * decompress and return object array
    229      * @return decompress and return object array
    230      */
    231     public final T[] toObjectArray() {
    232         try {
    233             T[] compactArr = (T[]) Array.newInstance(getElementClass(), getSerializedSize() / getTupleSize());
    234             for (int i = 0; i < compactArr.length; i++) {
    235                 compactArr[i] = getElementClass().newInstance();
    236                 deserialize(i, compactArr[i]);
    237             }
    238 
    239             T[] objArr = (T[]) Array.newInstance(getElementClass(), getTotalObjectSize());
    240             for (int i = 0; i < objArr.length; i++) {
    241                 int compactIndex = getCompactIndex(i);
    242                 objArr[i] = compactArr[compactIndex];
    243             }
    244             return objArr;
    245         } catch (Exception e) {
    246             return null;
    247         }
    248     }
    249 
    250     /**
    251      * serialize object
    252      * @param compactIndex compacted object index
    253      * @param store
    254      */
    255     protected abstract void serialize(int compactIndex, T store);
    256 
    257     /**
    258      * deserialize object
    259      * @param compactIndex compacted object index
    260      * @param store
    261      */
    262     protected abstract T deserialize(int compactIndex, T store);
    263 
    264     /**
    265      * serialized size of one object element
    266      */
    267     protected abstract int getTupleSize();
    268 
    269     protected abstract Class<T> getElementClass();
    270 }
    271