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