blob: 918072e41227858c1cd57e65a4b48289f6c94cde [file] [log] [blame]
package com.jme3.scene.plugins.blender.textures.blending;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.jme3.scene.plugins.blender.BlenderContext;
import com.jme3.texture.Image;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture2D;
import com.jme3.texture.Texture3D;
import com.jme3.texture.Image.Format;
import com.jme3.util.BufferUtils;
/**
* The class that is responsible for blending the following texture types:
* <li> RGBA8
* <li> ABGR8
* <li> BGR8
* <li> RGB8
* Not yet supported (but will be):
* <li> ARGB4444:
* <li> RGB10:
* <li> RGB111110F:
* <li> RGB16:
* <li> RGB16F:
* <li> RGB16F_to_RGB111110F:
* <li> RGB16F_to_RGB9E5:
* <li> RGB32F:
* <li> RGB565:
* <li> RGB5A1:
* <li> RGB9E5:
* <li> RGBA16:
* <li> RGBA16F
* @author Marcin Roguski (Kaelthas)
*/
public class TextureBlenderAWT extends AbstractTextureBlender {
private static final Logger LOGGER = Logger.getLogger(TextureBlenderAWT.class.getName());
@Override
public Texture blend(float[] materialColor, Texture texture, float[] color, float affectFactor, int blendType, boolean neg, BlenderContext blenderContext) {
float[] pixelColor = new float[] { color[0], color[1], color[2], 1.0f };
Format format = texture.getImage().getFormat();
ByteBuffer data = texture.getImage().getData(0);
data.rewind();
int width = texture.getImage().getWidth();
int height = texture.getImage().getHeight();
int depth = texture.getImage().getDepth();
if (depth == 0) {
depth = 1;
}
ByteBuffer newData = BufferUtils.createByteBuffer(width * height * depth * 4);
float[] resultPixel = new float[4];
int dataIndex = 0;
while (data.hasRemaining()) {
this.setupMaterialColor(data, format, neg, pixelColor);
this.blendPixel(resultPixel, materialColor, pixelColor, affectFactor, blendType, blenderContext);
newData.put(dataIndex++, (byte) (resultPixel[0] * 255.0f));
newData.put(dataIndex++, (byte) (resultPixel[1] * 255.0f));
newData.put(dataIndex++, (byte) (resultPixel[2] * 255.0f));
newData.put(dataIndex++, (byte) (pixelColor[3] * 255.0f));
}
if (texture.getType() == Texture.Type.TwoDimensional) {
return new Texture2D(new Image(Format.RGBA8, width, height, newData));
} else {
ArrayList<ByteBuffer> dataArray = new ArrayList<ByteBuffer>(1);
dataArray.add(newData);
return new Texture3D(new Image(Format.RGBA8, width, height, depth, dataArray));
}
}
/**
* This method alters the material color in a way dependent on the type of
* the image. For example the color remains untouched if the texture is of
* Luminance type. The luminance defines the interaction between the
* material color and color defined for texture blending. If the type has 3
* or more color channels then the material color is replaced with the
* texture's color and later blended with the defined blend color. All alpha
* values (if present) are ignored and not used during blending.
*
* @param data
* the image data
* @param imageFormat
* the format of the image
* @param neg
* defines it the result color should be nagated
* @param materialColor
* the material's color (value may be changed)
* @return texture intensity for the current pixel
*/
protected float setupMaterialColor(ByteBuffer data, Format imageFormat, boolean neg, float[] materialColor) {
float tin = 0.0f;
byte pixelValue = data.get();// at least one byte is always taken :)
float firstPixelValue = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
switch (imageFormat) {
case RGBA8:
materialColor[0] = firstPixelValue;
pixelValue = data.get();
materialColor[1] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
pixelValue = data.get();
materialColor[2] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
pixelValue = data.get();
materialColor[3] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
break;
case ABGR8:
materialColor[3] = firstPixelValue;
pixelValue = data.get();
materialColor[2] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
pixelValue = data.get();
materialColor[1] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
pixelValue = data.get();
materialColor[0] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
break;
case BGR8:
materialColor[2] = firstPixelValue;
pixelValue = data.get();
materialColor[1] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
pixelValue = data.get();
materialColor[0] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
materialColor[3] = 1.0f;
break;
case RGB8:
materialColor[0] = firstPixelValue;
pixelValue = data.get();
materialColor[1] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
pixelValue = data.get();
materialColor[2] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
materialColor[3] = 1.0f;
break;
case ARGB4444:
case RGB10:
case RGB111110F:
case RGB16:
case RGB16F:
case RGB16F_to_RGB111110F:
case RGB16F_to_RGB9E5:
case RGB32F:
case RGB565:
case RGB5A1:
case RGB9E5:
case RGBA16:
case RGBA16F:
case RGBA32F:// TODO: implement these textures
LOGGER.log(Level.WARNING, "Image type not yet supported for blending: {0}", imageFormat);
break;
default:
throw new IllegalStateException("Invalid image format type for AWT texture blender: " + imageFormat);
}
if (neg) {
materialColor[0] = 1.0f - materialColor[0];
materialColor[1] = 1.0f - materialColor[1];
materialColor[2] = 1.0f - materialColor[2];
}
// Blender formula for texture intensity calculation:
// 0.35*texres.tr+0.45*texres.tg+0.2*texres.tb
tin = 0.35f * materialColor[0] + 0.45f * materialColor[1] + 0.2f * materialColor[2];
return tin;
}
}