/** * Copyright 2008 - 2012 * * 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. * * @project loon * @author cping * @email:javachenpeng@yahoo.com * @version 0.3.3 */ package loon.particle; import java.util.Iterator; import loon.LSystem; import loon.LTexture; import loon.LTextures; import loon.action.sprite.Entity; import loon.canvas.LColor; import loon.opengl.BlendState; import loon.opengl.GLEx; import loon.opengl.TextureUtils; import loon.utils.GLUtils; import loon.utils.ObjectMap; import loon.utils.TArray; public class SimpleParticleSystem extends Entity { private static final int DEFAULT_PARTICLES = 100; private int state = LSystem.MODE_ADD; private TArray<SimpleEmitter> removeMe = new TArray<SimpleEmitter>(); private class ParticlePool { public SimpleParticle[] particles; public TArray<SimpleParticle> available; public ParticlePool(SimpleParticleSystem system, int maxParticles) { particles = new SimpleParticle[maxParticles]; available = new TArray<SimpleParticle>(); for (int i = 0; i < particles.length; i++) { particles[i] = createParticle(system); } reset(system); } public void reset(SimpleParticleSystem system) { available.clear(); for (int i = 0; i < particles.length; i++) { available.add(particles[i]); } } } protected ObjectMap<SimpleEmitter, ParticlePool> particlesByEmitter = new ObjectMap<SimpleEmitter, ParticlePool>(); protected int maxParticlesPerEmitter; protected TArray<SimpleEmitter> emitters = new TArray<SimpleEmitter>(); protected SimpleParticle dummy; private int pCount; private boolean usePoints; private boolean removeCompletedEmitters = true; private LTexture sprite; private String defaultImageName; private LColor mask; public SimpleParticleSystem(LTexture defaultSprite) { this(defaultSprite, DEFAULT_PARTICLES); } public SimpleParticleSystem(String defaultSpriteRef) { this(defaultSpriteRef, DEFAULT_PARTICLES); } @Override public void reset() { Iterator<ParticlePool> pools = particlesByEmitter.values().iterator(); while (pools.hasNext()) { ParticlePool pool = pools.next(); pool.reset(this); } for (int i = 0; i < emitters.size; i++) { SimpleEmitter emitter = emitters.get(i); emitter.resetState(); } super.reset(); } public void setRemoveCompletedEmitters(boolean remove) { removeCompletedEmitters = remove; } public void setUsePoints(boolean usePoints) { this.usePoints = usePoints; } public boolean usePoints() { return usePoints; } public SimpleParticleSystem(String defaultSpriteRef, int maxParticles) { this(defaultSpriteRef, maxParticles, null); } public SimpleParticleSystem(String defaultSpriteRef, int maxParticles, LColor mask) { this.maxParticlesPerEmitter = maxParticles; this.mask = mask; this.setRepaint(true); setDefaultImageName(defaultSpriteRef); dummy = createParticle(this); } public SimpleParticleSystem(LTexture defaultSprite, int maxParticles) { this.maxParticlesPerEmitter = maxParticles; this.setRepaint(true); sprite = defaultSprite; dummy = createParticle(this); } public void setDefaultImageName(String ref) { defaultImageName = ref; sprite = null; } public int getBlendingMode() { return GLUtils.getBlendMode(); } protected SimpleParticle createParticle(SimpleParticleSystem system) { return new SimpleParticle(system); } public int getEmitterCount() { return emitters.size; } public SimpleEmitter getEmitter(int index) { return emitters.get(index); } public void addEmitter(SimpleEmitter emitter) { emitters.add(emitter); ParticlePool pool = new ParticlePool(this, maxParticlesPerEmitter); particlesByEmitter.put(emitter, pool); } public void removeEmitter(SimpleEmitter emitter) { emitters.remove(emitter); particlesByEmitter.remove(emitter); } public void removeAllEmitters() { for (int i = 0; i < emitters.size; i++) { removeEmitter(emitters.get(i)); i--; } } public float getPositionX() { return _location.x; } public float getPositionY() { return _location.y; } public void setPosition(float x, float y) { this.setLocation(x, y); } public void render(GLEx g) { repaint(g, _location.x, _location.y); } @Override public void repaint(GLEx g, float x, float y) { if ((sprite == null) && (defaultImageName != null)) { loadSystemParticleImage(); } for (int emitterIdx = 0; emitterIdx < emitters.size; emitterIdx++) { SimpleEmitter emitter = emitters.get(emitterIdx); if (!emitter.isEnabled()) { continue; } int mode = g.getBlendMode(); if (emitter.useAdditive()) { g.setBlendMode(LSystem.MODE_ADD); } else { g.setBlendMode(state); } ParticlePool pool = particlesByEmitter.get(emitter); LTexture image = emitter.getImage(); if (image == null) { image = this.sprite; } if (!emitter.isOriented() && !emitter.usePoints(this)) { image.glBegin(); } image.getTextureBatch().setLocation(x, y); image.getTextureBatch().setBlendState(BlendState.Null); for (int i = 0; i < pool.particles.length; i++) { if (pool.particles[i].inUse()) { pool.particles[i].paint(g); } } if (!emitter.isOriented() && !emitter.usePoints(this)) { image.glEnd(); } g.setBlendMode(mode); } } private void loadSystemParticleImage() { try { if (mask != null) { sprite = TextureUtils.filterColor(defaultImageName, mask); } else { sprite = LTextures.loadTexture(defaultImageName); } } catch (Exception e) { e.printStackTrace(); defaultImageName = null; } } @Override public void onUpdate(long delta) { if ((sprite == null) && (defaultImageName != null)) { loadSystemParticleImage(); } removeMe.clear(); TArray<SimpleEmitter> emitters = new TArray<SimpleEmitter>( this.emitters); for (int i = 0; i < emitters.size; i++) { SimpleEmitter emitter = emitters.get(i); if (emitter.isEnabled()) { emitter.update(this, delta); if (removeCompletedEmitters) { if (emitter.completed()) { removeMe.add(emitter); particlesByEmitter.remove(emitter); } } } } this.emitters.removeAll(removeMe); pCount = 0; if (!particlesByEmitter.isEmpty()) { for (SimpleEmitter emitter : particlesByEmitter.keys()) { if (emitter.isEnabled()) { ParticlePool pool = particlesByEmitter.get(emitter); for (int i = 0; i < pool.particles.length; i++) { if (pool.particles[i].life > 0) { pool.particles[i].update(delta); pCount++; } } } } } } public int getParticleCount() { return pCount; } public SimpleParticle getNewParticle(SimpleEmitter emitter, float life) { ParticlePool pool = particlesByEmitter.get(emitter); TArray<SimpleParticle> available = pool.available; if (available.size > 0) { SimpleParticle p = available.removeIndex(available.size - 1); p.init(emitter, life); p.setImage(sprite); return p; } return dummy; } public void release(SimpleParticle particle) { if (particle != dummy) { ParticlePool pool = particlesByEmitter.get(particle.getEmitter()); pool.available.add(particle); } } public void releaseAll(SimpleEmitter emitter) { if (!particlesByEmitter.isEmpty()) { Iterator<ParticlePool> it = particlesByEmitter.values().iterator(); while (it.hasNext()) { ParticlePool pool = it.next(); for (int i = 0; i < pool.particles.length; i++) { if (pool.particles[i].inUse()) { if (pool.particles[i].getEmitter() == emitter) { pool.particles[i].setLife(-1); release(pool.particles[i]); } } } } } } public void moveAll(SimpleEmitter emitter, float x, float y) { ParticlePool pool = particlesByEmitter.get(emitter); for (int i = 0; i < pool.particles.length; i++) { if (pool.particles[i].inUse()) { pool.particles[i].move(x, y); } } } public int getBlendingState() { return state; } public void setBlendingState(int s) { this.state = s; } }