Home | History | Annotate | Download | only in g2d
      1 /*******************************************************************************
      2  * Copyright 2011 See AUTHORS file.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *   http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  ******************************************************************************/
     16 
     17 package com.badlogic.gdx.graphics.g2d;
     18 
     19 import java.io.BufferedReader;
     20 import java.io.File;
     21 import java.io.IOException;
     22 import java.io.InputStream;
     23 import java.io.InputStreamReader;
     24 import java.io.Writer;
     25 import java.util.HashMap;
     26 
     27 import com.badlogic.gdx.files.FileHandle;
     28 import com.badlogic.gdx.graphics.Texture;
     29 import com.badlogic.gdx.math.collision.BoundingBox;
     30 import com.badlogic.gdx.utils.Array;
     31 import com.badlogic.gdx.utils.Disposable;
     32 import com.badlogic.gdx.utils.GdxRuntimeException;
     33 import com.badlogic.gdx.utils.StreamUtils;
     34 
     35 /** See <a href="http://www.badlogicgames.com/wordpress/?p=1255">http://www.badlogicgames.com/wordpress/?p=1255</a>
     36  * @author mzechner */
     37 public class ParticleEffect implements Disposable {
     38 	private final Array<ParticleEmitter> emitters;
     39 	private BoundingBox bounds;
     40 	private boolean ownsTexture;
     41 
     42 	public ParticleEffect () {
     43 		emitters = new Array(8);
     44 	}
     45 
     46 	public ParticleEffect (ParticleEffect effect) {
     47 		emitters = new Array(true, effect.emitters.size);
     48 		for (int i = 0, n = effect.emitters.size; i < n; i++)
     49 			emitters.add(new ParticleEmitter(effect.emitters.get(i)));
     50 	}
     51 
     52 	public void start () {
     53 		for (int i = 0, n = emitters.size; i < n; i++)
     54 			emitters.get(i).start();
     55 	}
     56 
     57 	public void reset () {
     58 		for (int i = 0, n = emitters.size; i < n; i++)
     59 			emitters.get(i).reset();
     60 	}
     61 
     62 	public void update (float delta) {
     63 		for (int i = 0, n = emitters.size; i < n; i++)
     64 			emitters.get(i).update(delta);
     65 	}
     66 
     67 	public void draw (Batch spriteBatch) {
     68 		for (int i = 0, n = emitters.size; i < n; i++)
     69 			emitters.get(i).draw(spriteBatch);
     70 	}
     71 
     72 	public void draw (Batch spriteBatch, float delta) {
     73 		for (int i = 0, n = emitters.size; i < n; i++)
     74 			emitters.get(i).draw(spriteBatch, delta);
     75 	}
     76 
     77 	public void allowCompletion () {
     78 		for (int i = 0, n = emitters.size; i < n; i++)
     79 			emitters.get(i).allowCompletion();
     80 	}
     81 
     82 	public boolean isComplete () {
     83 		for (int i = 0, n = emitters.size; i < n; i++) {
     84 			ParticleEmitter emitter = emitters.get(i);
     85 			if (!emitter.isComplete()) return false;
     86 		}
     87 		return true;
     88 	}
     89 
     90 	public void setDuration (int duration) {
     91 		for (int i = 0, n = emitters.size; i < n; i++) {
     92 			ParticleEmitter emitter = emitters.get(i);
     93 			emitter.setContinuous(false);
     94 			emitter.duration = duration;
     95 			emitter.durationTimer = 0;
     96 		}
     97 	}
     98 
     99 	public void setPosition (float x, float y) {
    100 		for (int i = 0, n = emitters.size; i < n; i++)
    101 			emitters.get(i).setPosition(x, y);
    102 	}
    103 
    104 	public void setFlip (boolean flipX, boolean flipY) {
    105 		for (int i = 0, n = emitters.size; i < n; i++)
    106 			emitters.get(i).setFlip(flipX, flipY);
    107 	}
    108 
    109 	public void flipY () {
    110 		for (int i = 0, n = emitters.size; i < n; i++)
    111 			emitters.get(i).flipY();
    112 	}
    113 
    114 	public Array<ParticleEmitter> getEmitters () {
    115 		return emitters;
    116 	}
    117 
    118 	/** Returns the emitter with the specified name, or null. */
    119 	public ParticleEmitter findEmitter (String name) {
    120 		for (int i = 0, n = emitters.size; i < n; i++) {
    121 			ParticleEmitter emitter = emitters.get(i);
    122 			if (emitter.getName().equals(name)) return emitter;
    123 		}
    124 		return null;
    125 	}
    126 
    127 	public void save (Writer output) throws IOException {
    128 		int index = 0;
    129 		for (int i = 0, n = emitters.size; i < n; i++) {
    130 			ParticleEmitter emitter = emitters.get(i);
    131 			if (index++ > 0) output.write("\n\n");
    132 			emitter.save(output);
    133 		}
    134 	}
    135 
    136 	public void load (FileHandle effectFile, FileHandle imagesDir) {
    137 		loadEmitters(effectFile);
    138 		loadEmitterImages(imagesDir);
    139 	}
    140 
    141 	public void load (FileHandle effectFile, TextureAtlas atlas) {
    142 		load(effectFile, atlas, null);
    143 	}
    144 
    145 	public void load (FileHandle effectFile, TextureAtlas atlas, String atlasPrefix) {
    146 		loadEmitters(effectFile);
    147 		loadEmitterImages(atlas, atlasPrefix);
    148 	}
    149 
    150 	public void loadEmitters (FileHandle effectFile) {
    151 		InputStream input = effectFile.read();
    152 		emitters.clear();
    153 		BufferedReader reader = null;
    154 		try {
    155 			reader = new BufferedReader(new InputStreamReader(input), 512);
    156 			while (true) {
    157 				ParticleEmitter emitter = new ParticleEmitter(reader);
    158 				emitters.add(emitter);
    159 				if (reader.readLine() == null) break;
    160 				if (reader.readLine() == null) break;
    161 			}
    162 		} catch (IOException ex) {
    163 			throw new GdxRuntimeException("Error loading effect: " + effectFile, ex);
    164 		} finally {
    165 			StreamUtils.closeQuietly(reader);
    166 		}
    167 	}
    168 
    169 	public void loadEmitterImages (TextureAtlas atlas) {
    170 		loadEmitterImages(atlas, null);
    171 	}
    172 
    173 	public void loadEmitterImages (TextureAtlas atlas, String atlasPrefix) {
    174 		for (int i = 0, n = emitters.size; i < n; i++) {
    175 			ParticleEmitter emitter = emitters.get(i);
    176 			String imagePath = emitter.getImagePath();
    177 			if (imagePath == null) continue;
    178 			String imageName = new File(imagePath.replace('\\', '/')).getName();
    179 			int lastDotIndex = imageName.lastIndexOf('.');
    180 			if (lastDotIndex != -1) imageName = imageName.substring(0, lastDotIndex);
    181 			if (atlasPrefix != null) imageName = atlasPrefix + imageName;
    182 			Sprite sprite = atlas.createSprite(imageName);
    183 			if (sprite == null) throw new IllegalArgumentException("SpriteSheet missing image: " + imageName);
    184 			emitter.setSprite(sprite);
    185 		}
    186 	}
    187 
    188 	public void loadEmitterImages (FileHandle imagesDir) {
    189 		ownsTexture = true;
    190 		HashMap<String, Sprite> loadedSprites = new HashMap<String, Sprite>(emitters.size);
    191 		for (int i = 0, n = emitters.size; i < n; i++) {
    192 			ParticleEmitter emitter = emitters.get(i);
    193 			String imagePath = emitter.getImagePath();
    194 			if (imagePath == null) continue;
    195 			String imageName = new File(imagePath.replace('\\', '/')).getName();
    196 			Sprite sprite = loadedSprites.get(imageName);
    197 			if (sprite == null) {
    198 				sprite = new Sprite(loadTexture(imagesDir.child(imageName)));
    199 				loadedSprites.put(imageName, sprite);
    200 			}
    201 			emitter.setSprite(sprite);
    202 		}
    203 	}
    204 
    205 	protected Texture loadTexture (FileHandle file) {
    206 		return new Texture(file, false);
    207 	}
    208 
    209 	/** Disposes the texture for each sprite for each ParticleEmitter. */
    210 	public void dispose () {
    211 		if (!ownsTexture) return;
    212 		for (int i = 0, n = emitters.size; i < n; i++) {
    213 			ParticleEmitter emitter = emitters.get(i);
    214 			emitter.getSprite().getTexture().dispose();
    215 		}
    216 	}
    217 
    218 	/** Returns the bounding box for all active particles. z axis will always be zero. */
    219 	public BoundingBox getBoundingBox () {
    220 		if (bounds == null) bounds = new BoundingBox();
    221 
    222 		BoundingBox bounds = this.bounds;
    223 		bounds.inf();
    224 		for (ParticleEmitter emitter : this.emitters)
    225 			bounds.ext(emitter.getBoundingBox());
    226 		return bounds;
    227 	}
    228 
    229 	public void scaleEffect (float scaleFactor) {
    230 		for (ParticleEmitter particleEmitter : emitters) {
    231 			particleEmitter.getScale().setHigh(particleEmitter.getScale().getHighMin() * scaleFactor,
    232 				particleEmitter.getScale().getHighMax() * scaleFactor);
    233 			particleEmitter.getScale().setLow(particleEmitter.getScale().getLowMin() * scaleFactor,
    234 				particleEmitter.getScale().getLowMax() * scaleFactor);
    235 
    236 			particleEmitter.getVelocity().setHigh(particleEmitter.getVelocity().getHighMin() * scaleFactor,
    237 				particleEmitter.getVelocity().getHighMax() * scaleFactor);
    238 			particleEmitter.getVelocity().setLow(particleEmitter.getVelocity().getLowMin() * scaleFactor,
    239 				particleEmitter.getVelocity().getLowMax() * scaleFactor);
    240 
    241 			particleEmitter.getGravity().setHigh(particleEmitter.getGravity().getHighMin() * scaleFactor,
    242 				particleEmitter.getGravity().getHighMax() * scaleFactor);
    243 			particleEmitter.getGravity().setLow(particleEmitter.getGravity().getLowMin() * scaleFactor,
    244 				particleEmitter.getGravity().getLowMax() * scaleFactor);
    245 
    246 			particleEmitter.getWind().setHigh(particleEmitter.getWind().getHighMin() * scaleFactor,
    247 				particleEmitter.getWind().getHighMax() * scaleFactor);
    248 			particleEmitter.getWind().setLow(particleEmitter.getWind().getLowMin() * scaleFactor,
    249 				particleEmitter.getWind().getLowMax() * scaleFactor);
    250 
    251 			particleEmitter.getSpawnWidth().setHigh(particleEmitter.getSpawnWidth().getHighMin() * scaleFactor,
    252 				particleEmitter.getSpawnWidth().getHighMax() * scaleFactor);
    253 			particleEmitter.getSpawnWidth().setLow(particleEmitter.getSpawnWidth().getLowMin() * scaleFactor,
    254 				particleEmitter.getSpawnWidth().getLowMax() * scaleFactor);
    255 
    256 			particleEmitter.getSpawnHeight().setHigh(particleEmitter.getSpawnHeight().getHighMin() * scaleFactor,
    257 				particleEmitter.getSpawnHeight().getHighMax() * scaleFactor);
    258 			particleEmitter.getSpawnHeight().setLow(particleEmitter.getSpawnHeight().getLowMin() * scaleFactor,
    259 				particleEmitter.getSpawnHeight().getLowMax() * scaleFactor);
    260 
    261 			particleEmitter.getXOffsetValue().setLow(particleEmitter.getXOffsetValue().getLowMin() * scaleFactor,
    262 				particleEmitter.getXOffsetValue().getLowMax() * scaleFactor);
    263 
    264 			particleEmitter.getYOffsetValue().setLow(particleEmitter.getYOffsetValue().getLowMin() * scaleFactor,
    265 				particleEmitter.getYOffsetValue().getLowMax() * scaleFactor);
    266 		}
    267 	}
    268 
    269 	/** Sets the {@link com.badlogic.gdx.graphics.g2d.ParticleEmitter#setCleansUpBlendFunction(boolean) cleansUpBlendFunction}
    270 	 * parameter on all {@link com.badlogic.gdx.graphics.g2d.ParticleEmitter ParticleEmitters} currently in this ParticleEffect.
    271 	 * <p>
    272 	 * IMPORTANT: If set to false and if the next object to use this Batch expects alpha blending, you are responsible for setting
    273 	 * the Batch's blend function to (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) before that next object is drawn.
    274 	 * @param cleanUpBlendFunction */
    275 	public void setEmittersCleanUpBlendFunction (boolean cleanUpBlendFunction) {
    276 		for (int i = 0, n = emitters.size; i < n; i++) {
    277 			emitters.get(i).setCleansUpBlendFunction(cleanUpBlendFunction);
    278 		}
    279 	}
    280 }
    281