/* * Copyright (c) 2003-onwards Shaven Puppy Ltd * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of 'Shaven Puppy' nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.shavenpuppy.jglib.sprites; import java.io.Serializable; import com.shavenpuppy.jglib.Resource; /** * The sprite engine contains a list of sprites which it takes care of, * and has a SpriteRenderer to take care of actually doing the drawing. */ public class StaticSpriteEngine extends Resource implements SpriteEngine { private static final long serialVersionUID = 1L; /** The Renderer instance */ private final SpriteRenderer renderer; /** The sprites */ private Sprite[] sprites; /** The number of allocated sprites */ private int numAllocated; /** The number of visible sprites */ private int numVisible; /** The tick rate */ private int tickRate; /** Base alpha */ private float alpha = 1.0f; /** Sprite processor */ private SpriteProcessor spriteProcessor; /** Handy thing that just records the total number of sprites allocated in the entire system */ static int totalAllocated; /** * @return the total number of sprites allocated in all StaticSpriteEngines */ public static int getTotalAllocated() { return totalAllocated; } /** * C'tor * @param sortY * @param sortLayer * @param uniqueSprites * @param tickRate */ public StaticSpriteEngine(boolean sortY, int sortLayer, boolean uniqueSprites, int tickRate) { if (tickRate < 1) { throw new IllegalArgumentException("tickRate must be > 0"); } this.sprites = new Sprite[1]; this.tickRate = tickRate; for (int i = 0; i < sprites.length; i ++) { sprites[i] = new Sprite(this); sprites[i].index = i; } renderer = new DefaultSpriteRenderer(sortY, sortLayer, uniqueSprites); spriteProcessor = new SpriteProcessor() { @Override public void processRendering(Sprite[] sprite, int start, int end, SpriteRenderer renderer) { for (int i = start; i < end; i++) { Sprite s = sprites[i]; if (s.isVisible() && s.isActive()) { renderer.render(s); numVisible++; } } } }; } @Override public SpriteProcessor getSpriteProcessor() { return spriteProcessor; } @Override public void setSpriteProcessor(SpriteProcessor spriteProcessor) { this.spriteProcessor = spriteProcessor; } @Override protected void doCreate() { renderer.create(); } @Override protected void doDestroy() { renderer.destroy(); } /** * Sets the tick rate * @param newTickRate */ @Override public void setTickRate(int newTickRate) { tickRate = newTickRate; } /** * Gets the tick rate * @return the tick rate */ @Override public int getTickRate() { return tickRate; } /** * Allocate and initialize sprite. If there are no sprites available an exception is thrown. * The sprite returned will be visible and active, with no animation or image. * @param owner The sprite's new owner, which is used to keep track of debugging * @return a sprite */ @Override public Sprite allocateSprite(Serializable owner) { if (owner == null) { throw new NullPointerException("No owner specified"); } totalAllocated ++; if (numAllocated == sprites.length) { // Grow Sprite[] old = sprites; sprites = new Sprite[numAllocated * 2]; System.arraycopy(old, 0, sprites, 0, numAllocated); } Sprite s = sprites[numAllocated]; if (s == null) { s = sprites[numAllocated] = new Sprite(this); s.index = numAllocated; } s.init(owner); numAllocated ++; return s; } public int maxSprites() { return sprites.length; } public int numAllocated() { return numAllocated; } public int numFree() { return sprites.length - numAllocated; } /** * Deallocate a sprite. The sprite is returned to the sprite pool, and no matter what you do * with it now, it won't do anything on the screen. * @param sprite The sprite to return to the pool */ @Override public void deallocate(Sprite sprite) { totalAllocated --; sprites[sprite.index] = sprites[-- numAllocated]; sprites[sprite.index].index = sprite.index; sprites[numAllocated] = sprite; sprite.index = numAllocated; } /** * Remove all sprites */ @Override public void clear() { for (int i = numAllocated; --i >= 0; ) { sprites[i].deallocate(); } } /** * Tick all sprites. */ @Override public void tick() { final int n = numAllocated; for (int i = 0; i < n; i++) { Sprite s = sprites[i]; if (s.isActive()) { s.tick(); } } } // /** // * Dump sprites // */ // public void dump() { // final int n = numAllocated; // System.err.println("Sprite dump:"); // for (int i = 0; i < n; i++) { // System.err.println(sprites[i]); // } // } @Override public void render() { numVisible = 0; // Now render the sprites renderer.setAlpha(alpha); renderer.preRender(); spriteProcessor.processRendering(sprites, 0, numAllocated, renderer); renderer.postRender(); } /** * @return Returns the alpha. */ @Override public float getAlpha() { return alpha; } /** * Sets the base alpha for all the sprites. * @param alpha The alpha to set. */ @Override public void setAlpha(float alpha) { this.alpha = alpha; } @Override public SpriteRenderer getSpriteRenderer() { return renderer; } }