Home | History | Annotate | Download | only in particles
      1 package com.badlogic.gdx.graphics.g3d.particles;
      2 
      3 import java.util.Arrays;
      4 
      5 import com.badlogic.gdx.utils.Array;
      6 import com.badlogic.gdx.utils.GdxRuntimeException;
      7 import com.badlogic.gdx.utils.reflect.ArrayReflection;
      8 
      9 /** This class represents an group of elements like an array, but the properties of the elements are stored as separate arrays.
     10  *  These arrays are called {@link Channel} and are represented by {@link ChannelDescriptor}.
     11  *  It's not necessary to store primitive types in the channels but doing so will "exploit" data locality
     12  *  in the JVM, which is ensured for primitive types.
     13  *  Use {@link FloatChannel}, {@link IntChannel}, {@link ObjectChannel} to store the data.
     14  *  @author inferno */
     15 public class ParallelArray {
     16 
     17 	/** This class describes the content of a {@link Channel}*/
     18 	public static class ChannelDescriptor{
     19 		public int id;
     20 		public Class<?> type;
     21 		public int count;
     22 		public ChannelDescriptor(int id, Class<?> type, int count){
     23 			this.id = id;
     24 			this.type = type;
     25 			this.count = count;
     26 		}
     27 	}
     28 
     29 	/** This class represents a container of values for all the elements for a given property*/
     30 	public abstract class Channel{
     31 		public int id;
     32 		public Object data;
     33 		public int strideSize;
     34 		public Channel(int id, Object data, int strideSize){
     35 			this.id = id;
     36 			this.strideSize = strideSize;
     37 			this.data = data;
     38 		}
     39 		public abstract void add(int index, Object...objects);
     40 		public abstract void swap(int i, int k);
     41 		protected abstract void setCapacity (int requiredCapacity);
     42 	}
     43 
     44 	/** This interface is used to provide custom initialization of the {@link Channel} data */
     45 	public static interface ChannelInitializer<T extends Channel>{
     46 		public void init(T channel);
     47 	}
     48 
     49 	public class FloatChannel extends Channel{
     50 		public float[] data;
     51 		public FloatChannel (int id, int strideSize, int size) {
     52 			super(id, new float[size*strideSize], strideSize);
     53 			this.data = (float[])super.data;
     54 		}
     55 
     56 		@Override
     57 		public void add (int index, Object...objects) {
     58 			for(int i=strideSize*size, c = i+strideSize, k=0; i < c; ++i, ++k){
     59 				data[i] = (Float)objects[k];
     60 			}
     61 		}
     62 
     63 		@Override
     64 		public void swap (int i, int k) {
     65 			float t;
     66 			i=strideSize*i;
     67 			k =strideSize*k;
     68 			for(int c = i+strideSize; i < c; ++i, ++k){
     69 				t = data[i];
     70 				data[i] = data[k];
     71 				data[k] = t;
     72 			}
     73 		}
     74 
     75 		@Override
     76 		public void setCapacity (int requiredCapacity) {
     77 			float[] newData = new float[strideSize * requiredCapacity];
     78 			System.arraycopy(data, 0, newData, 0, Math.min(data.length, newData.length));
     79 			super.data = data = newData;
     80 		}
     81 	}
     82 
     83 	public class IntChannel extends Channel{
     84 		public int[] data;
     85 		public IntChannel (int id, int strideSize, int size) {
     86 			super(id, new int[size*strideSize], strideSize);
     87 			this.data = (int[])super.data;
     88 		}
     89 
     90 		@Override
     91 		public void add (int index, Object...objects) {
     92 			for(int i=strideSize*size, c = i+strideSize, k=0; i < c; ++i, ++k){
     93 				data[i] = (Integer)objects[k];
     94 			}
     95 		}
     96 
     97 		@Override
     98 		public void swap (int i, int k) {
     99 			int t;
    100 			i=strideSize*i;
    101 			k =strideSize*k;
    102 			for(int c = i+strideSize; i < c; ++i, ++k){
    103 				t = data[i];
    104 				data[i] = data[k];
    105 				data[k] = t;
    106 			}
    107 		}
    108 
    109 		@Override
    110 		public void setCapacity (int requiredCapacity) {
    111 			int[] newData = new int[strideSize * requiredCapacity];
    112 			System.arraycopy(data, 0, newData, 0, Math.min(data.length, newData.length));
    113 			super.data = data = newData;
    114 		}
    115 	}
    116 
    117 	@SuppressWarnings("unchecked")
    118 	public class ObjectChannel<T> extends Channel{
    119 		Class<T> componentType;
    120 		public T[] data;
    121 		public ObjectChannel (int id, int strideSize, int size, Class<T> type) {
    122 			super(id, ArrayReflection.newInstance(type, size*strideSize), strideSize);
    123 			componentType = type;
    124 			this.data = (T[]) super.data;
    125 		}
    126 
    127 		@Override
    128 		public void add (int index, Object...objects) {
    129 			for(int i=strideSize*size, c = i+strideSize, k=0; i < c; ++i, ++k){
    130 				this.data[i] = (T) objects[k];
    131 			}
    132 		}
    133 
    134 		@Override
    135 		public void swap (int i, int k) {
    136 			T t;
    137 			i=strideSize*i;
    138 			k =strideSize*k;
    139 			for(int c = i+strideSize; i < c; ++i, ++k){
    140 				t = data[i];
    141 				data[i] = data[k];
    142 				data[k] = t;
    143 			}
    144 		}
    145 
    146 		@Override
    147 		public void setCapacity (int requiredCapacity) {
    148 			T[] newData = (T[]) ArrayReflection.newInstance(componentType, strideSize * requiredCapacity);
    149 			System.arraycopy(data, 0, newData, 0, Math.min(data.length, newData.length));
    150 			super.data = data = newData;
    151 		}
    152 	}
    153 
    154 	/**the channels added to the array*/
    155 	Array<Channel> arrays;
    156 	/** the maximum amount of elements that this array can hold */
    157 	public int capacity;
    158 	/** the current amount of defined elements, do not change manually unless you know what you are doing.*/
    159 	public int size;
    160 
    161 	public ParallelArray(int capacity){
    162 		arrays = new Array<Channel>(false, 2,  Channel.class);
    163 		this.capacity = capacity;
    164 		size = 0;
    165 	}
    166 
    167 	/** Adds and returns a channel described by the channel descriptor parameter.
    168 	 *  If a channel with the same id already exists, no allocation is performed and that channel is returned. */
    169 	public <T extends Channel> T addChannel(ChannelDescriptor channelDescriptor){
    170 		return addChannel(channelDescriptor, null);
    171 	}
    172 
    173 	/** Adds and returns a channel described by the channel descriptor parameter.
    174 	 *  If a channel with the same id already exists, no allocation is performed and that channel is returned.
    175 	 *  Otherwise a new channel is allocated and initialized with the initializer. */
    176 	public <T extends Channel> T addChannel(ChannelDescriptor channelDescriptor, ChannelInitializer<T> initializer){
    177 		T channel = getChannel(channelDescriptor);
    178 		if(channel == null){
    179 			channel = allocateChannel(channelDescriptor);
    180 			if(initializer != null)
    181 				initializer.init(channel);
    182 			arrays.add(channel);
    183 		}
    184 		return channel;
    185 	}
    186 
    187 	@SuppressWarnings({"unchecked", "rawtypes"})
    188 	private <T extends Channel> T allocateChannel(ChannelDescriptor channelDescriptor){
    189 		if(channelDescriptor.type == float.class){
    190 			return (T)new FloatChannel(channelDescriptor.id, channelDescriptor.count, capacity);
    191 		}
    192 		else if(channelDescriptor.type == int.class){
    193 			return (T)new IntChannel(channelDescriptor.id, channelDescriptor.count, capacity);
    194 		}
    195 		else {
    196 			return (T)new ObjectChannel(channelDescriptor.id, channelDescriptor.count, capacity, channelDescriptor.type);
    197 		}
    198 	}
    199 
    200 	/**Removes the channel with the given id*/
    201 	public <T> void removeArray(int id){
    202 		arrays.removeIndex(findIndex(id));
    203 	}
    204 
    205 	private int findIndex (int id) {
    206 		for(int i=0; i < arrays.size;++i){
    207 			Channel array = arrays.items[i];
    208 			if(array.id == id)
    209 				return i;
    210 		}
    211 		return -1;
    212 	}
    213 
    214 	/**Adds an element considering the values in the same order as the current channels in the array.
    215 	 * The n_th value  must have the same type and stride of the given channel at position n*/
    216 	public void addElement(Object...values){
    217 		/*FIXME make it grow...*/
    218 		if(size == capacity)
    219 			throw new GdxRuntimeException("Capacity reached, cannot add other elements");
    220 
    221 		int k=0;
    222 		for(Channel strideArray : arrays){
    223 			strideArray.add(k, values);
    224 			k+= strideArray.strideSize;
    225 		}
    226 		++size;
    227 	}
    228 
    229 	/**Removes the element at the given index and swaps it with the last available element */
    230 	public void removeElement(int index){
    231 		int last = size -1;
    232 		//Swap
    233 		for(Channel strideArray : arrays){
    234 			strideArray.swap(index, last);
    235 		}
    236 		size = last;
    237 	}
    238 
    239 	/**@return the channel with the same id as the one in the descriptor */
    240 	@SuppressWarnings("unchecked")
    241 	public <T extends Channel> T getChannel (ChannelDescriptor descriptor) {
    242 		for(Channel array : arrays){
    243 			if(array.id == descriptor.id)
    244 				return (T) array;
    245 		}
    246 		return null;
    247 	}
    248 
    249 	/** Removes all the channels and sets size to 0 */
    250 	public void clear () {
    251 		arrays.clear();
    252 		size = 0;
    253 	}
    254 
    255 	/** Sets the capacity.
    256 	 * Each contained channel will be resized to match the required capacity and the current data will be preserved. */
    257 	public void setCapacity (int requiredCapacity) {
    258 		if(capacity != requiredCapacity){
    259 			for(Channel channel : arrays){
    260 				channel.setCapacity(requiredCapacity);
    261 			}
    262 			capacity = requiredCapacity;
    263 		}
    264 	}
    265 
    266 }
    267