package com.vitco.util.graphic; import com.vitco.util.misc.IntegerTools; import gnu.trove.map.hash.TIntObjectHashMap; /** * Basic and Advanced functionality for textures. */ public class TextureTools { // helper - determine "offsets" for a texture // Note: "Front width offset" means how many "equal" columns are at the left side of the texture (similar for others...) public static int[] getOffsets(int width, int height, boolean checkHeight, TIntObjectHashMap<int[]> pixels) { int[] result = new int[]{0, width}; if (checkHeight) { // fetch front offset Integer[] scanline = new Integer[width]; loop: for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int[] pixel = pixels.get(IntegerTools.makeInt(x, y)); if (pixel != null) { if (scanline[x] == null) { scanline[x] = pixel[2]; } else if (scanline[x] != pixel[2]) { break loop; } } } result[0] = y + 1; } // fetch back offset scanline = new Integer[width]; loop: for (int y = height - 1; y >= 0; y--) { for (int x = 0; x < width; x++) { int[] pixel = pixels.get(IntegerTools.makeInt(x, y)); if (pixel != null) { if (scanline[x] == null) { scanline[x] = pixel[2]; } else if (scanline[x] != pixel[2]) { break loop; } } } result[1] = y; } // adjust offsets (i.e. when the texture has only one color) if (result[0] > result[1]) { result[0] = 0; result[1] = height; } else if (result[0] == result[1]) { if (result[0] > (height - result[1])) { result[0] = 0; } else { result[1] = height; } } } else { // fetch front offset Integer[] scanline = new Integer[height]; loop: for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { int[] pixel = pixels.get(IntegerTools.makeInt(x, y)); if (pixel != null) { if (scanline[y] == null) { scanline[y] = pixel[2]; } else if (scanline[y] != pixel[2]) { break loop; } } } result[0] = x + 1; } // fetch back offset scanline = new Integer[height]; loop: for (int x = width - 1; x >= 0; x--) { for (int y = 0; y < height; y++) { int[] pixel = pixels.get(IntegerTools.makeInt(x, y)); if (pixel != null) { if (scanline[y] == null) { scanline[y] = pixel[2]; } else if (scanline[y] != pixel[2]) { break loop; } } } result[1] = x; } // adjust offsets (i.e. when the texture has only one color) if (result[0] > result[1]) { result[0] = 0; result[1] = width; } else if (result[0] == result[1]) { if (result[0] > (width - result[1])) { result[0] = 0; } else { result[1] = width; } } } return result; } // helper - compress function (with offsets that are ignored) // returns the new dimension and the compression factor (by that the valid area was compressed) // format (width, height, factor) public static int[] compress(int width, int height, int front, int back, boolean useHeight, TIntObjectHashMap<int[]> pixels) { int factor = 1; // compute inside dist int dist = back - front; if (dist > 1) { if (useHeight) { for (int d = 1, len = dist / 2 + 1; d < len; d++) { loop: if (dist % d == 0) { // potential new pixel representation TIntObjectHashMap<int[]> result = new TIntObjectHashMap<int[]>(); // the step width that would be compressed to one pixel int stepSize = dist / d; // loop over all steps for (int y = 0; y < d; y++) { // loop over width for (int x = 0; x < width; x++) { Integer lastColor = null; // loop over step for (int i = 0; i < stepSize; i++) { // compute the current point int p = IntegerTools.makeInt(x, front + y * stepSize + i); // obtain the pixel int[] pixel = pixels.get(p); if (pixel != null) { // check if the pixel color is consistent through this step if (lastColor == null) { lastColor = pixel[2]; result.put(IntegerTools.makeInt(x, front + y), new int[]{x, front + y, pixel[2]}); } else { if (lastColor != pixel[2]) { break loop; } } } } } } // -- loop was successful // add offset pixel to result array for (int x = 0; x < width; x++) { for (int y = 0; y < front; y++) { int p = IntegerTools.makeInt(x, y); int[] pixel = pixels.get(p); if (pixel != null) { result.put(p, pixel); } } for (int y = back; y < height; y++) { int p = IntegerTools.makeInt(x, y); int[] pixel = pixels.get(p); if (pixel != null) { int[] newPixel = new int[]{ x , y - dist + dist / stepSize, pixel[2] }; result.put(IntegerTools.makeInt(newPixel[0], newPixel[1]), newPixel); } } } pixels.clear(); pixels.putAll(result); height = front + (height - back) + dist / stepSize; factor = stepSize; break; } } } else { for (int d = 1, len = dist / 2 + 1; d < len; d++) { loop: if (dist % d == 0) { // potential new pixel representation TIntObjectHashMap<int[]> result = new TIntObjectHashMap<int[]>(); // the step width that would be compressed to one pixel int stepSize = dist / d; // loop over all steps for (int x = 0; x < d; x++) { // loop over height for (int y = 0; y < height; y++) { Integer lastColor = null; // loop over step for (int i = 0; i < stepSize; i++) { // compute the current point int p = IntegerTools.makeInt(front + x * stepSize + i, y); // obtain the pixel int[] pixel = pixels.get(p); if (pixel != null) { // check if the pixel color is consistent through this step if (lastColor == null) { lastColor = pixel[2]; result.put(IntegerTools.makeInt(front + x, y), new int[]{front + x, y, pixel[2]}); } else { if (lastColor != pixel[2]) { break loop; } } } } } } // -- loop was successful // add offset pixel to result array for (int y = 0; y < height; y++) { for (int x = 0; x < front; x++) { int p = IntegerTools.makeInt(x, y); int[] pixel = pixels.get(p); if (pixel != null) { result.put(p, pixel); } } for (int x = back; x < width; x++) { int p = IntegerTools.makeInt(x, y); int[] pixel = pixels.get(p); if (pixel != null) { int[] newPixel = new int[]{ x - dist + dist / stepSize, y, pixel[2] }; result.put(IntegerTools.makeInt(newPixel[0], newPixel[1]), newPixel); } } } pixels.clear(); pixels.putAll(result); width = front + (width - back) + dist / stepSize; factor = stepSize; break; } } } } return new int[]{width, height, factor}; } }