/******************************************************************************* * Copyright 2011 See AUTHORS file. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package com.badlogic.gdx.graphics.g3d.particles.influencers; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.graphics.g3d.particles.ParallelArray.FloatChannel; import com.badlogic.gdx.graphics.g3d.particles.ParticleChannels; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Json; import com.badlogic.gdx.utils.JsonValue; /** It's an {@link Influencer} which assigns a region of a {@link Texture} to the particles. * @author Inferno */ public abstract class RegionInfluencer extends Influencer { /** Assigns the first region of {@link RegionInfluencer#regions} to the particles. */ public static class Single extends RegionInfluencer { public Single () { } public Single (Single regionInfluencer) { super(regionInfluencer); } public Single (TextureRegion textureRegion) { super(textureRegion); } public Single (Texture texture) { super(texture); } @Override public void init () { AspectTextureRegion region = regions.items[0]; for (int i = 0, c = controller.emitter.maxParticleCount * regionChannel.strideSize; i < c; i += regionChannel.strideSize) { regionChannel.data[i + ParticleChannels.UOffset] = region.u; regionChannel.data[i + ParticleChannels.VOffset] = region.v; regionChannel.data[i + ParticleChannels.U2Offset] = region.u2; regionChannel.data[i + ParticleChannels.V2Offset] = region.v2; regionChannel.data[i + ParticleChannels.HalfWidthOffset] = 0.5f; regionChannel.data[i + ParticleChannels.HalfHeightOffset] = region.halfInvAspectRatio; } } @Override public Single copy () { return new Single(this); } } /** Assigns a random region of {@link RegionInfluencer#regions} to the particles. */ public static class Random extends RegionInfluencer { public Random () { } public Random (Random regionInfluencer) { super(regionInfluencer); } public Random (TextureRegion textureRegion) { super(textureRegion); } public Random (Texture texture) { super(texture); } @Override public void activateParticles (int startIndex, int count) { for (int i = startIndex * regionChannel.strideSize, c = i + count * regionChannel.strideSize; i < c; i += regionChannel.strideSize) { AspectTextureRegion region = regions.random(); regionChannel.data[i + ParticleChannels.UOffset] = region.u; regionChannel.data[i + ParticleChannels.VOffset] = region.v; regionChannel.data[i + ParticleChannels.U2Offset] = region.u2; regionChannel.data[i + ParticleChannels.V2Offset] = region.v2; regionChannel.data[i + ParticleChannels.HalfWidthOffset] = 0.5f; regionChannel.data[i + ParticleChannels.HalfHeightOffset] = region.halfInvAspectRatio; } } @Override public Random copy () { return new Random(this); } } /** Assigns a region to the particles using the particle life percent to calculate the current index in the * {@link RegionInfluencer#regions} array. */ public static class Animated extends RegionInfluencer { FloatChannel lifeChannel; public Animated () { } public Animated (Animated regionInfluencer) { super(regionInfluencer); } public Animated (TextureRegion textureRegion) { super(textureRegion); } public Animated (Texture texture) { super(texture); } @Override public void allocateChannels () { super.allocateChannels(); lifeChannel = controller.particles.addChannel(ParticleChannels.Life); } @Override public void update () { for (int i = 0, l = ParticleChannels.LifePercentOffset, c = controller.particles.size * regionChannel.strideSize; i < c; i += regionChannel.strideSize, l += lifeChannel.strideSize) { AspectTextureRegion region = regions.get((int)(lifeChannel.data[l] * (regions.size - 1))); regionChannel.data[i + ParticleChannels.UOffset] = region.u; regionChannel.data[i + ParticleChannels.VOffset] = region.v; regionChannel.data[i + ParticleChannels.U2Offset] = region.u2; regionChannel.data[i + ParticleChannels.V2Offset] = region.v2; regionChannel.data[i + ParticleChannels.HalfWidthOffset] = 0.5f; regionChannel.data[i + ParticleChannels.HalfHeightOffset] = region.halfInvAspectRatio; } } @Override public Animated copy () { return new Animated(this); } } /** It's a class used internally by the {@link RegionInfluencer} to represent a texture region. It contains the uv coordinates * of the region and the region inverse aspect ratio. */ public static class AspectTextureRegion { public float u, v, u2, v2; public float halfInvAspectRatio; public AspectTextureRegion () { } public AspectTextureRegion (AspectTextureRegion aspectTextureRegion) { set(aspectTextureRegion); } public AspectTextureRegion (TextureRegion region) { set(region); } public void set (TextureRegion region) { this.u = region.getU(); this.v = region.getV(); this.u2 = region.getU2(); this.v2 = region.getV2(); this.halfInvAspectRatio = 0.5f * ((float)region.getRegionHeight() / region.getRegionWidth()); } public void set (AspectTextureRegion aspectTextureRegion) { u = aspectTextureRegion.u; v = aspectTextureRegion.v; u2 = aspectTextureRegion.u2; v2 = aspectTextureRegion.v2; halfInvAspectRatio = aspectTextureRegion.halfInvAspectRatio; } } public Array<AspectTextureRegion> regions; FloatChannel regionChannel; public RegionInfluencer (int regionsCount) { this.regions = new Array<AspectTextureRegion>(false, regionsCount, AspectTextureRegion.class); } public RegionInfluencer () { this(1); AspectTextureRegion aspectRegion = new AspectTextureRegion(); aspectRegion.u = aspectRegion.v = 0; aspectRegion.u2 = aspectRegion.v2 = 1; aspectRegion.halfInvAspectRatio = 0.5f; regions.add(aspectRegion); } /** All the regions must be defined on the same Texture */ public RegionInfluencer (TextureRegion... regions) { this.regions = new Array<AspectTextureRegion>(false, regions.length, AspectTextureRegion.class); add(regions); } public RegionInfluencer (Texture texture) { this(new TextureRegion(texture)); } public RegionInfluencer (RegionInfluencer regionInfluencer) { this(regionInfluencer.regions.size); regions.ensureCapacity(regionInfluencer.regions.size); for (int i = 0; i < regionInfluencer.regions.size; ++i) { regions.add(new AspectTextureRegion((AspectTextureRegion)regionInfluencer.regions.get(i))); } } public void add (TextureRegion... regions) { this.regions.ensureCapacity(regions.length); for (TextureRegion region : regions) { this.regions.add(new AspectTextureRegion(region)); } } public void clear () { regions.clear(); } @Override public void allocateChannels () { regionChannel = controller.particles.addChannel(ParticleChannels.TextureRegion); } @Override public void write (Json json) { json.writeValue("regions", regions, Array.class, AspectTextureRegion.class); } @Override public void read (Json json, JsonValue jsonData) { regions.clear(); regions.addAll(json.readValue("regions", Array.class, AspectTextureRegion.class, jsonData)); } }