1 package com.badlogic.gdx.graphics.g3d.particles.influencers; 2 3 import com.badlogic.gdx.graphics.Texture; 4 import com.badlogic.gdx.graphics.g2d.TextureRegion; 5 import com.badlogic.gdx.graphics.g3d.particles.ParallelArray.FloatChannel; 6 import com.badlogic.gdx.graphics.g3d.particles.ParticleChannels; 7 import com.badlogic.gdx.utils.Array; 8 import com.badlogic.gdx.utils.Json; 9 import com.badlogic.gdx.utils.JsonValue; 10 11 /** It's an {@link Influencer} which assigns a region of a {@link Texture} to the particles. 12 * @author Inferno */ 13 public abstract class RegionInfluencer extends Influencer { 14 15 /** Assigns the first region of {@link RegionInfluencer#regions} to the particles.*/ 16 public static class Single extends RegionInfluencer{ 17 public Single(){} 18 19 public Single (Single regionInfluencer) { 20 super(regionInfluencer); 21 } 22 23 public Single (TextureRegion textureRegion) { 24 super(textureRegion); 25 } 26 27 public Single (Texture texture) { 28 super(texture); 29 } 30 31 @Override 32 public void init () { 33 AspectTextureRegion region = regions.items[0]; 34 for(int i=0, c = controller.emitter.maxParticleCount*regionChannel.strideSize; 35 i < c; 36 i +=regionChannel.strideSize){ 37 regionChannel.data[i +ParticleChannels.UOffset] = region.u; 38 regionChannel.data[i +ParticleChannels.VOffset] = region.v; 39 regionChannel.data[i +ParticleChannels.U2Offset] = region.u2; 40 regionChannel.data[i +ParticleChannels.V2Offset] = region.v2; 41 regionChannel.data[i +ParticleChannels.HalfWidthOffset] = 0.5f; 42 regionChannel.data[i +ParticleChannels.HalfHeightOffset] = region.halfInvAspectRatio; 43 } 44 } 45 46 @Override 47 public Single copy () { 48 return new Single(this); 49 } 50 } 51 52 /** Assigns a random region of {@link RegionInfluencer#regions} to the particles.*/ 53 public static class Random extends RegionInfluencer{ 54 public Random(){} 55 public Random (Random regionInfluencer) { 56 super(regionInfluencer); 57 } 58 public Random (TextureRegion textureRegion) { 59 super(textureRegion); 60 } 61 62 public Random (Texture texture) { 63 super(texture); 64 } 65 66 @Override 67 public void activateParticles (int startIndex, int count) { 68 for(int i=startIndex*regionChannel.strideSize, c = i +count*regionChannel.strideSize; 69 i < c; 70 i +=regionChannel.strideSize){ 71 AspectTextureRegion region = regions.random(); 72 regionChannel.data[i +ParticleChannels.UOffset] = region.u; 73 regionChannel.data[i +ParticleChannels.VOffset] = region.v; 74 regionChannel.data[i +ParticleChannels.U2Offset] = region.u2; 75 regionChannel.data[i +ParticleChannels.V2Offset] = region.v2; 76 regionChannel.data[i +ParticleChannels.HalfWidthOffset] = 0.5f; 77 regionChannel.data[i +ParticleChannels.HalfHeightOffset] = region.halfInvAspectRatio; 78 } 79 } 80 81 @Override 82 public Random copy () { 83 return new Random(this); 84 } 85 } 86 87 /** Assigns a region to the particles using the particle life percent 88 * to calculate the current index in the {@link RegionInfluencer#regions} array.*/ 89 public static class Animated extends RegionInfluencer{ 90 FloatChannel lifeChannel; 91 public Animated(){} 92 public Animated (Animated regionInfluencer) { 93 super(regionInfluencer); 94 } 95 96 public Animated (TextureRegion textureRegion) { 97 super(textureRegion); 98 } 99 100 public Animated (Texture texture) { 101 super(texture); 102 } 103 104 @Override 105 public void allocateChannels () { 106 super.allocateChannels(); 107 lifeChannel = controller.particles.addChannel(ParticleChannels.Life); 108 } 109 110 @Override 111 public void update () { 112 for(int i=0, l = ParticleChannels.LifePercentOffset, 113 c = controller.particles.size*regionChannel.strideSize; 114 i < c; 115 i +=regionChannel.strideSize, l +=lifeChannel.strideSize){ 116 AspectTextureRegion region = regions.get( (int)(lifeChannel.data[l]*(regions.size-1))); 117 regionChannel.data[i +ParticleChannels.UOffset] = region.u; 118 regionChannel.data[i +ParticleChannels.VOffset] = region.v; 119 regionChannel.data[i +ParticleChannels.U2Offset] = region.u2; 120 regionChannel.data[i +ParticleChannels.V2Offset] = region.v2; 121 regionChannel.data[i +ParticleChannels.HalfWidthOffset] = 0.5f; 122 regionChannel.data[i +ParticleChannels.HalfHeightOffset] = region.halfInvAspectRatio; 123 } 124 } 125 126 @Override 127 public Animated copy () { 128 return new Animated(this); 129 } 130 } 131 132 /** It's a class used internally by the {@link RegionInfluencer} to represent a texture region. 133 * It contains the uv coordinates of the region and the region inverse aspect ratio.*/ 134 public static class AspectTextureRegion{ 135 public float u, v, u2, v2; 136 public float halfInvAspectRatio; 137 138 public AspectTextureRegion(){} 139 140 public AspectTextureRegion( AspectTextureRegion aspectTextureRegion){ 141 set(aspectTextureRegion); 142 } 143 144 public AspectTextureRegion(TextureRegion region){ 145 set(region); 146 } 147 148 public void set(TextureRegion region){ 149 this.u = region.getU(); 150 this.v = region.getV(); 151 this.u2 = region.getU2(); 152 this.v2 = region.getV2(); 153 this.halfInvAspectRatio = 0.5f*((float)region.getRegionHeight()/region.getRegionWidth()); 154 } 155 156 public void set(AspectTextureRegion aspectTextureRegion){ 157 u = aspectTextureRegion.u; 158 v = aspectTextureRegion.v; 159 u2 = aspectTextureRegion.u2; 160 v2 = aspectTextureRegion.v2; 161 halfInvAspectRatio = aspectTextureRegion.halfInvAspectRatio; 162 } 163 } 164 165 public Array<AspectTextureRegion> regions; 166 FloatChannel regionChannel; 167 168 public RegionInfluencer(int regionsCount){ 169 this.regions = new Array<AspectTextureRegion>(false, regionsCount, AspectTextureRegion.class); 170 } 171 172 public RegionInfluencer(){ 173 this(1); 174 AspectTextureRegion aspectRegion = new AspectTextureRegion(); 175 aspectRegion.u = aspectRegion.v = 0; 176 aspectRegion.u2 = aspectRegion.v2 = 1; 177 aspectRegion.halfInvAspectRatio = 0.5f; 178 regions.add(aspectRegion); 179 } 180 181 /** All the regions must be defined on the same Texture */ 182 public RegionInfluencer(TextureRegion...regions){ 183 this.regions = new Array<AspectTextureRegion>( false, regions.length, AspectTextureRegion.class); 184 add(regions); 185 } 186 187 public RegionInfluencer(Texture texture){ 188 this(new TextureRegion(texture)); 189 } 190 191 public RegionInfluencer(RegionInfluencer regionInfluencer){ 192 this(regionInfluencer.regions.size); 193 regions.ensureCapacity(regionInfluencer.regions.size); 194 for(int i=0; i < regionInfluencer.regions.size; ++i){ 195 regions.add(new AspectTextureRegion((AspectTextureRegion)regionInfluencer.regions.get(i))); 196 } 197 } 198 199 public void add (TextureRegion...regions) { 200 this.regions.ensureCapacity(regions.length); 201 for(TextureRegion region : regions){ 202 this.regions.add(new AspectTextureRegion(region)); 203 } 204 } 205 206 public void clear(){ 207 regions.clear(); 208 } 209 210 @Override 211 public void allocateChannels () { 212 regionChannel = controller.particles.addChannel(ParticleChannels.TextureRegion); 213 } 214 215 @Override 216 public void write (Json json) { 217 json.writeValue("regions", regions, Array.class, AspectTextureRegion.class); 218 } 219 220 @Override 221 public void read (Json json, JsonValue jsonData) { 222 regions.clear(); 223 regions.addAll(json.readValue("regions", Array.class, AspectTextureRegion.class, jsonData)); 224 } 225 } 226