package com.kreative.paint.material.sprite; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Paint; import java.awt.Point; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class Sprite { private final SpriteSheet spriteSheet; private final SpriteTreeNode treeNode; private final SpriteSheetSlice slice; public Sprite(BufferedImage image, int hx, int hy, ColorTransform transform) { this.spriteSheet = new SpriteSheet(image, hx, hy, transform); this.treeNode = this.spriteSheet.root.children.get(0); this.slice = this.spriteSheet.slices.get(0); } public Sprite(SpriteSheet spriteSheet, SpriteTreeNode treeNode) { this.spriteSheet = spriteSheet; this.treeNode = treeNode; this.slice = spriteSheet.getSlice(treeNode.index); } public String getName() { return treeNode.name; } public int getDuration() { return treeNode.duration; } public int getWidth() { return slice.cellWidth; } public int getHeight() { return slice.cellHeight; } public int getHotspotX() { return slice.hotspotX; } public int getHotspotY() { return slice.hotspotY; } public ColorTransform getColorTransform() { return slice.transform; } private Sprite[] spriteCache = null; private void makeSpriteCache() { if (treeNode instanceof SpriteTreeNode.Branch) { SpriteTreeNode.Branch b = (SpriteTreeNode.Branch)treeNode; int n = b.getChildCount(); spriteCache = new Sprite[n]; for (int i = 0; i < n; i++) { SpriteTreeNode c = b.getChild(i); spriteCache[i] = new Sprite(spriteSheet, c); } } else { spriteCache = new Sprite[0]; } } public int getChildCount() { if (spriteCache == null) makeSpriteCache(); return spriteCache.length; } public Sprite getChild(int index) { if (spriteCache == null) makeSpriteCache(); if (index < 0 || index >= spriteCache.length) return this; return spriteCache[index]; } public Sprite getChildByPath(int... path) { Sprite c = this; for (int i : path) c = c.getChild(i); return c; } public List<Sprite> getChildren() { if (spriteCache == null) makeSpriteCache(); List<Sprite> children = new ArrayList<Sprite>(); children.addAll(Arrays.asList(spriteCache)); return children; } private int[] rawPixels = null; private Image rawImage = null; private Cursor rawVCursor = null; private Cursor rawOCursor = null; private int[] preparedPixels = null; private Image preparedImage = null; private Cursor preparedVCursor = null; private Cursor preparedOCursor = null; public int[] getRawPixels() { if (rawPixels == null) { int sx = slice.startX; int sy = slice.startY; int cw = slice.cellWidth; int ch = slice.cellHeight; BufferedImage bi = spriteSheet.image; int[] raw = new int[cw * ch]; bi.getRGB(sx, sy, cw, ch, raw, 0, cw); rawPixels = raw; } return rawPixels; } public Image getRawImage() { if (rawImage == null) { int cw = slice.cellWidth; int ch = slice.cellHeight; int bt = BufferedImage.TYPE_INT_ARGB; BufferedImage bi = new BufferedImage(cw, ch, bt); int[] raw = getRawPixels(); bi.setRGB(0, 0, cw, ch, raw, 0, cw); rawImage = bi; } return rawImage; } public Cursor getRawCursor(boolean outline) { Cursor c = (outline ? rawOCursor : rawVCursor); if (c == null) { Toolkit tk = Toolkit.getDefaultToolkit(); Dimension d = createCursorDimension(tk, outline); if (d == null) { c = Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR); } else { int[] ca = getRawPixels(); String name = super.toString() + "-raw"; c = createCursor(tk, d, ca, name, outline); } if (outline) rawOCursor = c; else rawVCursor = c; } return c; } public int[] getPreparedPixels() { if (preparedPixels == null) { ColorTransform tx = slice.transform; int[] raw = getRawPixels(); int[] prep = new int[raw.length]; tx.preparePixels(prep, 0, raw, 0, raw.length); preparedPixels = prep; } return preparedPixels; } public Image getPreparedImage() { if (preparedImage == null) { int cw = slice.cellWidth; int ch = slice.cellHeight; int bt = BufferedImage.TYPE_INT_ARGB; BufferedImage bi = new BufferedImage(cw, ch, bt); int[] prep = getPreparedPixels(); bi.setRGB(0, 0, cw, ch, prep, 0, cw); preparedImage = bi; } return preparedImage; } public Cursor getPreparedCursor(boolean outline) { Cursor c = (outline ? preparedOCursor : preparedVCursor); if (c == null) { Toolkit tk = Toolkit.getDefaultToolkit(); Dimension d = createCursorDimension(tk, outline); if (d == null) { c = Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR); } else { int[] ca = getPreparedPixels(); String name = super.toString() + "-prep"; c = createCursor(tk, d, ca, name, outline); } if (outline) preparedOCursor = c; else preparedVCursor = c; } return c; } public int[] getPixels( int k, int w, int r, int y, int g, int c, int b, int m ) { ColorTransform tx = slice.transform; int[] prep = getPreparedPixels(); int[] ret = new int[prep.length]; tx.replacePixels( ret, 0, prep, 0, prep.length, k, w, r, y, g, c, b, m ); return ret; } public Image getImage( int k, int w, int r, int y, int g, int c, int b, int m ) { int cw = slice.cellWidth; int ch = slice.cellHeight; int bt = BufferedImage.TYPE_INT_ARGB; BufferedImage bi = new BufferedImage(cw, ch, bt); int[] ret = getPixels(k, w, r, y, g, c, b, m); bi.setRGB(0, 0, cw, ch, ret, 0, cw); return bi; } public Cursor getCursor( int k, int w, int r, int y, int g, int c, int b, int m, boolean outline ) { Toolkit tk = Toolkit.getDefaultToolkit(); Dimension d = createCursorDimension(tk, outline); if (d == null) { return Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR); } else { int[] ca = getPixels(k, w, r, y, g, c, b, m); String name = super.toString() + "-" + k + "-" + w + "-" + r + "-" + y + "-" + g + "-" + c + "-" + b + "-" + m; return createCursor(tk, d, ca, name, outline); } } public void paint(Graphics2D gr, int gx, int gy) { paint(gr, gx, gy, gr.getPaint(), gr.getBackground()); } public void paint(Graphics2D gr, int gx, int gy, Paint fg, Paint bg) { paint(gr, gx, gy, fg, bg, null, null, null, null, null, null); } public void paint( Graphics2D gr, int gx, int gy, Paint k, Paint w, Paint r, Paint y, Paint g, Paint c, Paint b, Paint m ) { gx -= slice.hotspotX; gy -= slice.hotspotY; int cw = slice.cellWidth; int ch = slice.cellHeight; int[] prep = getPreparedPixels(); int[] ret = new int[prep.length]; slice.transform.replacePixels( ret, 0, cw, prep, 0, cw, new Rectangle(gx, gy, cw, ch), gr.getTransform(), gr.getRenderingHints(), k, w, r, y, g, c, b, m ); int bt = BufferedImage.TYPE_INT_ARGB; BufferedImage bi = new BufferedImage(cw, ch, bt); bi.setRGB(0, 0, cw, ch, ret, 0, cw); gr.drawImage(bi, null, gx, gy); } public void invalidate() { spriteCache = null; rawPixels = null; rawImage = null; rawVCursor = null; rawOCursor = null; preparedPixels = null; preparedImage = null; preparedVCursor = null; preparedOCursor = null; } private Dimension createCursorDimension(Toolkit tk, boolean outline) { int cw = slice.cellWidth; int ch = slice.cellHeight; if (outline) { cw += 2; ch += 2; } Dimension d = tk.getBestCursorSize(cw, ch); if (d.width < cw || d.height < ch) { d = tk.getBestCursorSize(cw + cw, ch + ch); if (d.width < cw || d.height < ch) { return null; } } return d; } private Cursor createCursor(Toolkit tk, Dimension d, int[] ca, String name, boolean outline) { int cw = slice.cellWidth; int ch = slice.cellHeight; int hx = slice.hotspotX; int hy = slice.hotspotY; if (outline) { cw += 2; ch += 2; hx++; hy++; ca = createCursorOutline(ca); name += "-outline"; } int bt = BufferedImage.TYPE_INT_ARGB; BufferedImage ci = new BufferedImage(d.width, d.height, bt); ci.setRGB(0, 0, cw, ch, ca, 0, cw); return tk.createCustomCursor(ci, new Point(hx, hy), name); } private int[] createCursorOutline(int[] pixels) { int cw = slice.cellWidth; int ch = slice.cellHeight; int[] ca = new int[(cw + 2) * (ch + 2)]; for (int sy = 0, dy = cw + 2, iy = 0; iy < ch; sy += cw, dy += cw + 2, iy++) { for (int sx = sy, dx = dy + 1, ix = 0; ix < cw; sx++, dx++, ix++) { if ((pixels[sx] >>> 24) != 0) { ca[dx] = pixels[sx]; } } } for (int ay = cw + 2, iy = 0; iy < ch; ay += cw + 2, iy++) { for (int ax = ay + 1, ix = 0; ix < cw; ax++, ix++) { if ((ca[ax] >>> 24) != 0) { if ((ca[ax - 1] >>> 24) == 0) ca[ax - 1] = 0xBECC1E; if ((ca[ax + 1] >>> 24) == 0) ca[ax + 1] = 0xBECC1E; if ((ca[ax - cw - 2] >>> 24) == 0) ca[ax - cw - 2] = 0xBECC1E; if ((ca[ax + cw + 2] >>> 24) == 0) ca[ax + cw + 2] = 0xBECC1E; } } } for (int i = 0; i < ca.length; i++) { if (ca[i] == 0xBECC1E) { ca[i] = -1; } } return ca; } }