diff --git a/client/src/main/java/plugin/api/API.java b/client/src/main/java/plugin/api/API.java index 7a43fb3..57208be 100644 --- a/client/src/main/java/plugin/api/API.java +++ b/client/src/main/java/plugin/api/API.java @@ -7,6 +7,7 @@ import rt4.Font; import java.awt.*; import java.awt.event.*; +import java.awt.image.BufferedImage; import java.util.ArrayList; import static rt4.MathUtils.clamp; @@ -81,6 +82,10 @@ public class API { return Inv.getObjectSprite(outlineType, objId, drawText, qty, shadowIntensity); } + public static Sprite GetSpriteFromPNG(BufferedImage image) { + return SpritePNGLoader.getImageIndexedSprite(image); + } + public static WindowMode GetWindowMode() { int mode = DisplayMode.getWindowMode(); switch(mode) { diff --git a/client/src/main/java/plugin/api/SpritePNGLoader.java b/client/src/main/java/plugin/api/SpritePNGLoader.java new file mode 100644 index 0000000..c937a2c --- /dev/null +++ b/client/src/main/java/plugin/api/SpritePNGLoader.java @@ -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. + *

+ * 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 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; + } +} \ No newline at end of file diff --git a/client/src/main/java/plugin/api/SpritePixels.java b/client/src/main/java/plugin/api/SpritePixels.java new file mode 100644 index 0000000..203fdcb --- /dev/null +++ b/client/src/main/java/plugin/api/SpritePixels.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2018, Adam + * 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; + } + +} \ No newline at end of file