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.math.FastMath;
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:
*
Luminance8
* Luminance8Alpha8
* Not yet supported (but will be):
* Luminance16:
* Luminance16Alpha16:
* Luminance16F:
* Luminance16FAlpha16F:
* Luminance32F:
* @author Marcin Roguski (Kaelthas)
*/
public class TextureBlenderLuminance extends AbstractTextureBlender {
private static final Logger LOGGER = Logger.getLogger(TextureBlenderLuminance.class.getName());
@Override
public Texture blend(float[] materialColor, Texture texture, float[] color, float affectFactor, int blendType, boolean neg, BlenderContext blenderContext) {
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];
float[] tinAndAlpha = new float[2];
int dataIndex = 0;
while (data.hasRemaining()) {
this.getTinAndAlpha(data, format, neg, tinAndAlpha);
this.blendPixel(resultPixel, materialColor, color, tinAndAlpha[0], 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) (tinAndAlpha[1] * 255.0f));
}
if (texture.getType() == Texture.Type.TwoDimensional) {
return new Texture2D(new Image(Format.RGBA8, width, height, newData));
} else {
ArrayList dataArray = new ArrayList(1);
dataArray.add(newData);
return new Texture3D(new Image(Format.RGBA8, width, height, depth, dataArray));
}
}
/**
* This method return texture intensity and alpha value.
*
* @param data
* the texture data
* @param imageFormat
* the image format
* @param neg
* indicates if the texture is negated
* @param result
* the table (2 elements) where the result is being stored
*/
protected void getTinAndAlpha(ByteBuffer data, Format imageFormat, boolean neg, float[] result) {
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 Luminance8:
result[0] = neg ? 1.0f - firstPixelValue : firstPixelValue;
result[1] = 1.0f;
break;
case Luminance8Alpha8:
result[0] = neg ? 1.0f - firstPixelValue : firstPixelValue;
pixelValue = data.get();
result[1] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
break;
case Luminance16:
case Luminance16Alpha16:
case Luminance16F:
case Luminance16FAlpha16F:
case Luminance32F:
LOGGER.log(Level.WARNING, "Image type not yet supported for blending: {0}", imageFormat);
break;
default:
throw new IllegalStateException("Invalid image format type for DDS texture blender: " + imageFormat);
}
}
/**
* This method blends the texture with an appropriate color.
*
* @param result
* the result color (variable 'in' in blender source code)
* @param materialColor
* the texture color (variable 'out' in blender source coude)
* @param color
* the previous color (variable 'tex' in blender source code)
* @param textureIntensity
* texture intensity (variable 'fact' in blender source code)
* @param textureFactor
* texture affection factor (variable 'facg' in blender source
* code)
* @param blendtype
* the blend type
* @param blenderContext
* the blender context
*/
protected void blendPixel(float[] result, float[] materialColor, float[] color, float textureIntensity, float textureFactor, int blendtype, BlenderContext blenderContext) {
float oneMinusFactor, col;
textureIntensity *= textureFactor;
switch (blendtype) {
case MTEX_BLEND:
oneMinusFactor = 1.0f - textureIntensity;
result[0] = textureIntensity * color[0] + oneMinusFactor * materialColor[0];
result[1] = textureIntensity * color[1] + oneMinusFactor * materialColor[1];
result[2] = textureIntensity * color[2] + oneMinusFactor * materialColor[2];
break;
case MTEX_MUL:
oneMinusFactor = 1.0f - textureFactor;
result[0] = (oneMinusFactor + textureIntensity * materialColor[0]) * color[0];
result[1] = (oneMinusFactor + textureIntensity * materialColor[1]) * color[1];
result[2] = (oneMinusFactor + textureIntensity * materialColor[2]) * color[2];
break;
case MTEX_DIV:
oneMinusFactor = 1.0f - textureIntensity;
if (color[0] != 0.0) {
result[0] = (oneMinusFactor * materialColor[0] + textureIntensity * materialColor[0] / color[0]) * 0.5f;
}
if (color[1] != 0.0) {
result[1] = (oneMinusFactor * materialColor[1] + textureIntensity * materialColor[1] / color[1]) * 0.5f;
}
if (color[2] != 0.0) {
result[2] = (oneMinusFactor * materialColor[2] + textureIntensity * materialColor[2] / color[2]) * 0.5f;
}
break;
case MTEX_SCREEN:
oneMinusFactor = 1.0f - textureFactor;
result[0] = 1.0f - (oneMinusFactor + textureIntensity * (1.0f - materialColor[0])) * (1.0f - color[0]);
result[1] = 1.0f - (oneMinusFactor + textureIntensity * (1.0f - materialColor[1])) * (1.0f - color[1]);
result[2] = 1.0f - (oneMinusFactor + textureIntensity * (1.0f - materialColor[2])) * (1.0f - color[2]);
break;
case MTEX_OVERLAY:
oneMinusFactor = 1.0f - textureFactor;
if (materialColor[0] < 0.5f) {
result[0] = color[0] * (oneMinusFactor + 2.0f * textureIntensity * materialColor[0]);
} else {
result[0] = 1.0f - (oneMinusFactor + 2.0f * textureIntensity * (1.0f - materialColor[0])) * (1.0f - color[0]);
}
if (materialColor[1] < 0.5f) {
result[1] = color[1] * (oneMinusFactor + 2.0f * textureIntensity * materialColor[1]);
} else {
result[1] = 1.0f - (oneMinusFactor + 2.0f * textureIntensity * (1.0f - materialColor[1])) * (1.0f - color[1]);
}
if (materialColor[2] < 0.5f) {
result[2] = color[2] * (oneMinusFactor + 2.0f * textureIntensity * materialColor[2]);
} else {
result[2] = 1.0f - (oneMinusFactor + 2.0f * textureIntensity * (1.0f - materialColor[2])) * (1.0f - color[2]);
}
break;
case MTEX_SUB:
result[0] = materialColor[0] - textureIntensity * color[0];
result[1] = materialColor[1] - textureIntensity * color[1];
result[2] = materialColor[2] - textureIntensity * color[2];
result[0] = FastMath.clamp(result[0], 0.0f, 1.0f);
result[1] = FastMath.clamp(result[1], 0.0f, 1.0f);
result[2] = FastMath.clamp(result[2], 0.0f, 1.0f);
break;
case MTEX_ADD:
result[0] = (textureIntensity * color[0] + materialColor[0]) * 0.5f;
result[1] = (textureIntensity * color[1] + materialColor[1]) * 0.5f;
result[2] = (textureIntensity * color[2] + materialColor[2]) * 0.5f;
break;
case MTEX_DIFF:
oneMinusFactor = 1.0f - textureIntensity;
result[0] = oneMinusFactor * materialColor[0] + textureIntensity * Math.abs(materialColor[0] - color[0]);
result[1] = oneMinusFactor * materialColor[1] + textureIntensity * Math.abs(materialColor[1] - color[1]);
result[2] = oneMinusFactor * materialColor[2] + textureIntensity * Math.abs(materialColor[2] - color[2]);
break;
case MTEX_DARK:
col = textureIntensity * color[0];
result[0] = col < materialColor[0] ? col : materialColor[0];
col = textureIntensity * color[1];
result[1] = col < materialColor[1] ? col : materialColor[1];
col = textureIntensity * color[2];
result[2] = col < materialColor[2] ? col : materialColor[2];
break;
case MTEX_LIGHT:
col = textureIntensity * color[0];
result[0] = col > materialColor[0] ? col : materialColor[0];
col = textureIntensity * color[1];
result[1] = col > materialColor[1] ? col : materialColor[1];
col = textureIntensity * color[2];
result[2] = col > materialColor[2] ? col : materialColor[2];
break;
case MTEX_BLEND_HUE:
case MTEX_BLEND_SAT:
case MTEX_BLEND_VAL:
case MTEX_BLEND_COLOR:
System.arraycopy(materialColor, 0, result, 0, 3);
this.blendHSV(blendtype, result, textureIntensity, color, blenderContext);
break;
default:
throw new IllegalStateException("Unknown blend type: " + blendtype);
}
}
}