this method is called in the context of the parent tag; it reads all <image> tags that are children of the current tag and only returns one of them
296 lines
7 KiB
Java
296 lines
7 KiB
Java
// This file is part of MicropolisJ.
|
|
// Copyright (C) 2013 Jason Long
|
|
// Portions Copyright (C) 1989-2007 Electronic Arts Inc.
|
|
//
|
|
// MicropolisJ is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU GPLv3, with additional terms.
|
|
// See the README file, included in this distribution, for details.
|
|
|
|
package micropolisj.gui;
|
|
|
|
import java.awt.*;
|
|
import java.awt.image.*;
|
|
import java.net.URL;
|
|
import java.io.*;
|
|
import java.util.*;
|
|
import javax.imageio.ImageIO;
|
|
import javax.swing.*;
|
|
import javax.xml.stream.*;
|
|
|
|
import micropolisj.engine.*;
|
|
import micropolisj.graphics.TileImage;
|
|
import static micropolisj.engine.TileConstants.*;
|
|
import static micropolisj.XML_Helper.*;
|
|
import static micropolisj.graphics.TileImage.*;
|
|
|
|
public class TileImages
|
|
{
|
|
final String name;
|
|
final int TILE_WIDTH;
|
|
final int TILE_HEIGHT;
|
|
TileImage [] tileImageMap;
|
|
Map<SpriteKind, Map<Integer, Image> > spriteImages;
|
|
|
|
private TileImages(String name, int size)
|
|
{
|
|
this.name = name;
|
|
this.TILE_WIDTH = size;
|
|
this.TILE_HEIGHT = size;
|
|
|
|
initTileImageMap();
|
|
}
|
|
|
|
String getResourceName()
|
|
{
|
|
return "/" + name + "/tiles.png";
|
|
}
|
|
|
|
class MyLoaderContext implements LoaderContext
|
|
{
|
|
Map<String,BufferedImage> images = new HashMap<String,BufferedImage>();
|
|
|
|
//implements LoaderContext
|
|
public BufferedImage getDefaultImage()
|
|
{
|
|
return getImage("tiles.png");
|
|
}
|
|
|
|
//implements LoaderContext
|
|
public BufferedImage getImage(String fileName)
|
|
{
|
|
if (!images.containsKey(fileName)) {
|
|
images.put(fileName, loadImage("/"+name+"/"+fileName));
|
|
}
|
|
return images.get(fileName);
|
|
}
|
|
}
|
|
|
|
void initTileImageMap()
|
|
{
|
|
if (this.spriteImages != null) {
|
|
// already loaded
|
|
return;
|
|
}
|
|
|
|
LoaderContext ctx = new MyLoaderContext();
|
|
|
|
try
|
|
{
|
|
|
|
// load tile->image mapping
|
|
this.tileImageMap = new TileImage[Tiles.getTileCount()];
|
|
String resourceName = "/" + name + "/tiles.idx";
|
|
|
|
InputStream inStream = TileImages.class.getResourceAsStream(resourceName);
|
|
XMLStreamReader in = XMLInputFactory.newInstance().createXMLStreamReader(inStream, "UTF-8");
|
|
|
|
in.nextTag();
|
|
if (!(in.getEventType() == XMLStreamConstants.START_ELEMENT &&
|
|
in.getLocalName().equals("micropolis-tiles-index"))) {
|
|
throw new IOException("Unrecognized file format");
|
|
}
|
|
|
|
while (in.nextTag() != XMLStreamConstants.END_ELEMENT) {
|
|
assert in.isStartElement();
|
|
|
|
String tagName = in.getLocalName();
|
|
if (!tagName.equals("tile")) {
|
|
skipToEndElement(in);
|
|
continue;
|
|
}
|
|
|
|
String tileName = in.getAttributeValue(null, "name");
|
|
TileImage img = readTileImageM(in, ctx);
|
|
|
|
assert tileName != null;
|
|
assert img != null;
|
|
|
|
TileSpec ts = Tiles.load(tileName);
|
|
tileImageMap[ts.tileNumber] = img;
|
|
|
|
assert in.isEndElement() && in.getLocalName().equals("tile");
|
|
}
|
|
|
|
in.close();
|
|
inStream.close();
|
|
|
|
}
|
|
catch (XMLStreamException e) {
|
|
throw new Error("unexpected: "+e, e);
|
|
}
|
|
catch (IOException e) {
|
|
throw new Error("unexpected: "+e, e);
|
|
}
|
|
}
|
|
|
|
static Map<Integer,TileImages> savedInstances = new HashMap<Integer,TileImages>();
|
|
|
|
public static TileImages getInstance(int size)
|
|
{
|
|
TileImages self = getInstance(String.format("%dx%d", size, size), size);
|
|
self.loadSpriteImages();
|
|
return self;
|
|
}
|
|
|
|
public static TileImages getInstance(String name, int size)
|
|
{
|
|
if (!savedInstances.containsKey(size)) {
|
|
savedInstances.put(size, new TileImages(name, size));
|
|
}
|
|
return savedInstances.get(size);
|
|
}
|
|
|
|
public class ImageInfo
|
|
{
|
|
BufferedImage srcImage;
|
|
int offsetY;
|
|
boolean animated;
|
|
|
|
ImageInfo(BufferedImage srcImage, int offsetY, boolean animated) {
|
|
this.srcImage = srcImage;
|
|
this.offsetY = offsetY;
|
|
this.animated = animated;
|
|
}
|
|
|
|
boolean isAnimated() { return animated; }
|
|
|
|
public void drawTo(Graphics gr, int destX, int destY)
|
|
{
|
|
gr.drawImage(getImage(),
|
|
destX, destY,
|
|
null);
|
|
}
|
|
|
|
public void drawToBytes(BufferedImage img, int x, int y)
|
|
{
|
|
for (int yy = 0; yy < TILE_HEIGHT; yy++)
|
|
{
|
|
for (int xx = 0; xx < TILE_WIDTH; xx++)
|
|
{
|
|
img.setRGB(x+xx,y+yy,
|
|
srcImage.getRGB(xx,offsetY+yy));
|
|
}
|
|
}
|
|
}
|
|
|
|
public Image getImage()
|
|
{
|
|
return srcImage.getSubimage(
|
|
0, offsetY,
|
|
TILE_WIDTH, TILE_HEIGHT
|
|
);
|
|
}
|
|
}
|
|
|
|
public ImageInfo getTileImageInfo(int tileNumber)
|
|
{
|
|
return getTileImageInfo(tileNumber, 0);
|
|
}
|
|
|
|
public ImageInfo getTileImageInfo(int tileNumber, int acycle)
|
|
{
|
|
assert (tileNumber & LOMASK) == tileNumber;
|
|
assert tileNumber >= 0 && tileNumber < tileImageMap.length;
|
|
|
|
TileImage ti = tileImageMap[tileNumber];
|
|
if (ti instanceof SimpleTileImage) {
|
|
final SimpleTileImage sti = (SimpleTileImage) ti;
|
|
|
|
return new ImageInfo(sti.srcImage, sti.offsetY, false);
|
|
}
|
|
else if (ti instanceof AnimatedTile) {
|
|
final AnimatedTile anim = (AnimatedTile) ti;
|
|
final SimpleTileImage sti = anim.getFrameByTime(acycle);
|
|
|
|
return new ImageInfo(sti.srcImage, sti.offsetY, true);
|
|
}
|
|
else {
|
|
throw new Error("no image for tile "+tileNumber);
|
|
}
|
|
}
|
|
|
|
public Image getTileImage(int tile)
|
|
{
|
|
return getTileImageInfo(tile).getImage();
|
|
}
|
|
|
|
public Image getSpriteImage(SpriteKind kind, int frameNumber)
|
|
{
|
|
assert spriteImages != null;
|
|
|
|
return spriteImages.get(kind).get(frameNumber);
|
|
}
|
|
|
|
private void loadSpriteImages()
|
|
{
|
|
if (this.spriteImages != null) {
|
|
// already loaded
|
|
return;
|
|
}
|
|
|
|
spriteImages = new EnumMap<SpriteKind, Map<Integer,Image> >(SpriteKind.class);
|
|
for (SpriteKind kind : SpriteKind.values())
|
|
{
|
|
HashMap<Integer,Image> imgs = new HashMap<Integer,Image>();
|
|
for (int i = 0; i < kind.numFrames; i++) {
|
|
Image img = loadSpriteImage(kind, i);
|
|
if (img != null) {
|
|
imgs.put(i, img);
|
|
}
|
|
}
|
|
spriteImages.put(kind, imgs);
|
|
}
|
|
}
|
|
|
|
Image loadSpriteImage(SpriteKind kind, int frameNo)
|
|
{
|
|
String resourceName = "/obj"+kind.objectId+"-"+frameNo;
|
|
|
|
// first, try to load specific size image
|
|
URL iconUrl = TileImages.class.getResource(resourceName+"_"+TILE_WIDTH+"x"+TILE_HEIGHT+".png");
|
|
if (iconUrl != null) {
|
|
return new ImageIcon(iconUrl).getImage();
|
|
}
|
|
|
|
iconUrl = TileImages.class.getResource(resourceName+".png");
|
|
if (iconUrl == null)
|
|
return null;
|
|
|
|
if (TILE_WIDTH==16 && TILE_HEIGHT==16) {
|
|
return new ImageIcon(iconUrl).getImage();
|
|
}
|
|
|
|
// scale the image ourselves
|
|
ImageIcon ii = new ImageIcon(iconUrl);
|
|
int destWidth = ii.getIconWidth() * TILE_WIDTH / 16;
|
|
int destHeight = ii.getIconHeight() * TILE_HEIGHT / 16;
|
|
|
|
GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
|
|
GraphicsDevice dev = env.getDefaultScreenDevice();
|
|
GraphicsConfiguration conf = dev.getDefaultConfiguration();
|
|
BufferedImage bi = conf.createCompatibleImage(destWidth, destHeight, Transparency.TRANSLUCENT);
|
|
Graphics2D gr = bi.createGraphics();
|
|
|
|
gr.drawImage(ii.getImage(),
|
|
0, 0, destWidth, destHeight,
|
|
0, 0,
|
|
ii.getIconWidth(), ii.getIconHeight(),
|
|
null);
|
|
return bi;
|
|
}
|
|
|
|
static BufferedImage loadImage(String resourceName)
|
|
{
|
|
URL url = TileImages.class.getResource(resourceName);
|
|
try {
|
|
|
|
BufferedImage bi = ImageIO.read(url);
|
|
return bi;
|
|
|
|
}
|
|
catch (IOException e) {
|
|
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
}
|