package org.ripple.power.ui.projector.action.sprite;
import java.awt.Color;
import java.awt.Image;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.PathIterator;
import java.awt.image.BufferedImage;
import java.awt.image.PixelGrabber;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import org.ripple.power.ui.graphics.LColor;
import org.ripple.power.ui.graphics.LGraphics;
import org.ripple.power.ui.graphics.LImage;
import org.ripple.power.ui.graphics.geom.RectBox;
import org.ripple.power.ui.projector.core.LObject;
import org.ripple.power.utils.CollectionUtils;
import org.ripple.power.utils.GraphicsUtils;
public class SpriteImage extends LObject implements ISprite {
/**
*
*/
private static final long serialVersionUID = -1982900453464314946L;
public boolean visible = true;
public BufferedImage serializablelImage;
private boolean isOpaque = true;
private Polygon newPy;
private SpriteRotate sRotate;
private int makePolygonInterval;
private Polygon[] polygons;
private final static int transparent = 0xff000000;
private LImage image;
protected int[] pixels;
protected int transform;
protected int width, height;
// 精灵透明度
protected int alpha = 255;
public SpriteImage(String fileName) {
this(fileName, 0, 0);
}
public SpriteImage(Image img) {
this(img, 0, 0);
}
public SpriteImage(Image img, int x, int y) {
this(img, x, y, img.getWidth(null), img.getHeight(null));
}
public SpriteImage(Image img, int x, int y, int width, int height) {
this.setLocation(x, y);
this.width = width;
this.height = height;
this.bind(img);
}
public SpriteImage(SpriteImage image) {
this(image, 0, 0);
}
public SpriteImage(String fileName, int x, int y) {
this(GraphicsUtils.loadNotCacheImage(fileName), x, y);
}
public SpriteImage(SpriteImage image, int x, int y) {
this.setLocation(x, y);
this.width = image.width;
this.height = image.height;
this.bind(image.serializablelImage);
}
public SpriteImage(int x, int y, int width, int height) {
this.setLocation(x, y);
this.width = width;
this.height = height;
this.bind(null, Color.RED);
}
private void bind(Image img) {
bind(img, null);
}
private void bind(Image img, Color color) {
int size = width * height;
pixels = new int[width * height];
transform = Sprite.TRANS_NONE;
PixelGrabber pixelGrabber = new PixelGrabber(img, 0, 0, width, height,
pixels, 0, width);
if (width < 48 && height < 48) {
makePolygonInterval = 1;
} else {
makePolygonInterval = 3;
}
boolean result = false;
try {
result = pixelGrabber.grabPixels();
} catch (InterruptedException ex) {
}
if (result) {
int pixel;
for (int i = 0; i < size; i++) {
pixels[i] = LColor.premultiply(pixel = pixels[i]);
if (isOpaque && (pixel >>> 24) < 255) {
isOpaque = false;
}
}
}
BufferedImage awtImage = null;
if (isOpaque) {
awtImage = GraphicsUtils
.newAwtRGBImage(pixels, width, height, size);
} else {
awtImage = GraphicsUtils.newAwtARGBImage(pixels, width, height,
size);
}
image = new LImage(serializablelImage = awtImage);
}
/**
* 变更掩码中数据为指定角度
*
* @param transform
*/
public Mask updateMask(int t) {
this.transform = t;
if (transform == Sprite.TRANS_NONE) {
return createMask(pixels, width, height);
}
int[] trans = new int[pixels.length];
int w = width;
int h = height;
if (transform != Sprite.TRANS_NONE) {
sRotate = makeRotate(transform);
trans = sRotate.makeSpritePixels();
w = sRotate.getWidth();
h = sRotate.getHeight();
}
return createMask(trans, w, h);
}
private SpriteRotate makeRotate(int t) {
int angle;
switch (t) {
case LGraphics.TRANS_ROT90:
angle = 90;
break;
case LGraphics.TRANS_ROT180:
angle = 180;
break;
case LGraphics.TRANS_ROT270:
angle = 270;
break;
case LGraphics.TRANS_MIRROR:
angle = -360;
break;
case LGraphics.TRANS_MIRROR_ROT90:
angle = -90;
break;
case LGraphics.TRANS_MIRROR_ROT180:
angle = -180;
break;
case LGraphics.TRANS_MIRROR_ROT270:
angle = -270;
break;
default:
throw new RuntimeException("Illegal transformation: " + transform);
}
return rotate(angle);
}
/**
* 生成像素掩码
*
* @param pixels
* @param w
* @param h
* @return
*/
private Mask createMask(int[] pixels, int w, int h) {
int width = w;
int height = h;
Mask data = new Mask(width, height);
boolean[][] mask = new boolean[height][width];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
mask[y][x] = (pixels[x + w * y] & transparent) == transparent;
}
}
data.setData(mask);
return data;
}
/**
* 判定指定像素点是否透明
*
* @param x
* @param y
* @return
*/
public boolean isTransparent(int x, int y) {
if (x < 0 || y < 0 || x >= width || y >= height) {
return true;
} else if (isOpaque) {
return false;
} else {
return (pixels[x + width * y] & transparent) == transparent;
}
}
/**
* 绘制图像到当前画布
*/
public void createUI(LGraphics g) {
if (visible) {
g.drawImage(serializablelImage, x(), y());
}
}
/**
* 旋转当前精灵像素为指定角度并返回
*
* @param angle
* @return
*/
public int[] rotatePixels(int angle) {
return rotate(angle).makePixels();
}
/**
* 旋转当前精灵像素为指定角度并返回精灵像素旋转用类
*
* @param angle
* @return
*/
public SpriteRotate rotate(int angle) {
if (sRotate == null) {
sRotate = new SpriteRotate(this, width, height, angle == -1 ? 0
: angle);
} else {
sRotate.setAngle(angle);
}
return sRotate;
}
public SpriteRotate getRotate() {
if (sRotate == null) {
rotate(0);
}
return sRotate;
}
/**
* 以当前图像为基础,创建一个指定旋转角度的Polygon
*
* @param angle
* @return
*/
public Polygon rotatePolygon(int x, int y, int angle) {
SpriteRotate sr = rotate(angle);
int[] pixels = sr.makePixels();
return makePolygon(pixels, x, y, 0, 0, sr.getWidth(), sr.getHeight());
}
/**
* 返回一个对应指定旋转角度,指定坐标的Polygon
*
* @param x
* @param y
* @param t
* @return
*/
protected Polygon getPolygon(int x, int y, int t) {
if (polygons == null) {
polygons = new Polygon[Sprite.TRANS_MIRROR_ROT90 + 1];
}
Polygon py = polygons[t];
if (py == null) {
if (t != Sprite.TRANS_NONE) {
sRotate = makeRotate(t);
int[] trans = sRotate.makeSpritePixels();
py = makePolygon(trans, 0, 0, 0, 0, sRotate.getWidth(),
sRotate.getHeight());
} else {
py = makePolygon(0, 0);
}
polygons[t] = py;
}
if (newPy == null) {
newPy = new Polygon(py.xpoints, py.ypoints, py.npoints);
} else {
int npoints = py.npoints;
newPy.npoints = npoints;
newPy.xpoints = CollectionUtils.copyOf(py.xpoints, npoints);
newPy.ypoints = CollectionUtils.copyOf(py.ypoints, npoints);
}
newPy.translate(x, y);
return newPy;
}
public Polygon makePolygon(int x, int y) {
return makePolygon(pixels, x, y, 0, 0, width, height);
}
public Polygon makePolygon(int startX, int startY, int limitX, int limitY) {
return makePolygon(pixels, 0, 0, startX, startY, limitX, limitY);
}
public Polygon makePolygon(int[] pixels, int offsetX, int offsetY,
int startX, int startY, int limitX, int limitY) {
Polygon split = null;
Polygon result = null;
ArrayList<Point[]> points = new ArrayList<Point[]>();
Point[] tmpPoint;
int x1, y1, x2, y2;
boolean secondPoint;
for (int y = startY; y < limitY - makePolygonInterval; y += makePolygonInterval) {
secondPoint = false;
x1 = y1 = -1;
x2 = y2 = -1;
for (int x = startX; x < limitX; x++) {
if (!secondPoint) {
if ((pixels[x + limitX * y] & transparent) == transparent) {
x1 = x;
y1 = y;
secondPoint = true;
}
} else {
if ((pixels[x + limitX * y] & transparent) == transparent) {
x2 = x;
y2 = y;
}
}
}
if (secondPoint && (x2 > -1) && (y2 > -1)) {
tmpPoint = new Point[2];
tmpPoint[0] = new Point(offsetX + x1, offsetY + y1);
tmpPoint[1] = new Point(offsetX + x2, offsetY + y2);
points.add(tmpPoint);
}
}
split = makePolygon(points);
if (split != null) {
points = new ArrayList<Point[]>();
for (int x = startX; x < limitX - makePolygonInterval; x += makePolygonInterval) {
secondPoint = false;
x1 = y1 = -1;
x2 = y2 = -1;
for (int y = startY; y < limitY; y++) {
if (!secondPoint) {
if ((pixels[x + limitX * y] & transparent) == transparent) {
x1 = x;
y1 = y;
secondPoint = true;
}
} else {
if ((pixels[x + limitX * y] & transparent) == transparent) {
x2 = x;
y2 = y;
}
}
}
if (secondPoint && (x2 > -1) && (y2 > -1)) {
tmpPoint = new Point[2];
tmpPoint[0] = new Point(offsetX + x1, offsetY + y1);
tmpPoint[1] = new Point(offsetX + x2, offsetY + y2);
points.add(tmpPoint);
}
}
result = makePolygon(points);
}
return result;
}
/**
* 将指定的Point集合注入Polygon当中
*
* @param points
* @return
*/
private static Polygon makePolygon(ArrayList<Point[]> points) {
Polygon polygon = null;
if (!points.isEmpty()) {
int size = points.size();
polygon = new Polygon();
for (int i = 0; i < size; i++) {
Point p = ((Point[]) points.get(i))[0];
polygon.addPoint(p.x, p.y);
}
for (int i = size - 1; i >= 0; i--) {
Point p = ((Point[]) points.get(i))[1];
polygon.addPoint(p.x, p.y);
}
}
return filterPolygon(polygon);
}
/**
*
* @param polygon
* @return
*/
private static Polygon filterPolygon(Polygon polygon) {
Area area = new Area(polygon);
Polygon newPoly = new Polygon();
PathIterator it = area.getPathIterator(
AffineTransform.getTranslateInstance(0, 0), 0);
float[] coords = new float[6];
LinkedHashSet<String> set = new LinkedHashSet<String>();
while (!it.isDone()) {
it.currentSegment(coords);
Point v = new Point((int) coords[0], (int) coords[1]);
if (!set.contains(v.toString())) {
newPoly.addPoint(v.x, v.y);
set.add(v.toString());
}
it.next();
}
return newPoly;
}
public BufferedImage getImage() {
return serializablelImage;
}
public void update(long timer) {
}
public boolean isVisible() {
return visible;
}
public void setVisible(boolean visible) {
this.visible = visible;
}
public void move(int x, int y) {
this.move(x, y);
}
public void setLocation(int x, int y) {
this.setX(x);
this.setY(y);
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
/**
* 设定当前透明度(0-255)
*
* @param alpha
*/
public void setAlphaValue(int alpha) {
if (alpha < 0 || alpha > 255) {
return;
}
if (isOpaque) {
for (int i = 0; i < pixels.length; i++) {
if (pixels[i] != 0xffffff) {
pixels[i] = LColor.premultiply(pixels[i], alpha);
}
}
} else {
for (int i = 0; i < pixels.length; i++) {
if (pixels[i] != 0xffffff) {
int[] rgb = LColor.getRGBs(pixels[i]);
pixels[i] = LColor.getARGB(rgb[0], rgb[1], rgb[2], alpha);
}
}
}
this.alpha = alpha;
}
/**
* 设定当前透明度(0.0F-1.0F)
*
* @param alpha
*/
public void setAlpha(float alpha) {
setAlphaValue((int) (255 * alpha));
}
/**
* 返回当前透明度(0-255)
*
* @return
*/
public int getAlphaValue() {
return alpha;
}
/**
* 返回当前透明度(0.0F-1.0F)
*
* @return
*/
public float getAlpha() {
return (alpha * 1.0f) / 255;
}
public int[] getData() {
return CollectionUtils.copyOf(pixels);
}
public SpriteImage copy() {
return new SpriteImage(this);
}
public RectBox getCollisionBox() {
return getRect(x(), y(), width, height);
}
public boolean isOpaque() {
return isOpaque;
}
public int getMakePolygonInterval() {
return makePolygonInterval;
}
public void setMakePolygonInterval(int makePolygonInterval) {
if (makePolygonInterval <= 0) {
makePolygonInterval = 1;
}
this.makePolygonInterval = makePolygonInterval;
}
public LImage getBitmap() {
return new LImage(serializablelImage);
}
public LImage getLImage() {
return image;
}
public void dispose() {
if (image != null) {
image.dispose();
image = null;
}
if (serializablelImage != null) {
serializablelImage = null;
}
if (pixels != null) {
pixels = null;
}
}
}