package loon.canvas;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import loon.LRelease;
import loon.LSystem;
import loon.LTexture;
import loon.Support;
import loon.geom.Polygon;
import loon.geom.RectI;
import loon.geom.Shape;
import loon.geom.Triangle2f;
import loon.geom.Vector2f;
import loon.utils.ArrayByte;
import loon.utils.CollectionUtils;
import loon.utils.MathUtils;
import loon.utils.TArray;
/**
* 跨平台处理像素用类(不同平台内部渲染实现通常有细节差异,某些时候不如自己写同一方法更能保证效果一致,比如转换代码到C#或C++平台时,
* 而且一些第三方支持库也可能没有类似于Image的本地图像渲染支持(如使用MonoGame或Unity3D为基础平台),这时就可以直接套用此类的实现)
*/
public class Pixmap extends Limit implements LRelease {
public final static int SRC_IN = 0;
public final static int SRC_OUT = 1;
public final static int SRC_OVER = 2;
private int _composite = -1;
private Canvas tmpCanvas = null;
public Image getImage() {
if (tmpCanvas == null) {
tmpCanvas = LSystem.base().graphics().createCanvas(getWidth(), getHeight());
}
tmpCanvas.image.setPixmap(this);
return tmpCanvas.image;
}
public LTexture toTexture() {
return getImage().texture();
}
public static Pixmap createImage(int w, int h) {
return new Pixmap(w, h, true);
}
public static Pixmap createImage(int w, int h, boolean hasAlpha) {
return new Pixmap(w, h, hasAlpha);
}
public static Pixmap getResize(Pixmap image, int w, int h) {
if (image == null) {
return null;
}
if (image._width == w && image._height == h) {
return image;
}
Pixmap result = new Pixmap(w, h, image._hasAlpha);
result.drawPixmap(image, 0, 0, w, h, 0, 0, image.getWidth(), image.getHeight());
return result;
}
public static Pixmap drawClipImage(Pixmap image, int objectWidth, int objectHeight, int x1, int y1, int x2,
int y2) {
Pixmap buffer = new Pixmap(objectWidth, objectHeight, true);
buffer.drawPixmap(image, 0, 0, objectWidth, objectHeight, x1, y1, x2 - x1, y2 - y1);
return buffer;
}
public static Pixmap drawClipImage(Pixmap image, int objectWidth, int objectHeight, int x, int y) {
Pixmap buffer = new Pixmap(objectWidth, objectHeight, true);
buffer.drawPixmap(image, 0, 0, objectWidth, objectHeight, x, y, objectWidth, objectHeight);
return buffer;
}
public static Pixmap drawCropImage(Pixmap image, int x, int y, int objectWidth, int objectHeight) {
Pixmap buffer = new Pixmap(objectWidth, objectHeight, true);
buffer.drawPixmap(image, 0, 0, objectWidth, objectHeight, x, y, objectWidth, objectHeight);
return buffer;
}
private RectI temp_rect = new RectI();
private int _baseColor = LColor.DEF_COLOR;
private int _background = LColor.black.getRGB();
private int _transparent = 0;
private boolean _isClosed;
private int[] _drawPixels;
private int _translateX, _translateY, _width, _height, size;
private LColor xorColor;
private boolean xorMode;
private int xorRGB;
private float _baseAlpha = 1f;
private boolean _hasAlpha;
private RectI defClip;
private RectI clip;
public Pixmap(int w, int h, boolean hasAlpha) {
this.set(new int[w * h], w, h, hasAlpha);
}
public Pixmap(int[] pixelsData, int w, int h, boolean hasAlpha) {
this.set(pixelsData, w, h, hasAlpha);
}
private void set(int[] pixelsData, int w, int h, boolean hasAlpha) {
this._width = w;
this._height = h;
this._drawPixels = pixelsData;
this._hasAlpha = hasAlpha;
this.size = _drawPixels.length;
if (hasAlpha) {
this._transparent = 0;
} else {
this._transparent = LColor.TRANSPARENT;
}
_transparent = 0;
this.defClip = new RectI(0, 0, _width, _height);
this.clip = new RectI(0, 0, _width, _height);
}
/**
* 清空屏幕为指定颜色
*
* @param c
*/
public Pixmap clearDraw(int c) {
if (_isClosed) {
return this;
}
for (int i = 0; i < this.size; i++) {
drawPoint(_drawPixels, i, c);
}
return this;
}
public Pixmap setBackground(int color) {
this._background = color;
return this;
}
/**
* 清空屏幕
*
*/
public Pixmap clearDraw() {
return clearDraw(_background);
}
/**
* 清空屏幕
*
*/
public Pixmap clear() {
for (int i = 0; i < size; i++) {
_drawPixels[i] = 0;
}
return this;
}
/**
* 清空屏幕
*
*/
public Pixmap fill() {
return clearDraw(_baseColor);
}
/**
* 向指定坐标插入像素
*
* @param x
* @param y
*/
public Pixmap putPixel(int x, int y) {
return putPixel(x, y, _baseColor);
}
/**
* 向指定坐标插入像素
*
* @param x
* @param y
*/
public Pixmap putPixel(int x, int y, int c) {
if (_isClosed) {
return this;
}
if (x < 0 || x >= _width || y < 0 || y >= _height) {
return this;
} else {
drawPoint(x, y, c);
}
return this;
}
/**
* 获得指定区域的RGB色彩
*
* @param pixels
* @return
*/
public int[] getRGB(int[] pixels) {
getRGB(0, 0, _width, _height, pixels, 0, _width);
return pixels;
}
/**
* 获得指定区域的RGB色彩
*
* @param x
* @param y
* @param w
* @param h
* @return
*/
public int[] getRGB(int x, int y, int w, int h) {
int[] pixels = new int[w * h];
getRGB(x, y, w, h, pixels, 0, w);
return pixels;
}
/**
* 获得指定区域的RGB色彩
*
* @param offset
* @param stride
* @param x
* @param y
* @param width
* @param height
* @return
*/
public int[] getRGB(int offset, int stride, int x, int y, int width, int height) {
int pixels[] = new int[width * height];
getRGB(x, y, width, height, pixels, offset, stride);
return pixels;
}
/**
* 获得指定区域的RGB色彩
*
* @param x
* @param y
* @param arrays
* @return
*/
public int[] getRGB(int x, int y, int[] pixels) {
int pixel = getPixel(x, y);
if (pixels == null) {
pixels = new int[3];
}
pixels[0] = (pixel >> 16) & 0xff;
pixels[1] = (pixel >> 8) & 0xff;
pixels[2] = (pixel) & 0xff;
return pixels;
}
/**
* 获得指定区域的RGB色彩
*
* @param startX
* @param startY
* @param w
* @param h
* @param rgbArray
* @param offset
* @param scansize
* @return
*/
public int[] getRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize) {
int yoff = offset;
int off;
if (rgbArray == null) {
rgbArray = new int[offset + h * scansize];
}
for (int y = startY; y < startY + h; y++, yoff += scansize) {
off = yoff;
for (int x = startX; x < startX + w; x++) {
rgbArray[off++] = getPixel(x, y);
}
}
return rgbArray;
}
/**
* 设定指定区域的RGB色彩
*
* @param startX
* @param startY
* @param w
* @param h
* @param rgbArray
* @param offset
* @param scansize
*/
public Pixmap setRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize) {
int yoff = offset;
int off;
for (int y = startY; y < startY + h; y++, yoff += scansize) {
off = yoff;
for (int x = startX; x < startX + w; x++) {
int pixel = rgbArray[off++];
putPixel(x, y, pixel);
}
}
return this;
}
/**
* 设定指定区域的RGB色彩
*
* @param pixels
* @param width
* @param height
*/
public Pixmap setRGB(int[] pixels, int width, int height) {
return setRGB(0, 0, width, height, pixels, 0, width);
}
/**
* 设定指定区域的RGB色彩
*
* @param pixels
* @param offset
* @param stride
* @param x
* @param y
* @param width
* @param height
*/
public Pixmap setRGB(int[] pixels, int offset, int stride, int x, int y, int width, int height) {
return setRGB(x, y, width, height, pixels, offset, stride);
}
/**
* 设定指定区域的RGB色彩
*
* @param pixels
* @param x
* @param y
* @param w
* @param h
* @return
*/
public int[] setRGB(int[] pixels, int x, int y, int w, int h) {
setRGB(x, y, w, h, pixels, 0, w);
return pixels;
}
/**
* 设定指定区域的RGB色彩
*
* @param x
* @param y
* @param pixels
*/
public Pixmap setRGB(int x, int y, int[] pixels) {
return putPixel(x, y, (255 << 24) | (pixels[0] << 16) | (pixels[1] << 8) | pixels[2]);
}
/**
* 设定指定区域的RGB色彩
*
* @param rgb
* @param x
* @param y
*/
public Pixmap setRGB(int rgb, int x, int y) {
return putPixel(x, y, rgb);
}
/**
* 获得指定位置像素
*
* @param x
* @param y
* @return
*/
public int getPixel(int x, int y) {
if (_isClosed) {
return -1;
}
if (x < 0 || x >= _width || y < 0 || y >= _height) {
return -1;
} else {
return _drawPixels[y * _width + x];
}
}
/**
* 让像素沿着X轴方向旋转
*/
public Pixmap mirrorX() {
if (_isClosed) {
return this;
}
int h = this._height;
int w = MathUtils.floor(this._width / (float) 2);
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
this.drawPoint(this._width - x - 1, y, this.getData(x, y));
}
}
return this;
}
/**
* 让像素沿着Y轴方向旋转
*/
public Pixmap mirrorY() {
if (_isClosed) {
return this;
}
int h = MathUtils.floor(this._height / (float) 2);
int w = this._width;
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
this.drawPoint(x, this._height - y - 1, this.getData(x, y));
}
}
return this;
}
/**
* 镜像翻转当前Pixmap为新图
*
* @return
*/
public Pixmap mirror() {
return mirror(true, false);
}
/**
* 水平翻转当前Pixmap为新图
*
* @return
*/
public Pixmap flip() {
return mirror(false, true);
}
/**
* 翻转当前Pixmap为新图
*
* @param mirror
* @param flip
* @return
*/
public Pixmap mirror(boolean mirror, boolean flip) {
if (_isClosed) {
return null;
}
Pixmap pixel = new Pixmap(_width, _height, _hasAlpha);
int[] pixels = pixel._drawPixels;
int index = 0;
int pixelIndex = (mirror ? _width - 1 : 0) + (flip ? _width * (_height - 1) : 0);
int flag = (mirror ? -1 : 1);
int offset = (mirror ? _width * 2 : 0) + (flip ? -_width * 2 : 0);
pixel._width = _width;
pixel._height = _height;
pixel._transparent = _transparent;
for (int j = 0; j < _height;) {
for (int i = 0; i < _width;) {
pixels[pixelIndex] = _drawPixels[index];
i++;
index++;
pixelIndex += flag;
}
j++;
pixelIndex += offset;
}
return pixel;
}
/**
* 将当前Pixmap克隆为新的Pixmap
*
* @return
*/
public Pixmap cpy() {
return copy(0, 0, _width, _height);
}
/**
* 从当前Pixmap中copy指定范围像素为新的Pixmap
*
* @param x
* @param y
* @param w
* @param h
* @return
*/
public Pixmap copy(int x, int y, int w, int h) {
if (_isClosed) {
return null;
}
Pixmap pixel = new Pixmap(w, h, _hasAlpha);
pixel._width = w;
pixel._height = h;
pixel.drawPixmap(this, 0, 0, w, h, x, y);
if (x < 0) {
w -= x;
x = 0;
}
if (y < 0) {
h -= y;
y = 0;
}
if (x + w > _width) {
w -= (x + w) - _width;
}
if (y + h > _height) {
h -= (y + h) - _height;
}
try {
for (int size = 0; size < h; size++) {
System.arraycopy(_drawPixels, (y + size) * _width + x, pixel._drawPixels, size * pixel._width, w);
}
} catch (IndexOutOfBoundsException e) {
}
return pixel;
}
/**
* 拆分当前Pixmap为指定数量的瓦片
*
* @param row
* @param col
* @return
*/
public Pixmap[] split(int row, int col) {
if (_isClosed) {
return null;
}
int count = row * col;
int w = _width / row;
int h = _height / col;
Pixmap[] pixels = new Pixmap[count];
for (int i = 0; i < count; i++) {
int x = (i % row) * w;
int y = (i / row) * h;
pixels[i] = copy(x, y, w, h);
}
return pixels;
}
/**
* 修正图像显示位置
*
* @param x
* @param y
*/
public Pixmap translate(int x, int y) {
if (_isClosed) {
return this;
}
_translateX = x;
_translateY = y;
if (defClip != null) {
defClip.x += _translateX;
defClip.y += _translateY;
clip.x = MathUtils.min(clip.x + _translateX, _width);
clip.y = MathUtils.min(clip.y + _translateY, _height);
clip.width = MathUtils.min(clip.width + _translateX, _width - _translateX);
clip.height = MathUtils.min(clip.height + _translateY, _height - _translateY);
}
return this;
}
public float getAlpha() {
return alpha();
}
// 以实际渲染颜色的alpha为优先返回
public float alpha() {
return ((_baseColor >> 24) & 0xFF) / 255f;
}
public Pixmap setAlpha(float alpha) {
if (alpha < 0.01f) {
alpha = 0.01f;
_baseAlpha = 0;
} else if (alpha > 1f) {
alpha = 1f;
_baseAlpha = 1f;
} else {
this._baseAlpha = alpha;
}
int ialpha = (int) (0xFF * MathUtils.clamp(alpha, 0, 1));
this._baseColor = (ialpha << 24) | (_baseColor & 0xFFFFFF);
return this;
}
public int color() {
return _baseColor;
}
public LColor getColor() {
return new LColor(_baseColor);
}
public Pixmap setColor(LColor color) {
int argb = color.getARGB();
setColor(argb);
return this;
}
public Pixmap setColor(int r, int g, int b) {
return setColor(LColor.getRGB(r, g, b));
}
public Pixmap setColor(int r, int g, int b, int a) {
return setColor(LColor.getARGB(r, g, b, a));
}
public Pixmap setColor(float r, float g, float b, float a) {
return setColor(LColor.getARGB((int) (r > 1 ? r : r * 255), (int) (g > 1 ? g : r * 255),
(int) (b > 1 ? b : b * 255), (int) (a > 1 ? a : a * 255)));
}
public Pixmap setColor(int c) {
if (this._baseAlpha != 1f) {
this._baseColor = c;
int ialpha = (int) (0xFF * MathUtils.clamp(this._baseAlpha, 0, 1));
this._baseColor = (ialpha << 24) | (_baseColor & 0xFFFFFF);
} else {
this._baseColor = c;
}
return this;
}
public Pixmap setPaintMode() {
xorColor = null;
xorMode = false;
xorRGB = 0;
return this;
}
public Pixmap setXORMode(LColor c) {
xorColor = c;
xorMode = xorColor != null;
xorRGB = xorMode ? xorColor.getRGB() : 0;
return this;
}
public Pixmap setXORMode(int red, int green, int blue) {
this.xorColor = new LColor(red, green, blue);
this.xorMode = true;
this.xorRGB = ((red & 0xFF) << 16) | ((green & 0xFF) << 8) | (blue & 0xFF);
return this;
}
public RectI getClipBounds() {
if (_isClosed) {
return null;
}
return defClip != null ? new RectI(defClip.x, defClip.y, defClip.width, defClip.height)
: new RectI(0, 0, _width, _height);
}
public Pixmap clipRect(int x, int y, int width, int height) {
if (_isClosed) {
return this;
}
if (defClip != null) {
defClip = defClip.getIntersection(new RectI(x, y, width, height));
clip = clip.getIntersection(new RectI(x + _translateX, y + _translateY, width, height));
} else {
defClip = new RectI(x, y, width, height);
clip = new RectI(x + _translateX, y + _translateY, width, height);
}
return this;
}
public Pixmap setClip(int x, int y, int width, int height) {
if (_isClosed) {
return this;
}
if (defClip == null) {
defClip = new RectI(x, y, width, height);
} else {
defClip.set(x, y, width, height);
}
clip = new RectI(MathUtils.max(x + _translateX, 0), MathUtils.max(y + _translateY, 0),
MathUtils.min(width, width - _translateX), MathUtils.min(height, height - _translateY));
return this;
}
public RectI getClip() {
if (_isClosed) {
return null;
}
return getClipBounds();
}
public Pixmap setClip(RectI clip) {
return setClip(clip.x, clip.y, clip.width, clip.height);
}
public Pixmap drawShapeImpl(Shape shape, int x1, int y1) {
if (shape == null) {
return this;
}
final float[] points = shape.getPoints();
int size = points.length;
int len = size / 2;
final int[] xps = new int[len];
final int[] yps = new int[len];
for (int i = 0, j = 0; i < size; i += 2, j++) {
xps[j] = (int) (points[i] + x1);
yps[j] = (int) (points[i + 1] + y1);
}
drawPolyline(xps, yps, len);
drawLine(xps[len - 1], yps[len - 1], xps[0], yps[0]);
return this;
}
public Pixmap fillShapeImpl(Shape shape, int x1, int y1) {
if (shape == null) {
return this;
}
final float[] points = shape.getPoints();
int size = points.length;
int len = size / 2;
final int[] xps = new int[len];
final int[] yps = new int[len];
for (int i = 0, j = 0; i < size; i += 2, j++) {
xps[j] = (int) (points[i] + x1);
yps[j] = (int) (points[i + 1] + y1);
}
RectI bounds = RectI.getIntersection(setBoundingBox(temp_rect, xps, yps, len), clip, temp_rect);
for (int x = bounds.x; x < bounds.x + bounds.width; x++) {
for (int y = bounds.y; y < bounds.y + bounds.height; y++) {
if (contains(xps, yps, len, bounds, x, y)) {
drawPoint(x, y);
}
}
}
return this;
}
/**
* 绘制五角星
*/
public Pixmap drawSixStart(LColor color, int x, int y, int r) {
if (_isClosed) {
return this;
}
setColor(color);
drawTriangle(color, x, y, r);
drawRTriangle(color, x, y, r);
return this;
}
/**
* 绘制正三角
*/
public Pixmap drawTriangle(LColor color, int x, int y, int r) {
if (_isClosed) {
return this;
}
int x1 = x;
int y1 = y - r;
int x2 = x - (int) (r * MathUtils.cos(MathUtils.PI / 6));
int y2 = y + (int) (r * MathUtils.sin(MathUtils.PI / 6));
int x3 = x + (int) (r * MathUtils.cos(MathUtils.PI / 6));
int y3 = y + (int) (r * MathUtils.sin(MathUtils.PI / 6));
int[] xpos = new int[3];
xpos[0] = x1;
xpos[1] = x2;
xpos[2] = x3;
int[] ypos = new int[3];
ypos[0] = y1;
ypos[1] = y2;
ypos[2] = y3;
setColor(color);
fillPolygon(xpos, ypos, 3);
return this;
}
/**
* 绘制倒三角
*/
public Pixmap drawRTriangle(LColor color, int x, int y, int r) {
if (_isClosed) {
return this;
}
int x1 = x;
int y1 = y + r;
int x2 = x - (int) (r * MathUtils.cos(MathUtils.PI / 6f));
int y2 = y - (int) (r * MathUtils.sin(MathUtils.PI / 6f));
int x3 = x + (int) (r * MathUtils.cos(MathUtils.PI / 6f));
int y3 = y - (int) (r * MathUtils.sin(MathUtils.PI / 6f));
int[] xpos = new int[3];
xpos[0] = x1;
xpos[1] = x2;
xpos[2] = x3;
int[] ypos = new int[3];
ypos[0] = y1;
ypos[1] = y2;
ypos[2] = y3;
setColor(color);
fillPolygon(xpos, ypos, 3);
return this;
}
/**
* 绘制并填充一组三角
*
* @param ts
*/
public Pixmap fillTriangle(Triangle2f[] ts) {
return fillTriangle(ts, 0, 0);
}
/**
* 绘制并填充一组三角
*
* @param ts
* @param x
* @param y
*/
public Pixmap fillTriangle(Triangle2f[] ts, int x, int y) {
if (_isClosed) {
return this;
}
if (ts == null) {
return this;
}
int size = ts.length;
for (int i = 0; i < size; i++) {
fillTriangle(ts[i], x, y);
}
return this;
}
/**
* 绘制并填充一组三角
*
* @param t
*/
public Pixmap fillTriangle(Triangle2f t) {
return fillTriangle(t, 0, 0);
}
/**
* 绘制并填充一组三角
*
* @param t
* @param x
* @param y
*/
public Pixmap fillTriangle(Triangle2f t, int x, int y) {
if (_isClosed) {
return this;
}
if (t == null) {
return this;
}
return fillTriangle(t.xpoints[0], t.ypoints[0], t.xpoints[1], t.ypoints[1], t.xpoints[2], t.ypoints[2]);
}
/**
* 绘制并填充一组三角
*
* @param x1
* @param y1
* @param x2
* @param y2
* @param x3
* @param y3
* @return
*/
public Pixmap fillTriangle(float x1, float y1, float x2, float y2, float x3, float y3) {
if (_isClosed) {
return this;
}
int[] xpos = new int[3];
int[] ypos = new int[3];
xpos[0] = (int) x1;
xpos[1] = (int) x2;
xpos[2] = (int) x3;
ypos[0] = (int) y1;
ypos[1] = (int) y2;
ypos[2] = (int) y3;
fillPolygon(xpos, ypos, 3);
return this;
}
/**
* 绘制一组三角
*
* @param ts
*/
public Pixmap drawTriangle(Triangle2f[] ts) {
return drawTriangle(ts, 0, 0);
}
/**
* 绘制一组三角
*
* @param ts
* @param x
* @param y
*/
public Pixmap drawTriangle(Triangle2f[] ts, int x, int y) {
if (_isClosed) {
return this;
}
if (ts == null) {
return this;
}
int size = ts.length;
for (int i = 0; i < size; i++) {
drawTriangle(ts[i], x, y);
}
return this;
}
/**
* 绘制三角
*
* @param t
*/
public Pixmap drawTriangle(Triangle2f t) {
return drawTriangle(t, 0, 0);
}
/**
* 绘制三角
*
* @param t
* @param x
* @param y
*/
public Pixmap drawTriangle(Triangle2f t, int x, int y) {
if (_isClosed) {
return this;
}
if (t == null) {
return this;
}
int[] xpos = new int[3];
int[] ypos = new int[3];
xpos[0] = x + (int) t.xpoints[0];
xpos[1] = x + (int) t.xpoints[1];
xpos[2] = x + (int) t.xpoints[2];
ypos[0] = y + (int) t.ypoints[0];
ypos[1] = y + (int) t.ypoints[1];
ypos[2] = y + (int) t.ypoints[2];
drawPolygon(xpos, ypos, 3);
return this;
}
/**
* 从指定位置开始截取指定大小像素到指定位置
*
* @param x
* @param y
* @param width
* @param height
* @param dx
* @param dy
*/
public Pixmap copyArea(int x, int y, int width, int height, int dx, int dy) {
if (_isClosed) {
return this;
}
x += _translateX;
y += _translateY;
int xStart = x;
int xEnd = x + width - 1;
int xStep = 1;
if (dx < 0) {
xStart = x + width - 1;
xEnd = x;
xStep = -1;
}
int yStart = y;
int yEnd = y + height - 1;
int yStep = 1;
if (dy < 0) {
yStart = y + height - 1;
yEnd = y;
yStep = -1;
}
for (x = xStart; x <= xEnd; x += xStep) {
for (y = yStart; y <= yEnd; y += yStep) {
if (!inside(x + dx, y + dy) && x >= 0 && x < width && y >= 0 && y < height) {
_drawPixels[x + dx + (y + dy) * width] = _drawPixels[x + y * width];
}
}
}
return this;
}
/**
* 绘制一条直线
*
* @param x1
* @param y1
* @param x2
* @param y2
*/
public Pixmap drawLine(int x1, int y1, int x2, int y2) {
if (_isClosed) {
return this;
}
x1 += _translateX;
y1 += _translateY;
x2 += _translateX;
y2 += _translateY;
int dx = x2 - x1;
int dy = y2 - y1;
if (dx == 0) {
if (y1 < y2) {
drawVerticalLine(x1, y1, y2);
} else {
drawVerticalLine(x1, y2, y1);
}
} else if (dy == 0) {
if (x1 < x2) {
drawLineImpl(x1, x2, y1);
} else {
drawLineImpl(x2, x1, y1);
}
} else {
boolean swapXY = false;
int dxNeg = 1;
int dyNeg = 1;
boolean negativeSlope = false;
if (MathUtils.abs(dy) > MathUtils.abs(dx)) {
int temp = x1;
x1 = y1;
y1 = temp;
temp = x2;
x2 = y2;
y2 = temp;
dx = x2 - x1;
dy = y2 - y1;
swapXY = true;
}
if (x1 > x2) {
int temp = x1;
x1 = x2;
x2 = temp;
temp = y1;
y1 = y2;
y2 = temp;
dx = x2 - x1;
dy = y2 - y1;
}
if (dy * dx < 0) {
if (dy < 0) {
dyNeg = -1;
dxNeg = 1;
} else {
dyNeg = 1;
dxNeg = -1;
}
negativeSlope = true;
}
int d = 2 * (dy * dyNeg) - (dx * dxNeg);
int incrH = 2 * dy * dyNeg;
int incrHV = 2 * ((dy * dyNeg) - (dx * dxNeg));
int x = x1;
int y = y1;
int tempX = x;
int tempY = y;
if (swapXY) {
int temp = x;
x = y;
y = temp;
}
drawPoint(x, y);
x = tempX;
y = tempY;
while (x < x2) {
if (d <= 0) {
x++;
d += incrH;
} else {
d += incrHV;
x++;
if (!negativeSlope) {
y++;
} else {
y--;
}
}
tempX = x;
tempY = y;
if (swapXY) {
int temp = x;
x = y;
y = temp;
}
drawPoint(x, y);
x = tempX;
y = tempY;
}
}
return this;
}
/**
* 绘制一个矩形
*
* @param x1
* @param y1
* @param w1
* @param h1
*/
public Pixmap drawRect(int x1, int y1, int w1, int h1) {
if (_isClosed) {
return this;
}
int tempX = x1;
int tempY = y1;
int tempWidth = x1 + w1;
int tempHeight = y1 + h1;
if (tempX > tempWidth) {
x1 = tempX;
tempX = tempWidth;
tempWidth = x1;
}
if (tempY > tempHeight) {
y1 = tempY;
tempY = tempHeight;
tempHeight = y1;
}
drawLine(tempX, tempY, tempHeight, tempY);
drawLine(tempX, tempY + 1, tempX, tempHeight);
drawLine(tempHeight, tempHeight, tempX + 1, tempHeight);
drawLine(tempHeight, tempHeight - 1, tempHeight, tempY + 1);
return this;
}
/**
* 绘制一个围绕指定区域旋转的矩形选框
*
* @param x
* @param y
* @param width
* @param height
* @param arcWidth
* @param arcHeight
*/
public Pixmap drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
if (_isClosed) {
return this;
}
drawLine(x + arcWidth / 2, y, x + width - arcWidth / 2, y);
drawLine(x, y + arcHeight / 2, x, y + height - arcHeight / 2);
drawLine(x + arcWidth / 2, y + height, x + width - arcWidth / 2, y + height);
drawLine(x + width, y + arcHeight / 2, x + width, y + height - arcHeight / 2);
drawArc(x, y, arcWidth, arcHeight, 90, 90);
drawArc(x + width - arcWidth, y, arcWidth, arcHeight, 0, 90);
drawArc(x, y + height + -arcHeight, arcWidth, arcHeight, 180, 90);
drawArc(x + width - arcWidth, y + height + -arcHeight, arcWidth, arcHeight, 270, 90);
return this;
}
public Pixmap fillRoundRect(int x, int y, int width, int height, int radius) {
if (radius < 0) {
throw new IllegalArgumentException("radius > 0");
}
if (radius == 0) {
fillRect(x, y, width, height);
return this;
}
int mr = MathUtils.min(width, height) / 2;
if (radius > mr) {
radius = mr;
}
int d = radius * 2;
int w = width - d;
int h = height - d;
if (w > 0 && h > 0) {
fillRect(x + radius, y, w, radius);
fillRect(x, y + radius, radius, h);
fillRect(x + width - radius, y + radius, radius, h);
fillRect(x + radius, y + height - radius, w, radius);
fillRect(x + radius, y + radius, w, h);
}
fillArc(x + width - d, y + height - d, d, d, 0, 90);
fillArc(x, y + height - d, d, d, 90, 180);
fillArc(x + width - d, y, d, d, 270, 360);
fillArc(x, y, d, d, 180, 270);
return this;
}
/**
* 填充一个围绕指定区域旋转的矩形选框
*
* @param x
* @param y
* @param width
* @param height
* @param arcWidth
* @param arcHeight
*/
public Pixmap fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
if (_isClosed) {
return this;
}
int w = width - arcWidth;
int h = height - arcHeight;
if (w > 0 && h > 0) {
fillRect(x + arcWidth / 2, y, w, height);
fillRect(x, y + arcHeight / 2 - 1, arcWidth / 2, h);
fillRect(x + width - arcWidth / 2, y + arcHeight / 2 - 1, arcWidth / 2, h);
}
fillArc(x + 1, y, arcWidth - 1, arcHeight - 1, 90, 90);
fillArc(x + width - arcWidth - 1, y, arcWidth - 1, arcHeight - 1, 0, 90);
fillArc(x + 1, y + height + -arcHeight, arcWidth - 1, arcHeight - 1, 180, 90);
fillArc(x + width - arcWidth - 1, y + height + -arcHeight, arcWidth - 1, arcHeight - 1, 270, 90);
return this;
}
/**
* 将一个指定的Pixmap绘制到当前Pixmap
*
* @param pixel
* @param x
* @param y
*/
public Pixmap drawPixmap(Pixmap pixel, int x, int y) {
if (pixel == null) {
return this;
} else {
drawPixmap(pixel, x, y, pixel._width, pixel._height, 0, 0);
return this;
}
}
/**
* 将一个指定的Pixmap绘制到当前Pixmap
*
* @param pixel
* @param x
* @param y
* @param w
* @param h
* @param offsetX
* @param offsetY
*/
public Pixmap drawPixmap(Pixmap pixel, int x, int y, int w, int h, int offsetX, int offsetY) {
if (_isClosed) {
return this;
}
x += _translateX;
y += _translateY;
int[] currentPixels = pixel._drawPixels;
int transparent = pixel._transparent;
if (x < 0) {
w += x;
offsetX -= x;
x = 0;
}
if (y < 0) {
h += y;
offsetY -= y;
y = 0;
}
if (x + w > _width) {
w = _width - x;
}
if (y + h > _height) {
h = _height - y;
}
if (w < 0 || h < 0) {
return this;
}
if (transparent < 0) {
for (int size = 0; size < h; size++) {
System.arraycopy(currentPixels, (offsetY + size) * pixel._width + offsetX, _drawPixels,
(y + size) * _width + x, w);
}
} else {
int findIndex = y * _width + x;
int drawIndex = offsetY * pixel._width + offsetX;
int moveFind = _width - w;
int moveDraw = pixel._width - w;
for (int i = 0; i < h; i++) {
for (int j = 0; j < w;) {
if (inside(j, i)) {
continue;
}
if (currentPixels[drawIndex] != transparent) {
drawPoint(_drawPixels, findIndex, currentPixels[drawIndex]);
}
j++;
findIndex++;
drawIndex++;
}
findIndex += moveFind;
drawIndex += moveDraw;
}
}
return this;
}
/**
* 将一个指定的Pixmap绘制到当前Pixmap,并扩展为指定大小
*
* @param pixel
* @param x
* @param y
* @param w
* @param h
*/
public Pixmap drawPixmap(Pixmap pixel, int x, int y, int w, int h) {
if (pixel == null) {
return this;
} else {
drawPixmap(pixel, x, y, w, h, 0, 0, pixel._width, pixel._height);
return this;
}
}
/**
* 将一个指定的Pixmap绘制到当前Pixmap,并截取为指定大小
*
* @param img
* @param dstX
* @param dstY
* @param dstWidth
* @param dstHeight
* @param srcX
* @param srcY
* @param srcWidth
* @param srcHeight
*/
public Pixmap drawPixmap(Pixmap img, int dstX, int dstY, int dstWidth, int dstHeight, int srcX, int srcY,
int srcWidth, int srcHeight) {
if (_isClosed || img == null || img._isClosed) {
return this;
}
dstX += _translateX;
dstY += _translateY;
srcX += _translateX;
srcY += _translateY;
if (dstWidth <= 0 || dstHeight <= 0 || srcWidth <= 0 || srcHeight <= 0) {
return this;
}
if (dstWidth == srcWidth && dstHeight == srcHeight) {
drawPixmap(img, dstX, dstY, dstWidth, dstHeight, srcX, srcY);
return this;
}
int[] currentPixels = img.getData();
int spitch = img._width;
int dpitch = this._width;
float x_ratio = ((float) srcWidth - 1) / dstWidth;
float y_ratio = ((float) srcHeight - 1) / dstHeight;
float x_diff = 0F;
float y_diff = 0F;
int dx = dstX;
int dy = dstY;
int sx = srcX;
int sy = srcY;
int i = 0;
int j = 0;
for (; i < dstHeight; i++) {
sy = (int) (i * y_ratio) + srcY;
dy = i + dstY;
y_diff = (y_ratio * i + srcY) - sy;
if (sy < 0 || dy < 0) {
continue;
}
if (sy >= img._height || dy >= this._height) {
break;
}
for (j = 0; j < dstWidth; j++) {
sx = (int) (j * x_ratio) + srcX;
dx = j + dstX;
x_diff = (x_ratio * j + srcX) - sx;
if (sx < 0 || dx < 0) {
continue;
}
if (sx >= img._width || dx >= this._width) {
break;
}
int src_ptr = sx + sy * spitch;
int dst_ptr = dx + dy * dpitch;
int src_color = currentPixels[src_ptr];
int src_pixel = src_color;
if (src_pixel != _transparent) {
float ta = (1 - x_diff) * (1 - y_diff);
float tb = (x_diff) * (1 - y_diff);
float tc = (1 - x_diff) * (y_diff);
float td = (x_diff) * (y_diff);
int a = (int) (((src_pixel & 0xff000000) >> 24) * ta + ((src_pixel & 0xff000000) >> 24) * tb
+ ((src_pixel & 0xff000000) >> 24) * tc + ((src_pixel & 0xff000000) >> 24) * td) & 0xff;
int b = (int) (((src_pixel & 0xff0000) >> 16) * ta + ((src_pixel & 0xff0000) >> 16) * tb
+ ((src_pixel & 0xff0000) >> 16) * tc + ((src_pixel & 0xff0000) >> 16) * td) & 0xff;
int g = (int) (((src_pixel & 0xff00) >> 8) * ta + ((src_pixel & 0xff00) >> 8) * tb
+ ((src_pixel & 0xff00) >> 8) * tc + ((src_pixel & 0xff00) >> 8) * td) & 0xff;
int r = (int) ((src_pixel & 0xff) * ta + (src_pixel & 0xff) * tb + (src_pixel & 0xff) * tc
+ (src_pixel & 0xff) * td) & 0xff;
int dst_color = _drawPixels[dst_ptr];
drawPoint(_drawPixels, dst_ptr, blend(r, g, b, a, dst_color));
} else {
drawPoint(_drawPixels, dst_ptr, _transparent);
}
}
}
return this;
}
private int blend(int src_r, int src_g, int src_b, int src_a, int value) {
int dst_r = (value & 0x00FF0000) >> 16;
int dst_g = (value & 0x0000FF00) >> 8;
int dst_b = (value & 0x000000FF);
int dst_a = (value & 0xFF000000) >> 24;
if (src_a == _transparent && dst_a == _transparent) {
return _transparent;
}
if (dst_a == 0) {
return ((src_a << 24) | (src_b << 16) | (src_g << 8) | src_r);
}
dst_r = (int) (dst_r + src_a * (src_r - dst_r) / 255);
dst_g = (int) (dst_g + src_a * (src_g - dst_g) / 255);
dst_b = (int) (dst_b + src_a * (src_b - dst_b) / 255);
dst_a = (int) (((1.0f - (1.0f - src_a / 255.0f) * (1.0f - dst_a / 255.0f)) * 255));
return (int) ((dst_a << 24) | (dst_b << 16) | (dst_g << 8) | dst_r);
}
public Pixmap fillRect(int x, int y, int width, int height) {
if (_isClosed) {
return this;
}
int maxX = MathUtils.min(x + width - 1 + _translateX, clip.x + clip.width - 1);
int maxY = MathUtils.min(y + height - 1 + _translateY, clip.y + clip.height - 1);
for (int row = MathUtils.max(y + _translateY, clip.y), rowOffset = row
* width; row <= maxY; row++, rowOffset += width) {
for (int col = MathUtils.max(x + _translateX, clip.x); col <= maxX; col++) {
drawPoint(_drawPixels, col + rowOffset);
}
}
return this;
}
public Pixmap clearRect(int x, int y, int width, int height) {
return fillRect(x, y, width, height);
}
/**
* 绘制一个椭圆形
*
* @param x
* @param y
* @param width
* @param height
*/
public Pixmap drawOval(int x, int y, int width, int height) {
if (_isClosed) {
return this;
}
drawCircle(x, y, width, height, false, new CircleUpdate() {
public void newPoint(int xLeft, int yTop, int xRight, int yBottom) {
drawPoint(xLeft, yTop);
drawPoint(xRight, yTop);
drawPoint(xLeft, yBottom);
drawPoint(xRight, yBottom);
}
});
return this;
}
/**
* 填充一个椭圆形
*
* @param x
* @param y
* @param width
* @param height
*/
public Pixmap fillOval(int x, int y, int width, int height) {
if (_isClosed) {
return this;
}
drawCircle(x, y, width, height, true, new CircleUpdate() {
public void newPoint(int xLeft, int yTop, int xRight, int yBottom) {
drawLineImpl(xLeft, xRight, yTop);
if (yTop != yBottom)
drawLineImpl(xLeft, xRight, yBottom);
}
});
return this;
}
/**
* 绘制一个弧线
*
* @param x
* @param y
* @param width
* @param height
* @param start
* @param arcAngle
*/
public Pixmap drawArc(int x, int y, int width, int height, int start, int arcAngle) {
if (_isClosed) {
return this;
}
if (arcAngle == 0) {
return this;
}
if (arcAngle < 0) {
start = 360 - arcAngle;
arcAngle = 360 + arcAngle;
}
start %= 360;
if (start < 0) {
start += 360;
}
if (arcAngle % 360 == 0) {
drawOval(x, y, width, height);
return this;
} else {
arcAngle %= 360;
}
final int startAngle = arcAngle > 0 ? start
: (start + arcAngle < 0 ? start + arcAngle + 360 : start + arcAngle);
final int centerX = x + _translateX + width / 2;
final int centerY = y + _translateY + height / 2;
final int xPoints[] = new int[7];
final int yPoints[] = new int[7];
final int nPoints = getBoundingShape(xPoints, yPoints, startAngle, MathUtils.abs(arcAngle), centerX, centerY,
x + _translateX - 1, y + _translateY - 1, width + 2, height + 2);
final RectI bounds = RectI.getIntersection(setBoundingBox(temp_rect, xPoints, yPoints, nPoints), clip,
temp_rect);
this.drawCircle(x, y, width, height, false, new CircleUpdate() {
public void newPoint(int xLeft, int yTop, int xRight, int yBottom) {
drawArcPoint(xPoints, yPoints, nPoints, bounds, xLeft, yTop);
drawArcPoint(xPoints, yPoints, nPoints, bounds, xRight, yTop);
drawArcPoint(xPoints, yPoints, nPoints, bounds, xLeft, yBottom);
drawArcPoint(xPoints, yPoints, nPoints, bounds, xRight, yBottom);
}
});
return this;
}
/**
* 填充一个弧线
*
* @param x
* @param y
* @param width
* @param height
* @param start
* @param arcAngle
*/
public Pixmap fillArc(int x, int y, int width, int height, int start, int arcAngle) {
if (_isClosed) {
return this;
}
if (arcAngle < 0) {
start = 360 - arcAngle;
arcAngle = 360 + arcAngle;
}
start %= 360;
if (start < 0) {
start += 360;
}
if (arcAngle % 360 == 0) {
fillOval(x, y, width, height);
return this;
} else {
arcAngle %= 360;
}
final int startAngle = arcAngle > 0 ? start
: (start + arcAngle < 0 ? start + arcAngle + 360 : start + arcAngle);
final int centerX = x + _translateX + width / 2;
final int centerY = y + _translateY + height / 2;
final int xPoints[] = new int[7];
final int yPoints[] = new int[7];
final int nPoints = getBoundingShape(xPoints, yPoints, startAngle, MathUtils.abs(arcAngle), centerX, centerY,
x + _translateX - 1, y + _translateY - 1, width + 2, height + 2);
final RectI bounds = setBoundingBox(temp_rect, xPoints, yPoints, nPoints);
this.drawCircle(x, y, width, height, true, new CircleUpdate() {
public void newPoint(int xLeft, int yTop, int xRight, int yBottom) {
drawArcImpl(xPoints, yPoints, nPoints, bounds, xLeft, xRight, yTop);
if (yTop != yBottom) {
drawArcImpl(xPoints, yPoints, nPoints, bounds, xLeft, xRight, yBottom);
}
}
});
return this;
}
public Pixmap drawPolyline(int xPoints[], int yPoints[], int nPoints) {
if (_isClosed) {
return this;
}
for (int i = 1; i < nPoints; i++) {
drawLine(xPoints[i - 1], yPoints[i - 1], xPoints[i], yPoints[i]);
}
return this;
}
/**
* 绘制一个多边形
*
* @param p
*/
public Pixmap drawPolygon(Polygon p) {
return drawShapeImpl(p, 0, 0);
}
/**
* 绘制一个多边形
*
* @param xPoints
* @param yPoints
* @param nPoints
*/
public Pixmap drawPolygon(int xPoints[], int yPoints[], int nPoints) {
drawPolyline(xPoints, yPoints, nPoints);
drawLine(xPoints[nPoints - 1], yPoints[nPoints - 1], xPoints[0], yPoints[0]);
return this;
}
/**
* 绘制并填充一个多边形
*
* @param p
*/
public Pixmap fillPolygon(Polygon p) {
return fillShapeImpl(p, 0, 0);
}
/**
* 绘制并填充一个多边形
*
* @param xPoints
* @param yPoints
* @param nPoints
*/
public Pixmap fillPolygon(int[] xPoints, int[] yPoints, int nPoints) {
int[] xPointsCopy;
if (_translateX == 0) {
xPointsCopy = xPoints;
} else {
xPointsCopy = CollectionUtils.copyOf(xPoints);
for (int i = 0; i < nPoints; i++) {
xPointsCopy[i] += _translateX;
}
}
int[] yPointsCopy;
if (_translateY == 0) {
yPointsCopy = yPoints;
} else {
yPointsCopy = CollectionUtils.copyOf(yPoints);
for (int i = 0; i < nPoints; i++) {
yPointsCopy[i] += _translateY;
}
}
RectI bounds = RectI.getIntersection(setBoundingBox(temp_rect, xPointsCopy, yPointsCopy, nPoints), clip,
temp_rect);
for (int x = bounds.x; x < bounds.x + bounds.width; x++) {
for (int y = bounds.y; y < bounds.y + bounds.height; y++) {
if (contains(xPointsCopy, yPointsCopy, nPoints, bounds, x, y)) {
drawPoint(x, y);
}
}
}
return this;
}
private void drawLineImpl(int x1, int x2, int y) {
if (_isClosed) {
return;
}
if (y >= clip.y && y < clip.y + clip.height) {
y *= _width;
int maxX = MathUtils.min(x2, clip.x + clip.width - 1);
if (_drawPixels != null)
for (int x = MathUtils.max(x1, clip.x); x <= maxX; x++)
drawPoint(_drawPixels, x + y);
}
}
private void drawVerticalLine(int x, int y1, int y2) {
if (x >= clip.x && x < clip.x + clip.width) {
int maxY = MathUtils.min(y2, clip.y + clip.height - 1) * _width;
if (_drawPixels != null)
for (int y = MathUtils.max(y1, clip.y) * _width; y <= maxY; y += _width)
drawPoint(_drawPixels, x + y);
}
}
private void drawPoint(int x, int y) {
if (!inside(x, y)) {
drawPoint(_drawPixels, x + y * _width);
}
}
private void drawPoint(int x, int y, int c) {
if (!inside(x, y)) {
if (_baseAlpha == 1f) {
int pixelIndex = x + y * _width;
_drawPixels[pixelIndex] = xorMode ? 0xFF000000 | ((_drawPixels[pixelIndex] ^ c) ^ xorRGB) : c;
} else {
int ialpha = (int) (0xFF * MathUtils.clamp(_baseAlpha, 0, 1));
c = (ialpha << 24) | (c & 0xFFFFFF);
int pixelIndex = x + y * _width;
_drawPixels[pixelIndex] = xorMode ? 0xFF000000 | ((_drawPixels[pixelIndex] ^ c) ^ xorRGB) : c;
}
}
}
private void drawPoint(int[] pixels, int pixelIndex) {
int pixel = pixels[pixelIndex];
if (_composite == -1) {
pixels[pixelIndex] = xorMode ? 0xFF000000 | ((pixel ^ _baseColor) ^ xorRGB) : _baseColor;
return;
} else {
switch (_composite) {
default:
case SRC_IN:
if (pixel != _transparent) {
pixels[pixelIndex] = xorMode ? 0xFF000000 | ((pixel ^ _baseColor) ^ xorRGB) : _baseColor;
}
break;
case SRC_OUT:
if (pixel == _transparent) {
pixels[pixelIndex] = xorMode ? 0xFF000000 | ((pixel ^ _baseColor) ^ xorRGB) : _baseColor;
}
break;
case SRC_OVER:
pixels[pixelIndex] = xorMode ? 0xFF000000 | ((pixel ^ _baseColor) ^ xorRGB) : _baseColor;
break;
}
}
}
private void drawPoint(int[] pixels, int pixelIndex, int c) {
int pixel = pixels[pixelIndex];
if (_composite == -1) {
if (_baseAlpha == 1f) {
pixels[pixelIndex] = xorMode ? 0xFF000000 | ((pixel ^ c) ^ xorRGB) : c;
} else {
int ialpha = (int) (0xFF * MathUtils.clamp(_baseAlpha, 0, 1));
c = (ialpha << 24) | (c & 0xFFFFFF);
pixels[pixelIndex] = xorMode ? 0xFF000000 | ((pixel ^ c) ^ xorRGB) : c;
}
return;
} else {
switch (_composite) {
default:
case SRC_IN:
if (pixel != _transparent) {
if (_baseAlpha == 1f) {
pixels[pixelIndex] = xorMode ? 0xFF000000 | ((pixel ^ c) ^ xorRGB) : c;
} else {
int ialpha = (int) (0xFF * MathUtils.clamp(_baseAlpha, 0, 1));
c = (ialpha << 24) | (c & 0xFFFFFF);
pixels[pixelIndex] = xorMode ? 0xFF000000 | ((pixel ^ c) ^ xorRGB) : c;
}
}
break;
case SRC_OUT:
if (pixel == _transparent) {
if (_baseAlpha == 1f) {
pixels[pixelIndex] = xorMode ? 0xFF000000 | ((pixel ^ c) ^ xorRGB) : c;
} else {
int ialpha = (int) (0xFF * MathUtils.clamp(_baseAlpha, 0, 1));
c = (ialpha << 24) | (c & 0xFFFFFF);
pixels[pixelIndex] = xorMode ? 0xFF000000 | ((pixel ^ c) ^ xorRGB) : c;
}
}
break;
case SRC_OVER:
if (_baseAlpha == 1f) {
pixels[pixelIndex] = xorMode ? 0xFF000000 | ((pixel ^ c) ^ xorRGB) : c;
} else {
int ialpha = (int) (0xFF * MathUtils.clamp(_baseAlpha, 0, 1));
c = (ialpha << 24) | (c & 0xFFFFFF);
pixels[pixelIndex] = xorMode ? 0xFF000000 | ((pixel ^ c) ^ xorRGB) : c;
}
break;
}
}
}
public int getComposite() {
return this._composite;
}
public Pixmap setComposite(int c) {
this._composite = c;
return this;
}
private void drawArcPoint(int xPoints[], int yPoints[], int nPoints, RectI bounds, int x, int y) {
if (contains(xPoints, yPoints, nPoints, bounds, x, y)) {
drawPoint(x, y);
}
}
private void drawArcImpl(int xPoints[], int yPoints[], int nPoints, RectI bounds, int xLeft, int xRight, int y) {
if (y >= clip.y && y < clip.y + clip.height) {
for (int x = MathUtils.max(xLeft, clip.x); x <= xRight; x++) {
if (contains(xPoints, yPoints, nPoints, bounds, x, y)) {
drawPoint(x, y);
}
}
}
}
private interface CircleUpdate {
public void newPoint(int xLeft, int yTop, int xRight, int yBottom);
}
private void drawCircle(int x, int y, int width, int height, boolean fill, CircleUpdate listener) {
int a = width / 2;
int b = height / 2;
long squareA = width * width / 4;
long squareB = height * height / 4;
long squareAB = MathUtils.round((long) width * width * height * height, 16L);
x += _translateX;
y += _translateY;
int centerX = x + a;
int centerY = y + b;
int deltaX = (width % 2 == 0) ? 0 : 1;
int deltaY = (height % 2 == 0) ? 0 : 1;
int currentY = b;
int currentX = 0;
int lastx1 = centerX - currentX;
int lastx2 = centerX + currentX + deltaX;
int lasty1 = centerY - currentY;
int lasty2 = centerY + currentY + deltaY;
while (currentX <= a && currentY >= 0) {
long deltaA = (currentX + 1) * (currentX + 1) * squareB + currentY * currentY * squareA - squareAB;
long deltaB = (currentX + 1) * (currentX + 1) * squareB + (currentY - 1) * (currentY - 1) * squareA
- squareAB;
long deltaC = currentX * currentX * squareB + (currentY - 1) * (currentY - 1) * squareA - squareAB;
if (deltaA <= 0) {
currentX++;
} else if (deltaC >= 0) {
currentY--;
} else {
int min = (int) MathUtils.min(MathUtils.abs(deltaA),
MathUtils.min(MathUtils.abs(deltaB), MathUtils.abs(deltaC)));
if (min == MathUtils.abs(deltaA)) {
currentX++;
} else if (min == MathUtils.abs(deltaC)) {
currentY--;
} else {
currentX++;
currentY--;
}
}
int x1 = centerX - currentX;
int x2 = centerX + currentX + deltaX;
int y1 = centerY - currentY;
int y2 = centerY + currentY + deltaY;
if (!fill || lasty1 != y1) {
listener.newPoint(lastx1, lasty1, lastx2, lasty2);
lasty1 = y1;
lasty2 = y2;
}
lastx1 = x1;
lastx2 = x2;
}
if (lasty1 < lasty2) {
for (; lasty1 <= lasty2; lasty1++, lasty2--) {
listener.newPoint(centerX - a, lasty1, centerX + a + deltaX, lasty2);
}
}
}
private boolean inside(int x, int y) {
return (x < clip.x || x >= clip.x + clip.width || y < clip.y || y >= clip.y + clip.height);
}
public int getX() {
return _translateX;
}
public void setX(int x) {
this._translateX = x;
}
public int getY() {
return _translateY;
}
public void setY(int y) {
this._translateY = y;
}
/**
* 获得当前图像是否不透明
*
* @return
*/
public boolean hasAlpha() {
return _hasAlpha;
}
/**
* 获得图像高
*
* @return
*/
public int getWidth() {
return _width;
}
/**
* 获得图像宽
*
* @return
*/
public int getHeight() {
return _height;
}
/**
* 获得指定区域是否透明
*
* @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 (!_hasAlpha) {
return false;
} else {
int pixel = _drawPixels[x + y * _width];
return (pixel >>> 24) == 0;
}
}
public int getTransparent() {
return _transparent;
}
public void setTransparent(int transparent) {
this._transparent = transparent;
}
public IntBuffer getPixelsData() {
return LSystem.base().support().newIntBuffer(_drawPixels);
}
public boolean isClosed() {
return _isClosed;
}
public int getSize() {
return size;
}
public int[] getData() {
return _drawPixels;
}
public void setData(int[] pixels) {
if (_isClosed) {
return;
}
this._drawPixels = pixels;
}
public int getData(int x, int y) {
if (_isClosed) {
return -1;
}
if (x < 0 || x >= this._width || y < 0 || y >= this._height) {
return -1;
} else {
return this._drawPixels[y * _width + x];
}
}
public TArray<Vector2f> getPoints(final Vector2f size, final int interval, final float scale) {
final int[] pixels = _drawPixels;
final TArray<Vector2f> points = new TArray<Vector2f>();
for (int y = 0; y < getHeight(); y += interval) {
for (int x = 0; x < getWidth(); x += interval) {
int tx = MathUtils.clamp(x + MathUtils.nextInt(-interval / 2, interval / 2), 0, getWidth() - 1);
int ty = MathUtils.clamp(y + MathUtils.nextInt(-interval / 2, interval / 2), 0, getHeight() - 1);
int color = pixels[getWidth() * ty + tx];
if (LColor.getRed(color) == 255) {
points.add((new Vector2f(tx, ty).sub(size)).mul(scale));
}
}
}
return points;
}
public String getBase64() {
return getRGBAsToArrayByte().toString();
}
public ArrayByte getRGBAsToArrayByte() {
return new ArrayByte(getRGBABytes());
}
public byte[] getABGRBytes() {
return getRGBABytes(true);
}
public byte[] getRGBABytes() {
return getRGBABytes(false);
}
public byte[] getRGBABytes(boolean flag) {
int idx = 0;
final int bits = 4;
final int[] pixesl = _drawPixels;
byte[] buffer = new byte[getWidth() * getHeight() * bits];
for (int i = 0, size = buffer.length; i < size; i += bits) {
int pixel = pixesl[idx++];
if (flag) {
buffer[i + 3] = (byte) (LColor.getAlpha(pixel));
buffer[i + 2] = (byte) (LColor.getRed(pixel));
buffer[i + 1] = (byte) (LColor.getGreen(pixel));
buffer[i] = (byte) (LColor.getBlue(pixel));
} else {
buffer[i] = (byte) (LColor.getRed(pixel));
buffer[i + 1] = (byte) (LColor.getGreen(pixel));
buffer[i + 2] = (byte) (LColor.getBlue(pixel));
buffer[i + 3] = (byte) (LColor.getAlpha(pixel));
}
}
return buffer;
}
public byte[] getBGRBytes() {
return getRGBBytes(true);
}
public byte[] getRGBBytes() {
return getRGBBytes(false);
}
public byte[] getRGBBytes(boolean flag) {
int idx = 0;
final int bits = 3;
final int[] pixesl = _drawPixels;
byte[] buffer = new byte[getWidth() * getHeight() * bits];
for (int i = 0, size = buffer.length; i < size; i += bits) {
int pixel = pixesl[idx++];
if (flag) {
buffer[i + 2] = (byte) (LColor.getRed(pixel));
buffer[i + 1] = (byte) (LColor.getGreen(pixel));
buffer[i] = (byte) (LColor.getBlue(pixel));
} else {
buffer[i] = (byte) (LColor.getRed(pixel));
buffer[i + 1] = (byte) (LColor.getGreen(pixel));
buffer[i + 2] = (byte) (LColor.getBlue(pixel));
}
}
return buffer;
}
public ByteBuffer convertPixmapToByteBuffer() {
Support support = LSystem.base().support();
ByteBuffer buffer = support.newByteBuffer(_width * _height * 4);
for (int y = 0; y < getHeight(); y++) {
for (int x = 0; x < getWidth(); x++) {
int pixel = this._drawPixels[y * _width + x];
buffer.put((byte) ((pixel >> 16) & 0xFF));
buffer.put((byte) ((pixel >> 8) & 0xFF));
buffer.put((byte) (pixel & 0xFF));
buffer.put((byte) ((pixel >> 24) & 0xFF));
}
}
buffer.flip();
return buffer;
}
public ByteBuffer convertPixmapToRGBByteBuffer() {
Support support = LSystem.base().support();
ByteBuffer buffer = support.newByteBuffer(_width * _height * 3);
for (int y = 0; y < getHeight(); y++) {
for (int x = 0; x < getWidth(); x++) {
int pixel = this._drawPixels[y * _width + x];
buffer.put((byte) ((pixel >> 16) & 0xFF));
buffer.put((byte) ((pixel >> 8) & 0xFF));
buffer.put((byte) (pixel & 0xFF));
}
}
buffer.flip();
return buffer;
}
public void convertByteBufferRGBToPixmap(ByteBuffer buffer) {
int idx = 0;
int dst = 0;
for (int y = 0; y < _height; y++) {
for (int x = 0; x < _width; x++) {
int r = buffer.get(idx++) & 0xFF;
int g = buffer.get(idx++) & 0xFF;
int b = buffer.get(idx++) & 0xFF;
this._drawPixels[dst + x] = LColor.rgb(r, g, b);
}
dst += _width;
}
}
public void convertByteBufferToPixmap(ByteBuffer buffer) {
int idx = 0;
int dst = 0;
for (int y = 0; y < _height; y++) {
for (int x = 0; x < _width; x++) {
int r = buffer.get(idx++) & 0xFF;
int g = buffer.get(idx++) & 0xFF;
int b = buffer.get(idx++) & 0xFF;
int a = buffer.get(idx++) & 0xFF;
this._drawPixels[dst + x] = LColor.argb(a, r, g, b);
}
dst += _width;
}
}
@Override
public String toString() {
StringBuilder sbr = new StringBuilder();
for (int y = 0; y < _height; y++) {
sbr.append('{');
for (int x = 0; x < _width; x++) {
int p = getData(x, y);
sbr.append(p);
if (x < _width - 1) {
sbr.append(',');
}
}
sbr.append('}');
sbr.append(",\n");
}
return sbr.toString();
}
@Override
public void close() {
_isClosed = true;
_drawPixels = null;
}
}