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