package com.indyforge.twod.engine.graphics.sprite;
import java.awt.HeadlessException;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import com.indyforge.twod.engine.graphics.GraphicsRoutines;
import com.indyforge.twod.engine.graphics.rendering.scenegraph.math.MathExt;
import com.indyforge.twod.engine.resources.Resource;
import com.indyforge.twod.engine.resources.assets.AssetManager;
/**
*
* A sprite is basically an image which contains sub-images which is typically
* used for animations.
*
* @author Matthias Hesse
* @see Animation
* @see AnimationBundle
*/
public final class Sprite implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
// Here we store all sub images
private transient BufferedImage[][] subImages;
// The sprite image resource
private final Resource<BufferedImage> imageResource;
// Here we store the raster information
private final int rasterX, rasterY;
/*
* When deserializing load the sub-images directly.
*/
private void readObject(ObjectInputStream in) throws IOException,
ClassNotFoundException {
// Read the default stuff
in.defaultReadObject();
// If not headless...
if (!AssetManager.isHeadless()) {
try {
// Try to load the images
loadSubImages();
} catch (Exception e) {
throw new IOException("Failed to load sub images", e);
}
}
}
/**
* Loads the sub-images.
*
* @throws Exception
* If an exception occurs.
*/
private void loadSubImages() throws Exception {
// Create new 2-dim array containing all sub-images
subImages = new BufferedImage[rasterY][rasterX];
// Iterate for x and y
for (int x = 0; x < rasterX; x++) {
for (int y = 0; y < rasterY; y++) {
// Create sub-image
subImages[y][x] = GraphicsRoutines.getSpriteSubImage(
imageResource.get(), rasterX, rasterY, x, y);
}
}
}
/**
* Creates a sprite.
*
* @param imageResource
* The sprite image resource.
* @param rasterX
* The columns of the sprite.
* @param rasterY
* The rows of the sprite.
* @throws Exception
* If an exception occurs.
*/
public Sprite(Resource<BufferedImage> imageResource, int rasterX,
int rasterY) throws Exception {
if (imageResource == null) {
throw new NullPointerException("imageResource");
} else if (rasterX <= 0) {
throw new IllegalArgumentException("rasterX must be > 0");
} else if (rasterY <= 0) {
throw new IllegalArgumentException("rasterY must be > 0");
}
// Save vars
this.imageResource = imageResource;
this.rasterX = rasterX;
this.rasterY = rasterY;
// If not headless...
if (!AssetManager.isHeadless()) {
// Load the sub images
loadSubImages();
}
}
public Resource<BufferedImage> getImageResource() {
return imageResource;
}
/**
* @return the sub images.
*/
public BufferedImage[][] getSubImages() {
if (AssetManager.isHeadless()) {
throw new HeadlessException();
}
return subImages;
}
/**
* @return the columns of the sprite.
*/
public int getRasterX() {
return rasterX;
}
/**
* @return the rows of the sprite.
*/
public int getRasterY() {
return rasterY;
}
/**
* Creates a new animation using a given range of sub images.
*
* @param name
* The name of the new animation.
* @param timePerImage
* The time-per-frame of the animation.
* @param fromX
* The x start component.
* @param fromY
* The y start component.
* @param count
* The number of sub images read step by step.
* @return a new animation containig the given sub images.
*/
public Animation newAnimationFromRange(String name, long timePerImage,
int fromX, int fromY, int count) {
if (count <= 0) {
throw new IllegalArgumentException("count must be > 0");
}
// Clamp the coords
fromX = MathExt.clamp(fromX, 0, rasterX - 1);
fromY = MathExt.clamp(fromY, 0, rasterY - 1);
// Create a list holding the image coords
List<Point> imageCoords = new ArrayList<Point>(count);
// Iteration vars
int x = fromX, y = fromY;
// Iterate
for (int i = 0; i < count; i++) {
// Save the coord
imageCoords.add(new Point(y, x));
// Inc
x++;
// Adjust
if (x >= rasterX) {
x = 0;
y++;
}
}
// Create a new instance of animation
return new Animation(this, name, imageCoords, timePerImage);
}
/**
* Creates a new animation using the given points.
*
* @param name
* The name of the new animation.
* @param timePerImage
* The time-per-frame of the animation.
* @param coords
* The coords of the sub images.
* @return a new animation containig the given sub images.
*/
public Animation newAnimation(String name, long timePerImage,
Point... coords) {
// Create a list holding the image coords
List<Point> imageCoords = new ArrayList<Point>(coords.length);
// Iterate over all coords
for (Point coord : coords) {
// Save coord
imageCoords.add(coord);
}
// Create a new instance of animation
return new Animation(this, name, imageCoords, timePerImage);
}
}