Added external PNG to JaGex sprite format support

This commit is contained in:
woahscam 2023-06-07 23:58:20 -04:00
parent 6ae6b19e44
commit 7b3d3f0919
3 changed files with 250 additions and 0 deletions

View file

@ -7,6 +7,7 @@ import rt4.Font;
import java.awt.*; import java.awt.*;
import java.awt.event.*; import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList; import java.util.ArrayList;
import static rt4.MathUtils.clamp; import static rt4.MathUtils.clamp;
@ -81,6 +82,10 @@ public class API {
return Inv.getObjectSprite(outlineType, objId, drawText, qty, shadowIntensity); return Inv.getObjectSprite(outlineType, objId, drawText, qty, shadowIntensity);
} }
public static Sprite GetSpriteFromPNG(BufferedImage image) {
return SpritePNGLoader.getImageIndexedSprite(image);
}
public static WindowMode GetWindowMode() { public static WindowMode GetWindowMode() {
int mode = DisplayMode.getWindowMode(); int mode = DisplayMode.getWindowMode();
switch(mode) { switch(mode) {

View file

@ -0,0 +1,106 @@
package plugin.api;
import rt4.GlAlphaSprite;
import rt4.SoftwareAlphaSprite;
import rt4.Sprite;
import java.awt.image.BufferedImage;
import java.awt.image.DirectColorModel;
import java.awt.image.PixelGrabber;
import java.util.ArrayList;
import java.util.List;
public class SpritePNGLoader {
/**
* Converts the buffered image into a sprite image and returns it
*
* @param image The image to be converted
* @return The buffered image as a sprite image
*/
public static SpritePixels getImageSpritePixels(BufferedImage image) {
int[] pixels = new int[image.getWidth() * image.getHeight()];
try {
PixelGrabber g = new PixelGrabber(image, 0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth());
g.setColorModel(new DirectColorModel(32, 0xff0000, 0xff00, 0xff, 0xff000000));
g.grabPixels();
// Make any fully transparent pixels fully black, because the sprite draw routines
// check for == 0, not actual transparency
for (int i = 0; i < pixels.length; i++) {
if ((pixels[i] & 0xFF000000) == 0) {
pixels[i] = 0;
}
}
} catch (InterruptedException ex) {
System.err.println("PixelGrabber was interrupted: " + ex);
}
return new SpritePixels(pixels, image.getWidth(), image.getHeight());
}
/**
* Converts an image into an {@code IndexedSprite} instance.
* <p>
* The passed in image can only have at max 255 different colors.
*
* @param image The image to be converted
* @return The image as an {@code IndexedSprite}
*/
public static Sprite getImageIndexedSprite(BufferedImage image) {
final byte[] pixels = new byte[image.getWidth() * image.getHeight()];
final List<Integer> palette = new ArrayList<>();
/*
When drawing the indexed sprite, palette idx 0 is seen as fully transparent,
so pad the palette out so that our colors start at idx 1.
*/
palette.add(0);
final int[] sourcePixels = image.getRGB(0, 0,
image.getWidth(), image.getHeight(),
null, 0, image.getWidth());
/*
Build a color palette and assign the pixels to positions in the palette.
*/
for (int j = 0; j < sourcePixels.length; j++) {
final int argb = sourcePixels[j];
final int a = (argb >> 24) & 0xFF;
final int rgb = argb & 0xFF_FF_FF;
// Default to not drawing the pixel.
int paletteIdx = 0;
// If the pixel is fully opaque, draw it.
if (a == 0xFF) {
paletteIdx = palette.indexOf(rgb);
if (paletteIdx == -1) {
paletteIdx = palette.size();
palette.add(rgb);
}
}
pixels[j] = (byte) paletteIdx;
}
if (palette.size() > 256) {
throw new RuntimeException("Passed in image had " + (palette.size() - 1)
+ " different colors, exceeding the max of 255.");
}
//int[] imgPalette = palette.stream().mapToInt(i -> i).toArray();
Sprite sprites;
//IndexedSprite sprite;
if (API.IsHD()) { //width, height, xOffsets[local16], yOffsets[local16], innerWidths[local16], innerHeights[local16], local38
sprites = new GlAlphaSprite(image.getWidth(), image.getHeight(), 0, 0, image.getWidth(), image.getHeight(), sourcePixels);
// sprite = new GlIndexedSprite(image.getWidth(), image.getHeight(), 0, 0, image.getWidth(), image.getHeight(), pixels, imgPalette);
} else {
sprites = new SoftwareAlphaSprite(image.getWidth(), image.getHeight(), 0, 0, image.getWidth(), image.getHeight(), sourcePixels);
// sprite = new SoftwareIndexedSprite(image.getWidth(), image.getHeight(), 0, 0, image.getWidth(), image.getHeight(), pixels, imgPalette);
}
return sprites;
}
}

View file

@ -0,0 +1,139 @@
/*
* Copyright (c) 2018, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 plugin.api;
import java.awt.image.BufferedImage;
class SpritePixels {
public int[] pixels;
public int width;
public int height;
public int offsetX;
int offsetY;
public SpritePixels(int[] var1, int var2, int var3) {
this.pixels = var1;
this.width = var2;
this.height = var3;
this.offsetY = 0;
this.offsetX = 0;
}
public SpritePixels(int var1, int var2) {
this(new int[var2 * var1], var1, var2);
}
public void drawBorder(int color) {
int[] newPixels = new int[this.width * this.height];
int pixelIndex = 0;
for (int y = 0; y < this.height; ++y) {
for (int x = 0; x < this.width; ++x) {
int pixel = this.pixels[pixelIndex];
if (pixel == 0) {
// W
if (x > 0 && this.pixels[pixelIndex - 1] != 0) {
pixel = color;
}
// N
else if (y > 0 && this.pixels[pixelIndex - this.width] != 0) {
pixel = color;
}
// E
else if (x < this.width - 1 && this.pixels[pixelIndex + 1] != 0) {
pixel = color;
}
// S
else if (y < this.height - 1 && this.pixels[pixelIndex + this.width] != 0) {
pixel = color;
}
}
newPixels[pixelIndex++] = pixel;
}
}
this.pixels = newPixels;
}
public void drawShadow(int color) {
for (int y = this.height - 1; y > 0; --y) {
int rowOffset = y * this.width;
for (int x = this.width - 1; x > 0; --x) {
// if *this* pixel is black/unset AND the pixel to the NW isn't black/unset
if (this.pixels[x + rowOffset] == 0 && this.pixels[x + rowOffset - 1 - this.width] != 0) {
this.pixels[x + rowOffset] = color;
}
}
}
}
static void method5843(int[] rasterizerPixels, int[] spritePixels, int var2, int var3, int pixelIndex, int width, int height, int var7, int var8) {
int var9 = -(width >> 2);
width = -(width & 3);
for (int var10 = -height; var10 < 0; ++var10) {
for (int i = var9 * 4; i < 0; ++i) {
var2 = spritePixels[var3++];
if (var2 != 0) {
rasterizerPixels[pixelIndex++] = var2;
} else {
++pixelIndex;
}
}
for (int i = width; i < 0; ++i) {
var2 = spritePixels[var3++];
if (var2 != 0) {
rasterizerPixels[pixelIndex++] = var2;
} else {
++pixelIndex;
}
}
pixelIndex += var7;
var3 += var8;
}
}
public BufferedImage toBufferedImage() {
int[] transPixels = new int[pixels.length];
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
for (int i = 0; i < pixels.length; i++) {
if (pixels[i] != 0) {
transPixels[i] = pixels[i] | 0xff000000;
}
}
img.setRGB(0, 0, width, height, transPixels, 0, width);
return img;
}
}