Home | History | Annotate | Download | only in particles
      1 package com.badlogic.gdx.graphics.g3d.particles;
      2 
      3 import com.badlogic.gdx.graphics.Camera;
      4 import com.badlogic.gdx.graphics.g3d.particles.renderers.ParticleControllerRenderData;
      5 import com.badlogic.gdx.math.Matrix4;
      6 import com.badlogic.gdx.math.Vector3;
      7 import com.badlogic.gdx.utils.Array;
      8 
      9 /** This class is used by particle batches to sort the particles before rendering.
     10  * @author Inferno */
     11 public abstract class ParticleSorter {
     12 	static final Vector3 TMP_V1 = new Vector3();
     13 
     14 	/** Using this class will not apply sorting */
     15 	public static class None extends ParticleSorter{
     16 		int currentCapacity = 0;
     17 		int[] indices;
     18 
     19 		@Override
     20 		public void ensureCapacity (int capacity) {
     21 			if(currentCapacity < capacity){
     22 				indices = new int[capacity];
     23 				for(int i=0; i < capacity; ++i)
     24 					indices[i] = i;
     25 				currentCapacity = capacity;
     26 			}
     27 		}
     28 
     29 		@Override
     30 		public  <T extends ParticleControllerRenderData> int[] sort(Array<T> renderData){
     31 			return indices;
     32 		}
     33 	}
     34 
     35 	/** This class will sort all the particles using the distance from camera. */
     36 	public static class Distance extends ParticleSorter{
     37 		private float[] distances;
     38 		private int[] particleIndices, particleOffsets;
     39 		private int currentSize = 0;
     40 
     41 		@Override
     42 		public void ensureCapacity (int capacity) {
     43 			if(currentSize < capacity){
     44 				distances = new float[capacity];
     45 				particleIndices = new int[capacity];
     46 				particleOffsets = new int[capacity];
     47 				currentSize = capacity;
     48 			}
     49 		}
     50 
     51 		@Override
     52 		public  <T extends ParticleControllerRenderData> int[] sort(Array<T> renderData){
     53 			float[] val = camera.view.val;
     54 			float cx = val[Matrix4.M20], cy = val[Matrix4.M21], cz = val[Matrix4.M22];
     55 			int count = 0, i = 0;
     56 			for(ParticleControllerRenderData data : renderData){
     57 				for(int k=0, c = i+data.controller.particles.size; i <c; ++i, k+=data.positionChannel.strideSize){
     58 					distances[i] = cx*data.positionChannel.data[k+ParticleChannels.XOffset] + cy*data.positionChannel.data[k+ParticleChannels.YOffset] + cz*data.positionChannel.data[k+ParticleChannels.ZOffset];
     59 					particleIndices[i] = i;
     60 				}
     61 				count += data.controller.particles.size;
     62 			}
     63 
     64 			qsort(0, count-1);
     65 
     66 			for(i=0; i < count; ++i){
     67 				particleOffsets[particleIndices[i]] = i;
     68 			}
     69 			return particleOffsets;
     70 		}
     71 
     72 		public void qsort( int si, int ei){
     73 			//base case
     74 			if(si< ei){
     75 				float tmp;
     76 				int 	tmpIndex, particlesPivotIndex;
     77 				//insertion
     78 				if (ei-si <= 8) {
     79 					for (int i=si; i <= ei; i++)
     80 						for (int j=i; j > si && distances[j-1]>distances[j]; j--){
     81 				           tmp = distances[j];
     82 				           distances[j] = distances[j-1];
     83 				           distances[j-1] = tmp;
     84 
     85 				           //Swap indices
     86 				           tmpIndex = particleIndices[j];
     87 				           particleIndices[j] = particleIndices[j-1];
     88 				           particleIndices[j-1] = tmpIndex;
     89 						}
     90 					return;
     91 				}
     92 
     93 				//Quick
     94 				float pivot = distances[si];
     95 				int i = si+1;
     96 				particlesPivotIndex = particleIndices[si];
     97 
     98 				//partition array
     99 				for(int j = si+1; j<= ei; j++){
    100 					if(pivot  > distances[j]){
    101 						if(j>i){
    102 							//Swap distances
    103 							tmp = distances[j];
    104 							distances[j] = distances[i];
    105 							distances[i] = tmp;
    106 
    107 							//Swap indices
    108 							tmpIndex = particleIndices[j];
    109 							particleIndices[j] = particleIndices[i];
    110 							particleIndices[i] = tmpIndex;
    111 						}
    112 						i++;
    113 					}
    114 				}
    115 
    116 				//put pivot in right position
    117 				distances[si] = distances[i-1];
    118 				distances[i-1] = pivot;
    119 				particleIndices[si] = particleIndices[i-1];
    120 				particleIndices[i-1] = particlesPivotIndex;
    121 
    122 				//call qsort on right and left sides of pivot
    123 				qsort(si, i-2);
    124 				qsort(i, ei);
    125 			}
    126 		}
    127 	}
    128 
    129 	protected Camera camera;
    130 
    131 	/**@return an array of offsets where each particle should be put in the resulting mesh
    132 	 * (also if more than one mesh will be generated, this is an absolute offset considering a BIG output array). */
    133 	public abstract <T extends ParticleControllerRenderData> int[] sort(Array<T> renderData);
    134 
    135 	public void setCamera(Camera camera){
    136 		this.camera = camera;
    137 	}
    138 	/** This method is called when the batch has increased the underlying particle buffer.
    139 	 * In this way the sorter can increase the data structures used to sort the particles (i.e increase backing array size) */
    140 	public void ensureCapacity (int capacity) {}
    141 }
    142