diff options
author | Rafael Marçalo <public@rafaelmarcalo.xyz> | 2024-09-05 16:31:33 +0100 |
---|---|---|
committer | Rafael Marçalo <public@rafaelmarcalo.xyz> | 2024-09-05 16:31:33 +0100 |
commit | 8b67572ad7e1508341345dc46a2597e9fa170cbb (patch) | |
tree | 8f37c4d60ce0f07b9eaf30be34f39298da97b242 /src/com/pkrandom/GFXFunctions.java | |
parent | b65f4a80da28e7ec4de16c8b1abf906e8d7be2c5 (diff) |
Diffstat (limited to 'src/com/pkrandom/GFXFunctions.java')
-rw-r--r-- | src/com/pkrandom/GFXFunctions.java | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/src/com/pkrandom/GFXFunctions.java b/src/com/pkrandom/GFXFunctions.java new file mode 100644 index 0000000..e5d5426 --- /dev/null +++ b/src/com/pkrandom/GFXFunctions.java @@ -0,0 +1,173 @@ +package com.pkrandom; + +/*----------------------------------------------------------------------------*/ +/*-- GFXFunctions.java - functions relating to graphics rendering. --*/ +/*-- Mainly used for rendering the sprites. --*/ +/*-- --*/ +/*-- Part of "Universal Pokemon Randomizer ZX" by the UPR-ZX team --*/ +/*-- Pokemon and any associated names and the like are --*/ +/*-- trademark and (C) Nintendo 1996-2020. --*/ +/*-- --*/ +/*-- Contains code based on "pokemon-x-y-icons", copyright (C) CatTrinket --*/ +/*-- --*/ +/*-- The custom code written here is licensed under the terms of the GPL: --*/ +/*-- --*/ +/*-- This program is free software: you can redistribute it and/or modify --*/ +/*-- it under the terms of the GNU General Public License as published by --*/ +/*-- the Free Software Foundation, either version 3 of the License, or --*/ +/*-- (at your option) any later version. --*/ +/*-- --*/ +/*-- This program is distributed in the hope that it will be useful, --*/ +/*-- but WITHOUT ANY WARRANTY; without even the implied warranty of --*/ +/*-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --*/ +/*-- GNU General Public License for more details. --*/ +/*-- --*/ +/*-- You should have received a copy of the GNU General Public License --*/ +/*-- along with this program. If not, see <http://www.gnu.org/licenses/>. --*/ +/*----------------------------------------------------------------------------*/ + +import java.awt.image.BufferedImage; +import java.util.LinkedList; +import java.util.Queue; + +public class GFXFunctions { + + public static BufferedImage drawTiledImage(byte[] data, int[] palette, int width, int height, int bpp) { + return drawTiledImage(data, palette, 0, width, height, 8, 8, bpp); + } + + public static BufferedImage drawTiledImage(byte[] data, int[] palette, int offset, int width, int height, int bpp) { + return drawTiledImage(data, palette, offset, width, height, 8, 8, bpp); + } + + private static BufferedImage drawTiledImage(byte[] data, int[] palette, int offset, int width, int height, + int tileWidth, int tileHeight, int bpp) { + if (bpp != 1 && bpp != 2 && bpp != 4 && bpp != 8) { + throw new IllegalArgumentException("Bits per pixel must be a multiple of 2."); + } + int pixelsPerByte = 8 / bpp; + if (width * height / pixelsPerByte + offset > data.length) { + throw new IllegalArgumentException("Invalid input image."); + } + + int bytesPerTile = tileWidth * tileHeight / pixelsPerByte; + int numTiles = width * height / (tileWidth * tileHeight); + int widthInTiles = width / tileWidth; + + BufferedImage bim = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + + for (int tile = 0; tile < numTiles; tile++) { + int tileX = tile % widthInTiles; + int tileY = tile / widthInTiles; + for (int yT = 0; yT < tileHeight; yT++) { + for (int xT = 0; xT < tileWidth; xT++) { + int value = data[tile * bytesPerTile + yT * tileWidth / pixelsPerByte + xT / pixelsPerByte + offset] & 0xFF; + if (pixelsPerByte != 1) { + value = (value >>> (xT % pixelsPerByte) * bpp) & ((1 << bpp) - 1); + } + bim.setRGB(tileX * tileWidth + xT, tileY * tileHeight + yT, palette[value]); + } + } + } + + return bim; + } + + public static BufferedImage drawTiledZOrderImage(byte[] data, int[] palette, int offset, int width, int height, int bpp) { + return drawTiledZOrderImage(data, palette, offset, width, height, 8, 8, bpp); + } + + private static BufferedImage drawTiledZOrderImage(byte[] data, int[] palette, int offset, int width, int height, + int tileWidth, int tileHeight, int bpp) { + if (bpp != 1 && bpp != 2 && bpp != 4 && bpp != 8) { + throw new IllegalArgumentException("Bits per pixel must be a multiple of 2."); + } + int pixelsPerByte = 8 / bpp; + if (width * height / pixelsPerByte + offset > data.length) { + throw new IllegalArgumentException("Invalid input image."); + } + + int bytesPerTile = tileWidth * tileHeight / pixelsPerByte; + int numTiles = width * height / (tileWidth * tileHeight); + int widthInTiles = width / tileWidth; + + BufferedImage bim = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + + for (int tile = 0; tile < numTiles; tile++) { + int tileX = tile % widthInTiles; + int tileY = tile / widthInTiles; + for (int yT = 0; yT < tileHeight; yT++) { + for (int xT = 0; xT < tileWidth; xT++) { + int value = data[tile * bytesPerTile + yT * tileWidth / pixelsPerByte + xT / pixelsPerByte + offset] & 0xFF; + if (pixelsPerByte != 1) { + value = (value >>> ((xT+1) % pixelsPerByte) * bpp) & ((1 << bpp) - 1); + } + + int withinTile = yT * tileWidth + xT; + int subX = (withinTile & 0b000001) | + (withinTile & 0b000100) >>> 1 | + (withinTile & 0b010000) >>> 2; + int subY = (withinTile & 0b000010) >>> 1 | + (withinTile & 0b001000) >>> 2 | + (withinTile & 0b100000) >>> 3; + bim.setRGB(tileX * tileWidth + subX, tileY * tileHeight + subY, palette[value]); + } + } + } + + return bim; + } + + public static int conv16BitColorToARGB(int palValue) { + int red = (int) ((palValue & 0x1F) * 8.25); + int green = (int) (((palValue & 0x3E0) >> 5) * 8.25); + int blue = (int) (((palValue & 0x7C00) >> 10) * 8.25); + return 0xFF000000 | (red << 16) | (green << 8) | blue; + } + + public static int conv3DS16BitColorToARGB(int palValue) { + int alpha = (int) ((palValue & 0x1) * 0xFF); + int blue = (int) (((palValue & 0x3E) >> 1) * 8.25); + int green = (int) (((palValue & 0x7C0) >> 6) * 8.25); + int red = (int) (((palValue & 0xF800) >> 11) * 8.25); + return (alpha << 24) | (red << 16) | (green << 8) | blue; + } + + public static void pseudoTransparency(BufferedImage img, int transColor) { + int width = img.getWidth(); + int height = img.getHeight(); + Queue<Integer> visitPixels = new LinkedList<>(); + boolean[][] queued = new boolean[width][height]; + + for (int x = 0; x < width; x++) { + queuePixel(x, 0, width, height, visitPixels, queued); + queuePixel(x, height - 1, width, height, visitPixels, queued); + } + + for (int y = 0; y < height; y++) { + queuePixel(0, y, width, height, visitPixels, queued); + queuePixel(width - 1, y, width, height, visitPixels, queued); + } + + while (!visitPixels.isEmpty()) { + int nextPixel = visitPixels.poll(); + int x = nextPixel % width; + int y = nextPixel / width; + if (img.getRGB(x, y) == transColor) { + img.setRGB(x, y, 0); + queuePixel(x - 1, y, width, height, visitPixels, queued); + queuePixel(x + 1, y, width, height, visitPixels, queued); + queuePixel(x, y - 1, width, height, visitPixels, queued); + queuePixel(x, y + 1, width, height, visitPixels, queued); + } + } + } + + private static void queuePixel(int x, int y, int width, int height, Queue<Integer> queue, boolean[][] queued) { + if (x >= 0 && x < width && y >= 0 && y < height && !queued[x][y]) { + queue.add((y) * width + (x)); + queued[x][y] = true; + } + } + +} |