package complexion.resource;
import java.awt.image.BufferedImage;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import complexion.client.Atom;
import complexion.common.Directions;
/**
* A sprite consists of several different images(icon states) indexed by string,
* which are in turn split into several animation frames indexed by integer, which
* are in turn split into several directions indexed by integer.
*
* By supplying an icon state, an animation frame, and a direction, a BufferedImage
* can be extracted, which can be used to draw the object.
*
* @author cib
*
*/
public class Sprite extends Resource {
/**
* Load a .dmi file(a tiled PNG with metadata) into a Sprite object.
* @param filename The filepath as string of the .dmi
* @throws IOException
*/
public Sprite(String filename) throws IOException
{
// Remember the filename
this.filename = filename;
// Generate a CRC from the file on disk
this.hashID = getCRC32(filename);
parseDMI(new FileInputStream(filename));
}
/**
* Load an input stream into a sprite object. Useful if the .dmi is part
* of a .rsc file, rather than being in its own file.
* @param stream An InputStream object containing the .dmi
* @throws IOException
*/
public Sprite(String filename, InputStream stream) throws IOException
{
// Remember the filename
this.filename = filename;
parseDMI(stream);
}
/**
* Helper function for initializing a DMIParser and using the PNG metadata
* to populate the sprite states.
*/
private void parseDMI(InputStream stream) throws IOException
{
DMIParser parser = new DMIParser();
parser.parse(stream);
// extract the results
this.states = parser.states;
this.width = parser.width;
this.height = parser.height;
}
/**
* Get the width of the sprite in pixels. This includes transparent/invisible areas.
* Width is a constant value throughout instance lifetime.
*/
public int getWidth()
{
return width;
}
/**
* Get the height of the sprite in pixels. This includes transparent/invisible areas.
* Height is a constant value throughout instance lifetime.
*/
public int getHeight()
{
return height;
}
/**
* Get the BufferedImage associated with a specific state/frame/dir combination.
* @param state A string representing the sprite state.
* @param frame The index in the sprite's animation.
* @param dir The direction in which the sprite is facing.
* @return The image, or null if not defined.
*/
public BufferedImage getImage(String state, int frame, int dir)
{
// Try to get the state
SpriteState st = states.get(state);
if(st == null) return null;
// Try to get the frame
SpriteFrame fr;
try
{
fr = st.frames.get(frame);
}
catch(IndexOutOfBoundsException e)
{
// If the frame doesn't exist, try frame 0, that one must
// always exist
fr = st.frames.get(0);
}
BufferedImage b = fr.directions.get(dir);
if(b == null)
{
// If the direction doesn't exist, try direction SOUTH,
// that one must always exist
b = fr.directions.get(Directions.SOUTH);
}
return b;
}
private Map<String,SpriteState> states;
private int width = 0;
private int height = 0;
}
/**
* Private class used to hold a sprite state/icon state of a Sprite.
* This in turn may hold multiple animation frames, which in turn
* may hold multiple directions.
*/
class SpriteState
{
List<SpriteFrame> frames;
}
/**
* Private class used to hold an animation frame of a SpriteState.
* This in turn may hold multiple directions.
*/
class SpriteFrame
{
Map<Integer,BufferedImage> directions;
int delay; // How many 1/10th of a second will pass until the next frame
}