package com.jme3.scene.plugins.blender.textures.io;
import com.jme3.math.FastMath;
import com.jme3.scene.plugins.blender.textures.TexturePixel;
import com.jme3.texture.Image;
import java.nio.ByteBuffer;
import jme3tools.converters.RGB565;
/**
* Implemens read/write operations for DDS images.
* This class currently implements only read operation.
* @author Marcin Roguski (Kaelthas)
*/
/* package */class DDSPixelInputOutput implements PixelInputOutput {
/**
* For this class the index should be considered as a pixel index in AWT image format.
*/
public void read(Image image, int layer, TexturePixel pixel, int index) {
this.read(image, layer, pixel, index % image.getWidth(), index / image.getWidth());
}
public void read(Image image, int layer, TexturePixel pixel, int x, int y) {
int xTexetlIndex = x % image.getWidth() >> 2;
int yTexelIndex = y % image.getHeight() >> 2;
int xTexelCount = image.getWidth() >> 2;
int texelIndex = yTexelIndex * xTexelCount + xTexetlIndex;
TexturePixel[] colors = new TexturePixel[] { new TexturePixel(), new TexturePixel(), new TexturePixel(), new TexturePixel() };
int indexes = 0;
long alphaIndexes = 0;
float[] alphas = null;
ByteBuffer data = image.getData().get(layer);
switch (image.getFormat()) {
case DXT1: // BC1
case DXT1A: {
data.position(texelIndex * 8);
short c0 = data.getShort();
short c1 = data.getShort();
int col0 = RGB565.RGB565_to_ARGB8(c0);
int col1 = RGB565.RGB565_to_ARGB8(c1);
colors[0].fromARGB8(col0);
colors[1].fromARGB8(col1);
if (col0 > col1) {
// creating color2 = 2/3color0 + 1/3color1
colors[2].fromPixel(colors[0]);
colors[2].mult(2);
colors[2].add(colors[1]);
colors[2].divide(3);
// creating color3 = 1/3color0 + 2/3color1;
colors[3].fromPixel(colors[1]);
colors[3].mult(2);
colors[3].add(colors[0]);
colors[3].divide(3);
} else {
// creating color2 = 1/2color0 + 1/2color1
colors[2].fromPixel(colors[0]);
colors[2].add(colors[1]);
colors[2].mult(0.5f);
colors[3].fromARGB8(0);
}
indexes = data.getInt();// 4-byte table with color indexes in decompressed table
break;
}
case DXT3: {// BC2
data.position(texelIndex * 16);
long alpha = data.getLong();
alphas = new float[16];
for (int i = 0; i < 16; ++i) {
alphaIndexes |= i << i * 4;
byte a = (byte) ((alpha >> i * 4 & 0x0F) << 4);
alphas[i] = a >= 0 ? a / 255.0f : 1.0f - ~a / 255.0f;
}
short c0 = data.getShort();
short c1 = data.getShort();
int col0 = RGB565.RGB565_to_ARGB8(c0);
int col1 = RGB565.RGB565_to_ARGB8(c1);
colors[0].fromARGB8(col0);
colors[1].fromARGB8(col1);
// creating color2 = 2/3color0 + 1/3color1
colors[2].fromPixel(colors[0]);
colors[2].mult(2);
colors[2].add(colors[1]);
colors[2].divide(3);
// creating color3 = 1/3color0 + 2/3color1;
colors[3].fromPixel(colors[1]);
colors[3].mult(2);
colors[3].add(colors[0]);
colors[3].divide(3);
indexes = data.getInt();// 4-byte table with color indexes in decompressed table
break;
}
case DXT5: {// BC3
data.position(texelIndex * 16);
alphas = new float[8];
alphas[0] = data.get() * 255.0f;
alphas[1] = data.get() * 255.0f;
// the casts to long must be done here because otherwise 32-bit integers would be shifetd by 32 and 40 bits which would result in improper values
alphaIndexes = (long)data.get() | (long)data.get() << 8 | (long)data.get() << 16 | (long)data.get() << 24 | (long)data.get() << 32 | (long)data.get() << 40;
if (alphas[0] > alphas[1]) {// 6 interpolated alpha values.
alphas[2] = (6 * alphas[0] + alphas[1]) / 7;
alphas[3] = (5 * alphas[0] + 2 * alphas[1]) / 7;
alphas[4] = (4 * alphas[0] + 3 * alphas[1]) / 7;
alphas[5] = (3 * alphas[0] + 4 * alphas[1]) / 7;
alphas[6] = (2 * alphas[0] + 5 * alphas[1]) / 7;
alphas[7] = (alphas[0] + 6 * alphas[1]) / 7;
} else {
alphas[2] = (4 * alphas[0] + alphas[1]) * 0.2f;
alphas[3] = (3 * alphas[0] + 2 * alphas[1]) * 0.2f;
alphas[4] = (2 * alphas[0] + 3 * alphas[1]) * 0.2f;
alphas[5] = (alphas[0] + 4 * alphas[1]) * 0.2f;
alphas[6] = 0;
alphas[7] = 1;
}
short c0 = data.getShort();
short c1 = data.getShort();
int col0 = RGB565.RGB565_to_ARGB8(c0);
int col1 = RGB565.RGB565_to_ARGB8(c1);
colors[0].fromARGB8(col0);
colors[1].fromARGB8(col1);
// creating color2 = 2/3color0 + 1/3color1
colors[2].fromPixel(colors[0]);
colors[2].mult(2);
colors[2].add(colors[1]);
colors[2].divide(3);
// creating color3 = 1/3color0 + 2/3color1;
colors[3].fromPixel(colors[1]);
colors[3].mult(2);
colors[3].add(colors[0]);
colors[3].divide(3);
indexes = data.getInt();// 4-byte table with color indexes in decompressed table
break;
}
default:
throw new IllegalStateException("Unsupported decompression format.");
}
// coordinates of the pixel in the selected texel
x = x - 4 * xTexetlIndex;// pixels are arranged from left to right
y = 3 - y - 4 * yTexelIndex;// pixels are arranged from bottom to top (that is why '3 - ...' is at the start)
int pixelIndexInTexel = (y * 4 + x) * (int) FastMath.log(colors.length, 2);
int alphaIndexInTexel = alphas != null ? (y * 4 + x) * (int) FastMath.log(alphas.length, 2) : 0;
// getting the pixel
int indexMask = colors.length - 1;
int colorIndex = indexes >> pixelIndexInTexel & indexMask;
float alpha = alphas != null ? alphas[(int) (alphaIndexes >> alphaIndexInTexel & 0x07)] : colors[colorIndex].alpha;
pixel.fromPixel(colors[colorIndex]);
pixel.alpha = alpha;
}
public void write(Image image, int layer, TexturePixel pixel, int index) {
throw new UnsupportedOperationException("Cannot put the DXT pixel by index because not every index contains the pixel color!");
}
public void write(Image image, int layer, TexturePixel pixel, int x, int y) {
throw new UnsupportedOperationException("Writing to DDS texture pixel by pixel is not yet supported!");
}
}