gdx-studio
git clone https://git.pyrossh.dev/gdx-studio
An IDE for creating Games using libgdx and Java supported on all platforms Android, iOS, Desktop
src_libs/com/badlogic/gdx/tools/imagepacker/ColorBleedEffect.java
| a62d533 | 1 | |
| a62d533 | 2 | package com.badlogic.gdx.tools.imagepacker; |
| a62d533 | 3 | |
| a62d533 | 4 | import com.badlogic.gdx.tools.imagepacker.ColorBleedEffect.Mask.MaskIterator; |
| a62d533 | 5 | |
| a62d533 | 6 | import java.awt.image.BufferedImage; |
| a62d533 | 7 | import java.util.NoSuchElementException; |
| a62d533 | 8 | |
| a62d533 | 9 | /** @author Ruben Garat |
| a62d533 | 10 | * @author Ariel Coppes |
| a62d533 | 11 | * @author Nathan Sweet */ |
| a62d533 | 12 | public class ColorBleedEffect { |
| a62d533 | 13 | static int TO_PROCESS = 0; |
| a62d533 | 14 | static int IN_PROCESS = 1; |
| a62d533 | 15 | static int REALDATA = 2; |
| a62d533 | 16 | static int[][] offsets = { {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}}; |
| a62d533 | 17 | |
| a62d533 | 18 | ARGBColor color = new ARGBColor(); |
| a62d533 | 19 | |
| a62d533 | 20 | public BufferedImage processImage (BufferedImage image, int maxIterations) { |
| a62d533 | 21 | int width = image.getWidth(); |
| a62d533 | 22 | int height = image.getHeight(); |
| a62d533 | 23 | |
| a62d533 | 24 | BufferedImage processedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); |
| a62d533 | 25 | int[] rgb = image.getRGB(0, 0, width, height, null, 0, width); |
| a62d533 | 26 | Mask mask = new Mask(rgb); |
| a62d533 | 27 | |
| a62d533 | 28 | int iterations = 0; |
| a62d533 | 29 | int lastPending = -1; |
| a62d533 | 30 | while (mask.pendingSize > 0 && mask.pendingSize != lastPending && iterations < maxIterations) { |
| a62d533 | 31 | lastPending = mask.pendingSize; |
| a62d533 | 32 | executeIteration(rgb, mask, width, height); |
| a62d533 | 33 | iterations++; |
| a62d533 | 34 | } |
| a62d533 | 35 | |
| a62d533 | 36 | processedImage.setRGB(0, 0, width, height, rgb, 0, width); |
| a62d533 | 37 | return processedImage; |
| a62d533 | 38 | } |
| a62d533 | 39 | |
| a62d533 | 40 | private void executeIteration (int[] rgb, Mask mask, int width, int height) { |
| a62d533 | 41 | MaskIterator iterator = mask.new MaskIterator(); |
| a62d533 | 42 | while (iterator.hasNext()) { |
| a62d533 | 43 | int pixelIndex = iterator.next(); |
| a62d533 | 44 | int x = pixelIndex % width; |
| a62d533 | 45 | int y = pixelIndex / width; |
| a62d533 | 46 | int r = 0, g = 0, b = 0; |
| a62d533 | 47 | int count = 0; |
| a62d533 | 48 | |
| a62d533 | 49 | for (int i = 0, n = offsets.length; i < n; i++) { |
| a62d533 | 50 | int[] offset = offsets[i]; |
| a62d533 | 51 | int column = x + offset[0]; |
| a62d533 | 52 | int row = y + offset[1]; |
| a62d533 | 53 | |
| a62d533 | 54 | if (column < 0 || column >= width || row < 0 || row >= height) continue; |
| a62d533 | 55 | |
| a62d533 | 56 | int currentPixelIndex = getPixelIndex(width, column, row); |
| a62d533 | 57 | if (mask.getMask(currentPixelIndex) == REALDATA) { |
| a62d533 | 58 | color.argb = rgb[currentPixelIndex]; |
| a62d533 | 59 | r += color.red(); |
| a62d533 | 60 | g += color.green(); |
| a62d533 | 61 | b += color.blue(); |
| a62d533 | 62 | count++; |
| a62d533 | 63 | } |
| a62d533 | 64 | } |
| a62d533 | 65 | |
| a62d533 | 66 | if (count != 0) { |
| a62d533 | 67 | color.setARGBA(0, r / count, g / count, b / count); |
| a62d533 | 68 | rgb[pixelIndex] = color.argb; |
| a62d533 | 69 | iterator.markAsInProgress(); |
| a62d533 | 70 | } |
| a62d533 | 71 | } |
| a62d533 | 72 | |
| a62d533 | 73 | iterator.reset(); |
| a62d533 | 74 | } |
| a62d533 | 75 | |
| a62d533 | 76 | private int getPixelIndex (int width, int x, int y) { |
| a62d533 | 77 | return y * width + x; |
| a62d533 | 78 | } |
| a62d533 | 79 | |
| a62d533 | 80 | static class Mask { |
| a62d533 | 81 | int[] data, pending, changing; |
| a62d533 | 82 | int pendingSize, changingSize; |
| a62d533 | 83 | |
| a62d533 | 84 | Mask (int[] rgb) { |
| a62d533 | 85 | data = new int[rgb.length]; |
| a62d533 | 86 | pending = new int[rgb.length]; |
| a62d533 | 87 | changing = new int[rgb.length]; |
| a62d533 | 88 | ARGBColor color = new ARGBColor(); |
| a62d533 | 89 | for (int i = 0; i < rgb.length; i++) { |
| a62d533 | 90 | color.argb = rgb[i]; |
| a62d533 | 91 | if (color.alpha() == 0) { |
| a62d533 | 92 | data[i] = TO_PROCESS; |
| a62d533 | 93 | pending[pendingSize] = i; |
| a62d533 | 94 | pendingSize++; |
| a62d533 | 95 | } else |
| a62d533 | 96 | data[i] = REALDATA; |
| a62d533 | 97 | } |
| a62d533 | 98 | } |
| a62d533 | 99 | |
| a62d533 | 100 | int getMask (int index) { |
| a62d533 | 101 | return data[index]; |
| a62d533 | 102 | } |
| a62d533 | 103 | |
| a62d533 | 104 | int removeIndex (int index) { |
| a62d533 | 105 | if (index >= pendingSize) throw new IndexOutOfBoundsException(String.valueOf(index)); |
| a62d533 | 106 | int value = pending[index]; |
| a62d533 | 107 | pendingSize--; |
| a62d533 | 108 | pending[index] = pending[pendingSize]; |
| a62d533 | 109 | return value; |
| a62d533 | 110 | } |
| a62d533 | 111 | |
| a62d533 | 112 | class MaskIterator { |
| a62d533 | 113 | private int index; |
| a62d533 | 114 | |
| a62d533 | 115 | boolean hasNext () { |
| a62d533 | 116 | return index < pendingSize; |
| a62d533 | 117 | } |
| a62d533 | 118 | |
| a62d533 | 119 | int next () { |
| a62d533 | 120 | if (index >= pendingSize) throw new NoSuchElementException(String.valueOf(index)); |
| a62d533 | 121 | return pending[index++]; |
| a62d533 | 122 | } |
| a62d533 | 123 | |
| a62d533 | 124 | void markAsInProgress () { |
| a62d533 | 125 | index--; |
| a62d533 | 126 | changing[changingSize] = removeIndex(index); |
| a62d533 | 127 | changingSize++; |
| a62d533 | 128 | } |
| a62d533 | 129 | |
| a62d533 | 130 | void reset () { |
| a62d533 | 131 | index = 0; |
| a62d533 | 132 | for (int i = 0; i < changingSize; i++) { |
| a62d533 | 133 | int index = changing[i]; |
| a62d533 | 134 | data[index] = REALDATA; |
| a62d533 | 135 | } |
| a62d533 | 136 | changingSize = 0; |
| a62d533 | 137 | } |
| a62d533 | 138 | } |
| a62d533 | 139 | } |
| a62d533 | 140 | |
| a62d533 | 141 | static class ARGBColor { |
| a62d533 | 142 | int argb = 0xff000000; |
| a62d533 | 143 | |
| a62d533 | 144 | public int red () { |
| a62d533 | 145 | return (argb >> 16) & 0xFF; |
| a62d533 | 146 | } |
| a62d533 | 147 | |
| a62d533 | 148 | public int green () { |
| a62d533 | 149 | return (argb >> 8) & 0xFF; |
| a62d533 | 150 | } |
| a62d533 | 151 | |
| a62d533 | 152 | public int blue () { |
| a62d533 | 153 | return (argb >> 0) & 0xFF; |
| a62d533 | 154 | } |
| a62d533 | 155 | |
| a62d533 | 156 | public int alpha () { |
| a62d533 | 157 | return (argb >> 24) & 0xff; |
| a62d533 | 158 | } |
| a62d533 | 159 | |
| a62d533 | 160 | public void setARGBA (int a, int r, int g, int b) { |
| a62d533 | 161 | if (a < 0 || a > 255 || r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) |
| a62d533 | 162 | throw new IllegalArgumentException("Invalid RGBA: " + r + ", " + g + "," + b + "," + a); |
| a62d533 | 163 | argb = ((a & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | ((b & 0xFF) << 0); |
| a62d533 | 164 | } |
| a62d533 | 165 | } |
| a62d533 | 166 | } |