Refactor sprite loading some, read alphas properly instead of this silly hack
This commit is contained in:
@@ -39,7 +39,8 @@ public class SpriteDefinition
|
|||||||
private int offsetY;
|
private int offsetY;
|
||||||
private int width;
|
private int width;
|
||||||
private int height;
|
private int height;
|
||||||
private byte[] pixels;
|
private byte[] pixels; // indexes into palette
|
||||||
|
private byte[] alphas;
|
||||||
private int maxWidth;
|
private int maxWidth;
|
||||||
private int maxHeight;
|
private int maxHeight;
|
||||||
|
|
||||||
@@ -108,6 +109,16 @@ public class SpriteDefinition
|
|||||||
this.pixels = pixels;
|
this.pixels = pixels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[] getAlphas()
|
||||||
|
{
|
||||||
|
return alphas;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAlphas(byte[] alphas)
|
||||||
|
{
|
||||||
|
this.alphas = alphas;
|
||||||
|
}
|
||||||
|
|
||||||
public int getMaxWidth()
|
public int getMaxWidth()
|
||||||
{
|
{
|
||||||
return maxWidth;
|
return maxWidth;
|
||||||
|
|||||||
@@ -35,88 +35,140 @@ import net.runelite.cache.io.InputStream;
|
|||||||
|
|
||||||
public class SpriteLoader
|
public class SpriteLoader
|
||||||
{
|
{
|
||||||
|
public static final int FLAG_VERTICAL = 0b01;
|
||||||
|
public static final int FLAG_ALPHA = 0b10;
|
||||||
|
|
||||||
private SpriteDefinition[] sprites;
|
private SpriteDefinition[] sprites;
|
||||||
|
|
||||||
private int[] loadedPalette;
|
private int[] loadedPalette;
|
||||||
private int loadedSpriteMaxWidth;
|
private int width;
|
||||||
private int loadedSpriteMaxHeight;
|
private int height;
|
||||||
|
|
||||||
public void load(InputStream stream)
|
public void load(InputStream stream)
|
||||||
{
|
{
|
||||||
stream.setOffset(stream.getLength() - 2);
|
stream.setOffset(stream.getLength() - 2);
|
||||||
int paletteChildCount = stream.readUnsignedShort();
|
int spriteCount = stream.readUnsignedShort();
|
||||||
sprites = new SpriteDefinition[paletteChildCount];
|
|
||||||
for (int i = 0; i < paletteChildCount; ++i)
|
sprites = new SpriteDefinition[spriteCount];
|
||||||
|
for (int i = 0; i < spriteCount; ++i)
|
||||||
{
|
{
|
||||||
sprites[i] = new SpriteDefinition(this);
|
sprites[i] = new SpriteDefinition(this);
|
||||||
}
|
}
|
||||||
stream.setOffset(stream.getLength() - 7 - paletteChildCount * 8);
|
|
||||||
loadedSpriteMaxWidth = stream.readUnsignedShort();
|
|
||||||
loadedSpriteMaxHeight = stream.readUnsignedShort();
|
|
||||||
int var3 = (stream.readUnsignedByte() & 255) + 1;
|
|
||||||
|
|
||||||
int spriteIndex;
|
// 2 for size
|
||||||
for (spriteIndex = 0; spriteIndex < paletteChildCount; ++spriteIndex)
|
// 5 for width, height, palette length
|
||||||
|
// + 8 bytes per sprite for offset x/y, width, and height
|
||||||
|
stream.setOffset(stream.getLength() - 7 - spriteCount * 8);
|
||||||
|
|
||||||
|
width = stream.readUnsignedShort();
|
||||||
|
height = stream.readUnsignedShort();
|
||||||
|
int paletteLength = (stream.readUnsignedByte() & 255) + 1;
|
||||||
|
|
||||||
|
for (int i = 0; i < spriteCount; ++i)
|
||||||
{
|
{
|
||||||
sprites[spriteIndex].setOffsetX(stream.readUnsignedShort());
|
sprites[i].setOffsetX(stream.readUnsignedShort());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (spriteIndex = 0; spriteIndex < paletteChildCount; ++spriteIndex)
|
for (int i = 0; i < spriteCount; ++i)
|
||||||
{
|
{
|
||||||
sprites[spriteIndex].setOffsetY(stream.readUnsignedShort());
|
sprites[i].setOffsetY(stream.readUnsignedShort());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (spriteIndex = 0; spriteIndex < paletteChildCount; ++spriteIndex)
|
for (int i = 0; i < spriteCount; ++i)
|
||||||
{
|
{
|
||||||
sprites[spriteIndex].setWidth(stream.readUnsignedShort());
|
sprites[i].setWidth(stream.readUnsignedShort());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (spriteIndex = 0; spriteIndex < paletteChildCount; ++spriteIndex)
|
for (int i = 0; i < spriteCount; ++i)
|
||||||
{
|
{
|
||||||
sprites[spriteIndex].setHeight(stream.readUnsignedShort());
|
sprites[i].setHeight(stream.readUnsignedShort());
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.setOffset(stream.getLength() - 7 - paletteChildCount * 8 - (var3 - 1) * 3);
|
// same as above + 3 bytes for each palette entry, except for the first one (which is transparent)
|
||||||
loadedPalette = new int[var3];
|
stream.setOffset(stream.getLength() - 7 - spriteCount * 8 - (paletteLength - 1) * 3);
|
||||||
|
loadedPalette = new int[paletteLength];
|
||||||
|
|
||||||
for (spriteIndex = 1; spriteIndex < var3; ++spriteIndex)
|
for (int i = 1; i < paletteLength; ++i)
|
||||||
{
|
{
|
||||||
loadedPalette[spriteIndex] = stream.read24BitInt();
|
loadedPalette[i] = stream.read24BitInt();
|
||||||
if (0 == loadedPalette[spriteIndex])
|
|
||||||
|
if (loadedPalette[i] == 0)
|
||||||
{
|
{
|
||||||
loadedPalette[spriteIndex] = 1;
|
loadedPalette[i] = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.setOffset(0);
|
stream.setOffset(0);
|
||||||
|
|
||||||
for (spriteIndex = 0; spriteIndex < paletteChildCount; ++spriteIndex)
|
for (int i = 0; i < spriteCount; ++i)
|
||||||
{
|
{
|
||||||
SpriteDefinition def = sprites[spriteIndex];
|
SpriteDefinition def = sprites[i];
|
||||||
int width = def.getWidth();
|
int width = def.getWidth();
|
||||||
int height = def.getHeight();
|
int height = def.getHeight();
|
||||||
int dimmension = width * height;
|
// XXX OFFSETS
|
||||||
byte[] loadPixels = new byte[dimmension];
|
int dimension = width * height;
|
||||||
int var4 = stream.readUnsignedByte();
|
byte[] pixelPaletteIndicies = new byte[dimension];
|
||||||
int var5;
|
byte[] pixelAlphas = new byte[dimension];
|
||||||
if (var4 == 0)
|
|
||||||
|
int flags = stream.readUnsignedByte();
|
||||||
|
|
||||||
|
if ((flags & FLAG_VERTICAL) == 0)
|
||||||
{
|
{
|
||||||
for (var5 = 0; var5 < dimmension; ++var5)
|
// read horizontally
|
||||||
|
for (int j = 0; j < dimension; ++j)
|
||||||
{
|
{
|
||||||
loadPixels[var5] = (byte) stream.readByte();
|
pixelPaletteIndicies[j] = stream.readByte();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (1 == var4)
|
else
|
||||||
{
|
{
|
||||||
for (var5 = 0; var5 < width; ++var5)
|
// read vertically
|
||||||
|
for (int j = 0; j < width; ++j)
|
||||||
{
|
{
|
||||||
for (int var8 = 0; var8 < height; ++var8)
|
for (int k = 0; k < height; ++k)
|
||||||
{
|
{
|
||||||
loadPixels[width * var8 + var5] = (byte) stream.readByte();
|
pixelPaletteIndicies[width * k + j] = stream.readByte();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
def.setPixels(loadPixels);
|
|
||||||
|
// read alphas
|
||||||
|
if ((flags & FLAG_ALPHA) != 0)
|
||||||
|
{
|
||||||
|
if ((flags & FLAG_VERTICAL) == 0)
|
||||||
|
{
|
||||||
|
// read horizontally
|
||||||
|
for (int j = 0; j < dimension; ++j)
|
||||||
|
{
|
||||||
|
pixelAlphas[j] = stream.readByte();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// read vertically
|
||||||
|
for (int j = 0; j < width; ++j)
|
||||||
|
{
|
||||||
|
for (int k = 0; k < height; ++k)
|
||||||
|
{
|
||||||
|
pixelAlphas[width * k + j] = stream.readByte();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// everything non-zero is opaque
|
||||||
|
for (int j = 0; j < dimension; ++j)
|
||||||
|
{
|
||||||
|
int index = pixelPaletteIndicies[j];
|
||||||
|
|
||||||
|
if (index != 0)
|
||||||
|
pixelAlphas[j] = (byte) 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def.setPixels(pixelPaletteIndicies);
|
||||||
|
def.setAlphas(pixelAlphas);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,8 +30,7 @@
|
|||||||
|
|
||||||
package net.runelite.cache.renderable;
|
package net.runelite.cache.renderable;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.image.*;
|
|
||||||
import net.runelite.cache.definitions.SpriteDefinition;
|
import net.runelite.cache.definitions.SpriteDefinition;
|
||||||
|
|
||||||
public class RGBSprite
|
public class RGBSprite
|
||||||
@@ -94,15 +93,19 @@ public class RGBSprite
|
|||||||
sprite.spriteWidth = def.getWidth();
|
sprite.spriteWidth = def.getWidth();
|
||||||
sprite.spriteHeight = def.getHeight();
|
sprite.spriteHeight = def.getHeight();
|
||||||
|
|
||||||
int dimmension = sprite.spriteWidth * sprite.spriteHeight;
|
int dimension = sprite.spriteWidth * sprite.spriteHeight;
|
||||||
byte[] pixels = def.getPixels();
|
byte[] pixels = def.getPixels();
|
||||||
|
|
||||||
int[] palette = def.getLoader().getLoadedPalette();
|
int[] palette = def.getLoader().getLoadedPalette();
|
||||||
|
byte[] alphas = def.getAlphas();
|
||||||
|
|
||||||
sprite.pixels = new int[dimmension];
|
sprite.pixels = new int[dimension];
|
||||||
|
|
||||||
for (int pos = 0; pos < dimmension; ++pos)
|
for (int pos = 0; pos < dimension; ++pos)
|
||||||
{
|
{
|
||||||
sprite.pixels[pos] = palette[pixels[pos] & 255];
|
int index = pixels[pos] & 0xff;
|
||||||
|
|
||||||
|
sprite.pixels[pos] = palette[index] | (alphas[pos] << 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
return sprite;
|
return sprite;
|
||||||
@@ -110,43 +113,8 @@ public class RGBSprite
|
|||||||
|
|
||||||
public BufferedImage getBufferedImage()
|
public BufferedImage getBufferedImage()
|
||||||
{
|
{
|
||||||
BufferedImage bi = new BufferedImage(spriteWidth, spriteHeight, BufferedImage.TYPE_INT_RGB);
|
BufferedImage bi = new BufferedImage(spriteWidth, spriteHeight, BufferedImage.TYPE_INT_ARGB);
|
||||||
bi.setRGB(0, 0, spriteWidth, spriteHeight, pixels, 0, spriteWidth);
|
bi.setRGB(0, 0, spriteWidth, spriteHeight, pixels, 0, spriteWidth);
|
||||||
Image img = makeColorTransparent(bi, new Color(0, 0, 0));
|
return bi;
|
||||||
BufferedImage trans = imageToBufferedImage(img);
|
|
||||||
return trans;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Image makeColorTransparent(BufferedImage im, final Color color)
|
|
||||||
{
|
|
||||||
final int markerRGB = color.getRGB() | 0xFF000000;
|
|
||||||
|
|
||||||
RGBImageFilter filter = new RGBImageFilter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public final int filterRGB(int x, int y, int rgb)
|
|
||||||
{
|
|
||||||
if ((rgb | 0xFF000000) == markerRGB)
|
|
||||||
{
|
|
||||||
return 0x00FFFFFF & rgb;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return rgb;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ImageProducer ip = new FilteredImageSource(im.getSource(), filter);
|
|
||||||
return Toolkit.getDefaultToolkit().createImage(ip);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static BufferedImage imageToBufferedImage(Image image)
|
|
||||||
{
|
|
||||||
BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB);
|
|
||||||
Graphics2D g2 = bufferedImage.createGraphics();
|
|
||||||
g2.drawImage(image, 0, 0, null);
|
|
||||||
g2.dispose();
|
|
||||||
return bufferedImage;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,6 +64,8 @@ public class SpriteLoaderTest
|
|||||||
java.io.File base = StoreLocation.LOCATION,
|
java.io.File base = StoreLocation.LOCATION,
|
||||||
outDir = folder.newFolder();
|
outDir = folder.newFolder();
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
try (Store store = new Store(base))
|
try (Store store = new Store(base))
|
||||||
{
|
{
|
||||||
store.load();
|
store.load();
|
||||||
@@ -96,10 +98,14 @@ public class SpriteLoaderTest
|
|||||||
java.io.File targ = new java.io.File(outDir, a.getArchiveId() + "-" + i + ".png");
|
java.io.File targ = new java.io.File(outDir, a.getArchiveId() + "-" + i + ".png");
|
||||||
targ.mkdirs();
|
targ.mkdirs();
|
||||||
ImageIO.write(image, "png", targ);
|
ImageIO.write(image, "png", targ);
|
||||||
|
|
||||||
|
++count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info("Dumped to {}", outDir);
|
Assert.assertTrue(count > 3000);
|
||||||
|
|
||||||
|
logger.info("Dumped {} sprites to {}", count, outDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user