Home | History | Annotate | Download | only in blending
      1 package com.jme3.scene.plugins.blender.textures.blending;
      2 
      3 import java.nio.ByteBuffer;
      4 import java.util.ArrayList;
      5 import java.util.logging.Level;
      6 import java.util.logging.Logger;
      7 
      8 import com.jme3.math.FastMath;
      9 import com.jme3.scene.plugins.blender.BlenderContext;
     10 import com.jme3.texture.Image;
     11 import com.jme3.texture.Texture;
     12 import com.jme3.texture.Texture2D;
     13 import com.jme3.texture.Texture3D;
     14 import com.jme3.texture.Image.Format;
     15 import com.jme3.util.BufferUtils;
     16 
     17 /**
     18  * The class that is responsible for blending the following texture types:
     19  * <li> Luminance8
     20  * <li> Luminance8Alpha8
     21  * Not yet supported (but will be):
     22  * <li> Luminance16:
     23  * <li> Luminance16Alpha16:
     24  * <li> Luminance16F:
     25  * <li> Luminance16FAlpha16F:
     26  * <li> Luminance32F:
     27  * @author Marcin Roguski (Kaelthas)
     28  */
     29 public class TextureBlenderLuminance extends AbstractTextureBlender {
     30 	private static final Logger	LOGGER	= Logger.getLogger(TextureBlenderLuminance.class.getName());
     31 
     32 	@Override
     33 	public Texture blend(float[] materialColor, Texture texture, float[] color, float affectFactor, int blendType, boolean neg, BlenderContext blenderContext) {
     34 		Format format = texture.getImage().getFormat();
     35 		ByteBuffer data = texture.getImage().getData(0);
     36 		data.rewind();
     37 
     38 		int width = texture.getImage().getWidth();
     39 		int height = texture.getImage().getHeight();
     40 		int depth = texture.getImage().getDepth();
     41 		if (depth == 0) {
     42 			depth = 1;
     43 		}
     44 		ByteBuffer newData = BufferUtils.createByteBuffer(width * height * depth * 4);
     45 
     46 		float[] resultPixel = new float[4];
     47 		float[] tinAndAlpha = new float[2];
     48 		int dataIndex = 0;
     49 		while (data.hasRemaining()) {
     50 			this.getTinAndAlpha(data, format, neg, tinAndAlpha);
     51 			this.blendPixel(resultPixel, materialColor, color, tinAndAlpha[0], affectFactor, blendType, blenderContext);
     52 			newData.put(dataIndex++, (byte) (resultPixel[0] * 255.0f));
     53 			newData.put(dataIndex++, (byte) (resultPixel[1] * 255.0f));
     54 			newData.put(dataIndex++, (byte) (resultPixel[2] * 255.0f));
     55 			newData.put(dataIndex++, (byte) (tinAndAlpha[1] * 255.0f));
     56 		}
     57 		if (texture.getType() == Texture.Type.TwoDimensional) {
     58 			return new Texture2D(new Image(Format.RGBA8, width, height, newData));
     59 		} else {
     60 			ArrayList<ByteBuffer> dataArray = new ArrayList<ByteBuffer>(1);
     61 			dataArray.add(newData);
     62 			return new Texture3D(new Image(Format.RGBA8, width, height, depth, dataArray));
     63 		}
     64 	}
     65 
     66 	/**
     67 	 * This method return texture intensity and alpha value.
     68 	 *
     69 	 * @param data
     70 	 *            the texture data
     71 	 * @param imageFormat
     72 	 *            the image format
     73 	 * @param neg
     74 	 *            indicates if the texture is negated
     75 	 * @param result
     76 	 *            the table (2 elements) where the result is being stored
     77 	 */
     78 	protected void getTinAndAlpha(ByteBuffer data, Format imageFormat, boolean neg, float[] result) {
     79 		byte pixelValue = data.get();// at least one byte is always taken
     80 		float firstPixelValue = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
     81 		switch (imageFormat) {
     82 			case Luminance8:
     83 				result[0] = neg ? 1.0f - firstPixelValue : firstPixelValue;
     84 				result[1] = 1.0f;
     85 				break;
     86 			case Luminance8Alpha8:
     87 				result[0] = neg ? 1.0f - firstPixelValue : firstPixelValue;
     88 				pixelValue = data.get();
     89 				result[1] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
     90 				break;
     91 			case Luminance16:
     92 			case Luminance16Alpha16:
     93 			case Luminance16F:
     94 			case Luminance16FAlpha16F:
     95 			case Luminance32F:
     96 				LOGGER.log(Level.WARNING, "Image type not yet supported for blending: {0}", imageFormat);
     97 				break;
     98 			default:
     99 				throw new IllegalStateException("Invalid image format type for DDS texture blender: " + imageFormat);
    100 		}
    101 	}
    102 
    103 	/**
    104 	 * This method blends the texture with an appropriate color.
    105 	 *
    106 	 * @param result
    107 	 *            the result color (variable 'in' in blender source code)
    108 	 * @param materialColor
    109 	 *            the texture color (variable 'out' in blender source coude)
    110 	 * @param color
    111 	 *            the previous color (variable 'tex' in blender source code)
    112 	 * @param textureIntensity
    113 	 *            texture intensity (variable 'fact' in blender source code)
    114 	 * @param textureFactor
    115 	 *            texture affection factor (variable 'facg' in blender source
    116 	 *            code)
    117 	 * @param blendtype
    118 	 *            the blend type
    119 	 * @param blenderContext
    120 	 *            the blender context
    121 	 */
    122 	protected void blendPixel(float[] result, float[] materialColor, float[] color, float textureIntensity, float textureFactor, int blendtype, BlenderContext blenderContext) {
    123 		float oneMinusFactor, col;
    124 		textureIntensity *= textureFactor;
    125 
    126 		switch (blendtype) {
    127 			case MTEX_BLEND:
    128 				oneMinusFactor = 1.0f - textureIntensity;
    129 				result[0] = textureIntensity * color[0] + oneMinusFactor * materialColor[0];
    130 				result[1] = textureIntensity * color[1] + oneMinusFactor * materialColor[1];
    131 				result[2] = textureIntensity * color[2] + oneMinusFactor * materialColor[2];
    132 				break;
    133 			case MTEX_MUL:
    134 				oneMinusFactor = 1.0f - textureFactor;
    135 				result[0] = (oneMinusFactor + textureIntensity * materialColor[0]) * color[0];
    136 				result[1] = (oneMinusFactor + textureIntensity * materialColor[1]) * color[1];
    137 				result[2] = (oneMinusFactor + textureIntensity * materialColor[2]) * color[2];
    138 				break;
    139 			case MTEX_DIV:
    140 				oneMinusFactor = 1.0f - textureIntensity;
    141 				if (color[0] != 0.0) {
    142 					result[0] = (oneMinusFactor * materialColor[0] + textureIntensity * materialColor[0] / color[0]) * 0.5f;
    143 				}
    144 				if (color[1] != 0.0) {
    145 					result[1] = (oneMinusFactor * materialColor[1] + textureIntensity * materialColor[1] / color[1]) * 0.5f;
    146 				}
    147 				if (color[2] != 0.0) {
    148 					result[2] = (oneMinusFactor * materialColor[2] + textureIntensity * materialColor[2] / color[2]) * 0.5f;
    149 				}
    150 				break;
    151 			case MTEX_SCREEN:
    152 				oneMinusFactor = 1.0f - textureFactor;
    153 				result[0] = 1.0f - (oneMinusFactor + textureIntensity * (1.0f - materialColor[0])) * (1.0f - color[0]);
    154 				result[1] = 1.0f - (oneMinusFactor + textureIntensity * (1.0f - materialColor[1])) * (1.0f - color[1]);
    155 				result[2] = 1.0f - (oneMinusFactor + textureIntensity * (1.0f - materialColor[2])) * (1.0f - color[2]);
    156 				break;
    157 			case MTEX_OVERLAY:
    158 				oneMinusFactor = 1.0f - textureFactor;
    159 				if (materialColor[0] < 0.5f) {
    160 					result[0] = color[0] * (oneMinusFactor + 2.0f * textureIntensity * materialColor[0]);
    161 				} else {
    162 					result[0] = 1.0f - (oneMinusFactor + 2.0f * textureIntensity * (1.0f - materialColor[0])) * (1.0f - color[0]);
    163 				}
    164 				if (materialColor[1] < 0.5f) {
    165 					result[1] = color[1] * (oneMinusFactor + 2.0f * textureIntensity * materialColor[1]);
    166 				} else {
    167 					result[1] = 1.0f - (oneMinusFactor + 2.0f * textureIntensity * (1.0f - materialColor[1])) * (1.0f - color[1]);
    168 				}
    169 				if (materialColor[2] < 0.5f) {
    170 					result[2] = color[2] * (oneMinusFactor + 2.0f * textureIntensity * materialColor[2]);
    171 				} else {
    172 					result[2] = 1.0f - (oneMinusFactor + 2.0f * textureIntensity * (1.0f - materialColor[2])) * (1.0f - color[2]);
    173 				}
    174 				break;
    175 			case MTEX_SUB:
    176 				result[0] = materialColor[0] - textureIntensity * color[0];
    177 				result[1] = materialColor[1] - textureIntensity * color[1];
    178 				result[2] = materialColor[2] - textureIntensity * color[2];
    179 				result[0] = FastMath.clamp(result[0], 0.0f, 1.0f);
    180 				result[1] = FastMath.clamp(result[1], 0.0f, 1.0f);
    181 				result[2] = FastMath.clamp(result[2], 0.0f, 1.0f);
    182 				break;
    183 			case MTEX_ADD:
    184 				result[0] = (textureIntensity * color[0] + materialColor[0]) * 0.5f;
    185 				result[1] = (textureIntensity * color[1] + materialColor[1]) * 0.5f;
    186 				result[2] = (textureIntensity * color[2] + materialColor[2]) * 0.5f;
    187 				break;
    188 			case MTEX_DIFF:
    189 				oneMinusFactor = 1.0f - textureIntensity;
    190 				result[0] = oneMinusFactor * materialColor[0] + textureIntensity * Math.abs(materialColor[0] - color[0]);
    191 				result[1] = oneMinusFactor * materialColor[1] + textureIntensity * Math.abs(materialColor[1] - color[1]);
    192 				result[2] = oneMinusFactor * materialColor[2] + textureIntensity * Math.abs(materialColor[2] - color[2]);
    193 				break;
    194 			case MTEX_DARK:
    195 				col = textureIntensity * color[0];
    196 				result[0] = col < materialColor[0] ? col : materialColor[0];
    197 				col = textureIntensity * color[1];
    198 				result[1] = col < materialColor[1] ? col : materialColor[1];
    199 				col = textureIntensity * color[2];
    200 				result[2] = col < materialColor[2] ? col : materialColor[2];
    201 				break;
    202 			case MTEX_LIGHT:
    203 				col = textureIntensity * color[0];
    204 				result[0] = col > materialColor[0] ? col : materialColor[0];
    205 				col = textureIntensity * color[1];
    206 				result[1] = col > materialColor[1] ? col : materialColor[1];
    207 				col = textureIntensity * color[2];
    208 				result[2] = col > materialColor[2] ? col : materialColor[2];
    209 				break;
    210 			case MTEX_BLEND_HUE:
    211 			case MTEX_BLEND_SAT:
    212 			case MTEX_BLEND_VAL:
    213 			case MTEX_BLEND_COLOR:
    214 				System.arraycopy(materialColor, 0, result, 0, 3);
    215 				this.blendHSV(blendtype, result, textureIntensity, color, blenderContext);
    216 				break;
    217 			default:
    218 				throw new IllegalStateException("Unknown blend type: " + blendtype);
    219 		}
    220 	}
    221 }
    222