You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
232 lines
8.0 KiB
232 lines
8.0 KiB
/**
|
|
*
|
|
*/
|
|
package com.jotuntech.sketcher.common;
|
|
|
|
import java.awt.image.BufferedImage;
|
|
import java.awt.image.DataBufferInt;
|
|
import java.io.IOException;
|
|
import java.io.Serializable;
|
|
|
|
/**
|
|
* @author Thor Harald Johansen
|
|
*
|
|
*/
|
|
public class BitmapTile implements Serializable {
|
|
static final long serialVersionUID = 3265680755614445636L;
|
|
|
|
public final static int SIZE = 32;
|
|
public final static int SIZE_2 = 5;
|
|
public final static int SIZE_MASK = 31;
|
|
|
|
private BufferedImage image;
|
|
private int[] pixels;
|
|
private byte[] encoded;
|
|
|
|
/**
|
|
* Creates a bitmap tile
|
|
*/
|
|
public BitmapTile() {
|
|
image = new BufferedImage(SIZE, SIZE, BufferedImage.TYPE_INT_ARGB);
|
|
pixels = ((DataBufferInt)image.getRaster().getDataBuffer()).getData();
|
|
}
|
|
|
|
public BitmapTile(BufferedImage imagex) {
|
|
image = new BufferedImage(SIZE, SIZE, BufferedImage.TYPE_INT_ARGB);
|
|
pixels = ((DataBufferInt)image.getRaster().getDataBuffer()).getData();
|
|
|
|
image.getGraphics().drawImage(imagex, 0, 0, null);
|
|
}
|
|
|
|
public BitmapTile(BitmapTile tile) {
|
|
image = new BufferedImage(SIZE, SIZE, BufferedImage.TYPE_INT_ARGB);
|
|
tile.image.copyData(image.getRaster());
|
|
pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
|
|
}
|
|
|
|
/*
|
|
public void blendPixel(int x, int y, int sourceColor, int sourceAlpha65025) {
|
|
// Offset in destination pixel array
|
|
int offset = (y << SIZE_2) + x;
|
|
|
|
// Fetch destionation pixel
|
|
int destinationPixel = pixels[offset];
|
|
|
|
// Get destination's alpha
|
|
int destinationAlpha = Pixels.getChannel0(destinationPixel);
|
|
|
|
// Divide source alpha
|
|
int sourceAlpha = sourceAlpha65025 / 255;
|
|
|
|
if(sourceAlpha > 0) {
|
|
if(sourceAlpha == 255) {
|
|
pixels[offset] = Pixels.pack(255, sourceColor);
|
|
} else {
|
|
if(destinationAlpha == 0) {
|
|
int dither = sourceAlpha < 255 && sourceAlpha65025 % 255 > Pixels.random() ? 1 : 0;
|
|
pixels[offset] = Pixels.pack(sourceAlpha + dither, sourceColor);
|
|
} else {
|
|
// Destination alpha result
|
|
int destinationAlphaResult, destinationAlphaResult65025;
|
|
|
|
if(destinationAlpha == 255) {
|
|
destinationAlphaResult = 255;
|
|
destinationAlphaResult65025 = 65025;
|
|
} else {
|
|
destinationAlphaResult65025 = Math.min(65205, destinationAlpha * 255 + sourceAlpha65025);
|
|
destinationAlphaResult = destinationAlphaResult65025 / 255;
|
|
destinationAlphaResult += destinationAlphaResult < 255 && destinationAlphaResult65025 % 255 > Pixels.random() ? 1 : 0;
|
|
}
|
|
|
|
if(sourceColor == Pixels.stripChannel0(destinationPixel)) {
|
|
pixels[offset] = Pixels.pack(destinationAlphaResult, sourceColor);
|
|
} else {
|
|
// Destination colors
|
|
int destinationRed = Pixels.getChannel1(destinationPixel);
|
|
int destinationGreen = Pixels.getChannel2(destinationPixel);
|
|
int destinationBlue = Pixels.getChannel3(destinationPixel);
|
|
|
|
// Source colors
|
|
int sourceRed = Pixels.getChannel1(sourceColor);
|
|
int sourceGreen = Pixels.getChannel2(sourceColor);
|
|
int sourceBlue = Pixels.getChannel3(sourceColor);
|
|
|
|
if(destinationAlphaResult == 255) {
|
|
int outputRed = destinationRed + ((sourceRed - destinationRed) * sourceAlpha65025) / 65025;
|
|
int outputGreen = destinationGreen + ((sourceGreen - destinationGreen) * sourceAlpha65025) / 65025;
|
|
int outputBlue = destinationBlue + ((sourceBlue - destinationBlue) * sourceAlpha65025) / 65025;
|
|
|
|
// Blend, and store to destination
|
|
pixels[offset] = Pixels.pack(255,
|
|
outputRed,
|
|
outputGreen,
|
|
outputBlue);
|
|
} else {
|
|
// Blend, and store to destination
|
|
pixels[offset] = Pixels.pack(destinationAlphaResult,
|
|
destinationRed + ((sourceRed - destinationRed) * sourceAlpha65025) / destinationAlphaResult65025,
|
|
destinationGreen + ((sourceGreen - destinationGreen) * sourceAlpha65025) / destinationAlphaResult65025,
|
|
destinationBlue + ((sourceBlue - destinationBlue) * sourceAlpha65025) / destinationAlphaResult65025);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
public void blendPixel(int x, int y, int sourceColor, int sourceAlpha65025, int maxAlpha) {
|
|
// Offset in destination pixel array
|
|
int offset = (y << SIZE_2) + x;
|
|
|
|
// Fetch destionation pixel
|
|
int destinationPixel = pixels[offset];
|
|
|
|
// Get destination's alpha
|
|
int destinationAlpha = Pixels.getChannel0(destinationPixel);
|
|
|
|
// Divide source alpha
|
|
int sourceAlpha = sourceAlpha65025 / 255;
|
|
|
|
if(sourceAlpha > 0) {
|
|
if(sourceAlpha == 255) {
|
|
pixels[offset] = Pixels.pack(255, sourceColor);
|
|
} else {
|
|
if(destinationAlpha == 0) {
|
|
int dither = sourceAlpha65025 % 255 > Pixels.random() ? 1 : 0;
|
|
pixels[offset] = Pixels.pack((sourceAlpha & 0xFFFFFFFE) | dither, sourceColor);
|
|
} else {
|
|
// Destination alpha result
|
|
int destinationAlphaResult, destinationAlphaResult65025;
|
|
|
|
if(destinationAlpha == 255) {
|
|
destinationAlphaResult = 255;
|
|
destinationAlphaResult65025 = 65025;
|
|
} else {
|
|
// Destination multiplied by inverted source alpha.
|
|
int invSrcAlphaMulDest65025 = (destinationAlpha * (65025 - sourceAlpha65025)) / 255;
|
|
|
|
// Set destination alpha result
|
|
destinationAlphaResult65025 = Math.max(destinationAlpha * 255, Math.min(maxAlpha * 255, sourceAlpha65025 + invSrcAlphaMulDest65025));
|
|
destinationAlphaResult = destinationAlphaResult65025 / 255;
|
|
destinationAlphaResult = (destinationAlphaResult & 0xFFFFFFFE) | (destinationAlphaResult65025 % 255 > Pixels.random() ? 1 : 0);
|
|
}
|
|
|
|
if(sourceColor == Pixels.stripChannel0(destinationPixel)) {
|
|
if(destinationAlphaResult == 255) {
|
|
pixels[offset] = Pixels.pack(255, sourceColor);
|
|
} else {
|
|
pixels[offset] = Pixels.pack(destinationAlphaResult, sourceColor);
|
|
}
|
|
} else {
|
|
// Destination colors
|
|
int destinationRed = Pixels.getChannel1(destinationPixel);
|
|
int destinationGreen = Pixels.getChannel2(destinationPixel);
|
|
int destinationBlue = Pixels.getChannel3(destinationPixel);
|
|
|
|
// Source colors
|
|
int sourceRed = Pixels.getChannel1(sourceColor);
|
|
int sourceGreen = Pixels.getChannel2(sourceColor);
|
|
int sourceBlue = Pixels.getChannel3(sourceColor);
|
|
|
|
if(destinationAlphaResult == 255) {
|
|
int outputRed = destinationRed + ((sourceRed - destinationRed) * sourceAlpha65025) / 65025;
|
|
int outputGreen = destinationGreen + ((sourceGreen - destinationGreen) * sourceAlpha65025) / 65025;
|
|
int outputBlue = destinationBlue + ((sourceBlue - destinationBlue) * sourceAlpha65025) / 65025;
|
|
|
|
// Blend, and store to destination
|
|
pixels[offset] = Pixels.pack(255,
|
|
outputRed,
|
|
outputGreen,
|
|
outputBlue);
|
|
} else {
|
|
// Blend, and store to destination
|
|
pixels[offset] = Pixels.pack(destinationAlphaResult,
|
|
destinationRed + ((sourceRed - destinationRed) * sourceAlpha65025) / destinationAlphaResult65025,
|
|
destinationGreen + ((sourceGreen - destinationGreen) * sourceAlpha65025) / destinationAlphaResult65025,
|
|
destinationBlue + ((sourceBlue - destinationBlue) * sourceAlpha65025) / destinationAlphaResult65025);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void writeObject(java.io.ObjectOutputStream out) throws IOException {
|
|
out.writeObject(pixels);
|
|
}
|
|
|
|
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
|
|
this.image = new BufferedImage(SIZE, SIZE, BufferedImage.TYPE_INT_ARGB);
|
|
this.pixels = ((DataBufferInt)image.getRaster().getDataBuffer()).getData();
|
|
|
|
int[] pixels = (int[])in.readObject();
|
|
for(int i = 0; i < pixels.length; i++) {
|
|
this.pixels[i] = pixels[i];
|
|
}
|
|
}
|
|
|
|
public void setImage(BufferedImage image) {
|
|
this.image = image;
|
|
}
|
|
|
|
public BufferedImage getImage() {
|
|
return image;
|
|
}
|
|
|
|
public void setPixels(int[] pixels) {
|
|
this.pixels = pixels;
|
|
}
|
|
|
|
public int[] getPixels() {
|
|
return pixels;
|
|
}
|
|
|
|
public void setEncoded(byte[] encoded) {
|
|
this.encoded = encoded;
|
|
}
|
|
|
|
public byte[] getEncoded() {
|
|
return encoded;
|
|
}
|
|
}
|
|
|