Browse Source

Better support for textures blending.
- support for DDS blending (without textures decompression :) )
- support for RGBA textures blending
- support for generated textures blending
Also done blending refactoring. Blending functions moved to separated classes from TextureHelper.
It will increase code redability.

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9188 75d07b2b-3a1a-0410-a2c5-0572b91ccdca

Kae..pl 13 years ago
parent
commit
2b004e803d

+ 7 - 4
engine/src/blender/com/jme3/scene/plugins/blender/materials/MaterialContext.java

@@ -9,6 +9,8 @@ import com.jme3.scene.plugins.blender.file.Structure;
 import com.jme3.scene.plugins.blender.materials.MaterialHelper.DiffuseShader;
 import com.jme3.scene.plugins.blender.materials.MaterialHelper.DiffuseShader;
 import com.jme3.scene.plugins.blender.materials.MaterialHelper.SpecularShader;
 import com.jme3.scene.plugins.blender.materials.MaterialHelper.SpecularShader;
 import com.jme3.scene.plugins.blender.textures.TextureHelper;
 import com.jme3.scene.plugins.blender.textures.TextureHelper;
+import com.jme3.scene.plugins.blender.textures.blending.TextureBlender;
+import com.jme3.scene.plugins.blender.textures.blending.TextureBlenderFactory;
 import com.jme3.texture.Texture;
 import com.jme3.texture.Texture;
 import com.jme3.texture.Texture.Type;
 import com.jme3.texture.Texture.Type;
 import com.jme3.texture.Texture.WrapMode;
 import com.jme3.texture.Texture.WrapMode;
@@ -140,9 +142,6 @@ public final class MaterialContext {
 		Map<Number, List<Structure[]>> sortedTextures = this.sortAndFilterTextures();
 		Map<Number, List<Structure[]>> sortedTextures = this.sortAndFilterTextures();
 		loadedTextures = new HashMap<Number, Texture>(sortedTextures.size());
 		loadedTextures = new HashMap<Number, Texture>(sortedTextures.size());
 		textureToMTexMap = new HashMap<Texture, Structure>();
 		textureToMTexMap = new HashMap<Texture, Structure>();
-		if(sortedTextures.size() > 0) {//texutre covers the material color
-			diffuseColor.set(1, 1, 1, 1);
-		}
 		float[] diffuseColorArray = new float[] {diffuseColor.r, diffuseColor.g, diffuseColor.b, diffuseColor.a};
 		float[] diffuseColorArray = new float[] {diffuseColor.r, diffuseColor.g, diffuseColor.b, diffuseColor.a};
 		TextureHelper textureHelper = blenderContext.getHelper(TextureHelper.class);
 		TextureHelper textureHelper = blenderContext.getHelper(TextureHelper.class);
 		for(Entry<Number, List<Structure[]>> entry : sortedTextures.entrySet()) {
 		for(Entry<Number, List<Structure[]>> entry : sortedTextures.entrySet()) {
@@ -157,7 +156,8 @@ public final class MaterialContext {
 												  ((Number) mtexAndTex[0].getFieldValue("g")).floatValue(), 
 												  ((Number) mtexAndTex[0].getFieldValue("g")).floatValue(), 
 												  ((Number) mtexAndTex[0].getFieldValue("b")).floatValue() };
 												  ((Number) mtexAndTex[0].getFieldValue("b")).floatValue() };
 					float colfac = ((Number) mtexAndTex[0].getFieldValue("colfac")).floatValue();
 					float colfac = ((Number) mtexAndTex[0].getFieldValue("colfac")).floatValue();
-					texture = textureHelper.blendTexture(diffuseColorArray, texture, color, colfac, blendType, negateTexture, blenderContext);
+					TextureBlender textureBlender = TextureBlenderFactory.createTextureBlender(texture.getImage().getFormat());
+					texture = textureBlender.blend(diffuseColorArray, texture, color, colfac, blendType, negateTexture, blenderContext);
 					texture.setWrap(WrapMode.Repeat);
 					texture.setWrap(WrapMode.Repeat);
 					textures.add(texture);
 					textures.add(texture);
 					textureToMTexMap.put(texture, mtexAndTex[0]);
 					textureToMTexMap.put(texture, mtexAndTex[0]);
@@ -175,6 +175,9 @@ public final class MaterialContext {
 		boolean transparent = false;
 		boolean transparent = false;
 		if(diffuseColor != null) {
 		if(diffuseColor != null) {
 			transparent = diffuseColor.a < 1.0f;
 			transparent = diffuseColor.a < 1.0f;
+			if(sortedTextures.size() > 0) {//texutre covers the material color
+				diffuseColor.set(1, 1, 1, 1);
+			}
 		}
 		}
 		if(specularColor != null) {
 		if(specularColor != null) {
 			transparent = transparent || specularColor.a < 1.0f;
 			transparent = transparent || specularColor.a < 1.0f;

+ 0 - 304
engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureDecompressor.java

@@ -1,304 +0,0 @@
-package com.jme3.scene.plugins.blender.textures;
-
-import java.nio.ByteBuffer;
-import java.util.logging.Logger;
-
-import jme3tools.converters.RGB565;
-
-import com.jme3.math.FastMath;
-import com.jme3.texture.Image;
-import com.jme3.texture.Image.Format;
-import com.jme3.util.BufferUtils;
-
-/**
- * This class decompresses the given image (if necessary) to the RGBA8 format.
- * Currently supported compressed textures are: DXT1, DXT3, DXT5.
- * @author Marcin Roguski (Kaelthas)
- */
-/*package*/ class TextureDecompressor {
-	private static final Logger	LOGGER	= Logger.getLogger(TextureDecompressor.class.getName());
-
-	/**
-	 * This method decompresses the given image. If the given image is already
-	 * decompressed nothing happens and it is simply returned.
-	 * 
-	 * @param image
-	 *            the image to decompress
-	 * @return the decompressed image
-	 */
-	public static Image decompress(Image image) {//TODO: support 3D textures
-		byte[] bytes = null;
-		TexturePixel[] colors = null;
-		ByteBuffer data = image.getData(0);
-		data.rewind();
-		Format format = image.getFormat();
-
-		DDSTexelData texelData = new DDSTexelData(data.remaining() / (format.getBitsPerPixel() * 2), image.getWidth(), image.getHeight(), format != Format.DXT1);
-		switch (format) {// TODO: DXT1A
-			case DXT1:// BC1
-				bytes = new byte[image.getWidth() * image.getHeight() * 4];
-				colors = new TexturePixel[] { new TexturePixel(), new TexturePixel(), new TexturePixel(), new TexturePixel() };
-				while (data.hasRemaining()) {
-					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);
-					}
-					int indexes = data.getInt();// 4-byte table with color indexes in decompressed table
-					texelData.add(colors, indexes);
-				}
-				break;
-			case DXT3:// BC2
-				bytes = new byte[image.getWidth() * image.getHeight() * 4];
-				colors = new TexturePixel[] { new TexturePixel(), new TexturePixel(), new TexturePixel(), new TexturePixel() };
-				while (data.hasRemaining()) {
-					long alpha = data.getLong();
-					float[] alphas = new float[16];
-					long alphasIndex = 0;
-					for (int i = 0; i < 16; ++i) {
-						alphasIndex |= 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);
-
-					int indexes = data.getInt();// 4-byte table with color indexes in decompressed table
-					texelData.add(colors, indexes, alphas, alphasIndex);
-				}
-				break;
-			case DXT5:// BC3
-				bytes = new byte[image.getWidth() * image.getHeight() * 4];
-				colors = new TexturePixel[] { new TexturePixel(), new TexturePixel(), new TexturePixel(), new TexturePixel() };
-				float[] alphas = new float[8];
-				while (data.hasRemaining()) {
-					alphas[0] = data.get() * 255.0f;
-					alphas[1] = data.get() * 255.0f;
-					long alphaIndices = (int) data.get() | ((int) data.get() << 8) | ((int) data.get() << 16) | ((int) data.get() << 24) | ((int) data.get() << 32) | ((int) 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);
-
-					int indexes = data.getInt();// 4-byte table with color
-												// indexes in decompressed table
-					texelData.add(colors, indexes, alphas, alphaIndices);
-				}
-				break;
-			default:
-				LOGGER.fine("Unsupported decompression format.");
-		}
-
-		if (bytes != null) {// writing the data to the result table
-			byte[] pixelBytes = new byte[4];
-			for (int i = 0; i < image.getWidth(); ++i) {
-				for (int j = 0; j < image.getHeight(); ++j) {
-					texelData.getRGBA8(i, j, pixelBytes);
-					bytes[(j * image.getWidth() + i) * 4] = pixelBytes[0];
-					bytes[(j * image.getWidth() + i) * 4 + 1] = pixelBytes[1];
-					bytes[(j * image.getWidth() + i) * 4 + 2] = pixelBytes[2];
-					bytes[(j * image.getWidth() + i) * 4 + 3] = pixelBytes[3];
-				}
-			}
-			return new Image(Format.RGBA8, image.getWidth(), image.getHeight(), BufferUtils.createByteBuffer(bytes));
-		}
-		return image;
-	}
-
-	/**
-	 * The data that helps in bytes calculations for the result image.
-	 * 
-	 * @author Marcin Roguski (Kaelthas)
-	 */
-	private static class DDSTexelData {
-		/** The colors of the texes. */
-		private TexturePixel[][]	colors;
-		/** The indexes of the texels. */
-		private long[]				indexes;
-		/** The alphas of the texels (might be null). */
-		private float[][]			alphas;
-		/** The indexels of texels alpha values (might be null). */
-		private long[]				alphaIndexes;
-		/** The counter of texel x column. */
-		private int					xCounter;
-		/** The counter of texel y row. */
-		private int					yCounter;
-		/** The width of the image in pixels. */
-		private int					pixelWidth;
-		/** The height of the image in pixels. */
-		private int					pixelHeight;
-		/** The total texel count. */
-		private int					xTexelCount;
-
-		/**
-		 * Constructor. Allocates the required memory. Initializes variables.
-		 * 
-		 * @param textelsCount
-		 *            the total count of the texels
-		 * @param pixelWidth
-		 *            the width of the image in pixels
-		 * @param pixelHeight
-		 *            the height of the image in pixels
-		 * @param isAlpha
-		 *            indicates if the memory for alpha values should be
-		 *            allocated
-		 */
-		public DDSTexelData(int textelsCount, int pixelWidth, int pixelHeight, boolean isAlpha) {
-			textelsCount = (pixelWidth * pixelHeight) >> 4;
-			this.colors = new TexturePixel[textelsCount][];
-			this.indexes = new long[textelsCount];
-			this.xTexelCount = pixelWidth >> 2;
-			this.yCounter = (pixelHeight >> 2) - 1;// xCounter is 0 for now
-			this.pixelHeight = pixelHeight;
-			this.pixelWidth = pixelWidth;
-			if (isAlpha) {
-				this.alphas = new float[textelsCount][];
-				this.alphaIndexes = new long[textelsCount];
-			}
-		}
-
-		/**
-		 * This method adds a color and indexes for a texel.
-		 * 
-		 * @param colors
-		 *            the colors of the texel
-		 * @param indexes
-		 *            the indexes of the texel
-		 */
-		public void add(TexturePixel[] colors, int indexes) {
-			this.add(colors, indexes, null, 0);
-		}
-
-		/**
-		 * This method adds a color, color indexes and alha values (with their
-		 * indexes) for a texel.
-		 * 
-		 * @param colors
-		 *            the colors of the texel
-		 * @param indexes
-		 *            the indexes of the texel
-		 * @param alphas
-		 *            the alpha values
-		 * @param alphaIndexes
-		 *            the indexes of the given alpha values
-		 */
-		public void add(TexturePixel[] colors, int indexes, float[] alphas, long alphaIndexes) {
-			int index = yCounter * xTexelCount + xCounter;
-			this.colors[index] = colors;
-			this.indexes[index] = indexes;
-			if (alphas != null) {
-				this.alphas[index] = alphas;
-				this.alphaIndexes[index] = alphaIndexes;
-			}
-			++this.xCounter;
-			if (this.xCounter >= this.xTexelCount) {
-				this.xCounter = 0;
-				--this.yCounter;
-			}
-		}
-
-		/**
-		 * This method returns the values of the pixel located on the given
-		 * coordinates on the result image.
-		 * 
-		 * @param x
-		 *            the x coordinate of the pixel
-		 * @param y
-		 *            the y coordinate of the pixel
-		 * @param result
-		 *            the table where the result is stored
-		 */
-		public void getRGBA8(int x, int y, byte[] result) {
-			int xTexetlIndex = (x % pixelWidth) / 4;
-			int yTexelIndex = (y % pixelHeight) / 4;
-
-			int texelIndex = yTexelIndex * xTexelCount + xTexetlIndex;
-			TexturePixel[] colors = this.colors[texelIndex];
-
-			// 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 = (int) ((this.indexes[texelIndex] >> pixelIndexInTexel) & indexMask);
-			float alpha = this.alphas != null ? this.alphas[texelIndex][(int) ((this.alphaIndexes[texelIndex] >> alphaIndexInTexel) & 0x07)] : colors[colorIndex].alpha;
-			result[0] = (byte) (colors[colorIndex].red * 255.0f);
-			result[1] = (byte) (colors[colorIndex].green * 255.0f);
-			result[2] = (byte) (colors[colorIndex].blue * 255.0f);
-			result[3] = (byte) (alpha * 255.0f);
-		}
-	}
-}

+ 3 - 381
engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureHelper.java

@@ -51,7 +51,6 @@ import com.jme3.asset.BlenderKey.FeaturesToLoad;
 import com.jme3.asset.GeneratedTextureKey;
 import com.jme3.asset.GeneratedTextureKey;
 import com.jme3.asset.TextureKey;
 import com.jme3.asset.TextureKey;
 import com.jme3.math.ColorRGBA;
 import com.jme3.math.ColorRGBA;
-import com.jme3.math.FastMath;
 import com.jme3.math.Vector3f;
 import com.jme3.math.Vector3f;
 import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
 import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext;
@@ -61,7 +60,6 @@ import com.jme3.scene.plugins.blender.file.FileBlockHeader;
 import com.jme3.scene.plugins.blender.file.Pointer;
 import com.jme3.scene.plugins.blender.file.Pointer;
 import com.jme3.scene.plugins.blender.file.Structure;
 import com.jme3.scene.plugins.blender.file.Structure;
 import com.jme3.scene.plugins.blender.materials.MaterialContext;
 import com.jme3.scene.plugins.blender.materials.MaterialContext;
-import com.jme3.scene.plugins.blender.materials.MaterialHelper;
 import com.jme3.texture.Image;
 import com.jme3.texture.Image;
 import com.jme3.texture.Image.Format;
 import com.jme3.texture.Image.Format;
 import com.jme3.texture.Texture;
 import com.jme3.texture.Texture;
@@ -115,23 +113,6 @@ public class TextureHelper extends AbstractBlenderHelper {
 	public static final int		MAP_WARP			= 8192;
 	public static final int		MAP_WARP			= 8192;
 	public static final int		MAP_LAYER			= 16384;
 	public static final int		MAP_LAYER			= 16384;
 
 
-	// blendtypes
-	public static final int		MTEX_BLEND			= 0;
-	public static final int		MTEX_MUL			= 1;
-	public static final int		MTEX_ADD			= 2;
-	public static final int		MTEX_SUB			= 3;
-	public static final int		MTEX_DIV			= 4;
-	public static final int		MTEX_DARK			= 5;
-	public static final int		MTEX_DIFF			= 6;
-	public static final int		MTEX_LIGHT			= 7;
-	public static final int		MTEX_SCREEN			= 8;
-	public static final int		MTEX_OVERLAY		= 9;
-	public static final int		MTEX_BLEND_HUE		= 10;
-	public static final int		MTEX_BLEND_SAT		= 11;
-	public static final int		MTEX_BLEND_VAL		= 12;
-	public static final int		MTEX_BLEND_COLOR	= 13;
-	public static final int		MTEX_NUM_BLENDTYPES	= 14;
-
 	protected NoiseGenerator noiseGenerator;
 	protected NoiseGenerator noiseGenerator;
 	private Map<Integer, TextureGenerator> textureGenerators = new HashMap<Integer, TextureGenerator>();
 	private Map<Integer, TextureGenerator> textureGenerators = new HashMap<Integer, TextureGenerator>();
 
 
@@ -229,60 +210,6 @@ public class TextureHelper extends AbstractBlenderHelper {
 		return result;
 		return result;
 	}
 	}
 
 
-	/**
-	 * This method blends the given texture with material color and the defined color in 'map to' panel. As a result of this method a new
-	 * texture is created. The input texture is NOT.
-	 * 
-	 * @param materialColor
-	 *        the material diffuse color
-	 * @param texture
-	 *        the texture we use in blending
-	 * @param color
-	 *        the color defined for the texture
-	 * @param affectFactor
-	 *        the factor that the color affects the texture (value form 0.0 to 1.0)
-	 * @param blendType
-	 *        the blending type
-	 * @param blenderContext
-	 *        the blender context
-	 * @return new texture that was created after the blending
-	 */
-	public Texture blendTexture(float[] materialColor, Texture texture, float[] color, float affectFactor, int blendType, boolean neg, BlenderContext blenderContext) {
-		float[] materialColorClone = materialColor.clone();//this array may change, so we copy it
-		Format format = texture.getImage().getFormat();
-		ByteBuffer data = texture.getImage().getData(0);
-		
-		Image decompressedImage = TextureDecompressor.decompress(texture.getImage());
-		data = decompressedImage.getData(0);
-		format = decompressedImage.getFormat();
-		
-		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()) {
-			float tin = this.setupMaterialColor(data, format, neg, materialColorClone);
-			this.blendPixel(resultPixel, materialColorClone, color, tin, 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) (materialColorClone[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 merges the given textures. The result texture has no alpha
 	 * This method merges the given textures. The result texture has no alpha
 	 * factor (is always opaque).
 	 * factor (is always opaque).
@@ -296,6 +223,9 @@ public class TextureHelper extends AbstractBlenderHelper {
 	public Texture mergeTextures(List<Texture> sources, MaterialContext materialContext) {
 	public Texture mergeTextures(List<Texture> sources, MaterialContext materialContext) {
 		Texture result = null;
 		Texture result = null;
 		if(sources!=null && sources.size()>0) {
 		if(sources!=null && sources.size()>0) {
+			if(sources.size() == 1) {
+				return sources.get(0);//just return the texture
+			}
 			//checking the sizes of the textures (tehy should perfectly match)
 			//checking the sizes of the textures (tehy should perfectly match)
 			int lastTextureWithoutAlphaIndex = 0;
 			int lastTextureWithoutAlphaIndex = 0;
 			int width = sources.get(0).getImage().getWidth();
 			int width = sources.get(0).getImage().getWidth();
@@ -360,314 +290,6 @@ public class TextureHelper extends AbstractBlenderHelper {
 		}
 		}
 		return result;
 		return result;
 	}
 	}
-	
-	/**
-	 * 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 Luminance8:
-			tin = neg ? 1.0f - firstPixelValue : firstPixelValue;
-			materialColor[3] = tin;
-			neg = false;//do not negate the materialColor, it must be unchanged
-			break;
-		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 Luminance8Alpha8:
-			tin = neg ? 1.0f - firstPixelValue : firstPixelValue;
-			neg = false;//do not negate the materialColor, it must be unchanged
-			pixelValue = data.get(); // ignore alpha
-			materialColor[3] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
-			break;
-		case DXT1:
-			
-			break;
-		case DXT1A:
-		case DXT3:
-		case DXT5:
-			break;
-		case Luminance16:
-		case Luminance16Alpha16:
-		case Alpha16:
-		case Alpha8:
-		case ARGB4444:
-		case Depth:
-		case Depth16:
-		case Depth24:
-		case Depth32:
-		case Depth32F:
-		case Intensity16:
-		case Intensity8:
-		case LATC:
-		case LTC:
-		case Luminance16F:
-		case Luminance16FAlpha16F:
-		case Luminance32F:
-		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:
-			LOGGER.log(Level.WARNING, "Image type not yet supported for blending: {0}", imageFormat);
-			break;
-		default:
-			throw new IllegalStateException("Unknown image format type: " + imageFormat);
-		}
-		if (neg) {
-			materialColor[0] = 1.0f - materialColor[0];
-			materialColor[1] = 1.0f - materialColor[1];
-			materialColor[2] = 1.0f - materialColor[2];
-		}
-		return tin;
-	}
-
-	/**
-	 * 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.rampBlend(blendtype, result, textureIntensity, color, blenderContext);
-				break;
-			default:
-				throw new IllegalStateException("Unknown blend type: " + blendtype);
-		}
-	}
-
-	/**
-	 * The method that performs the ramp blending.
-	 * 
-	 * @param type
-	 *        the blend type
-	 * @param rgb
-	 *        the rgb value where the result is stored
-	 * @param fac
-	 *        color affection factor
-	 * @param col
-	 *        the texture color
-	 * @param blenderContext
-	 *        the blender context
-	 */
-	protected void rampBlend(int type, float[] rgb, float fac, float[] col, BlenderContext blenderContext) {
-		float oneMinusFactor = 1.0f - fac;
-		MaterialHelper materialHelper = blenderContext.getHelper(MaterialHelper.class);
-
-		if (rgb.length >= 3) {
-			switch (type) {
-				case MTEX_BLEND_HUE: {
-					float[] colorTransformResult = new float[3];
-					materialHelper.rgbToHsv(col[0], col[1], col[2], colorTransformResult);
-					if (colorTransformResult[1] != 0.0f) {
-						float colH = colorTransformResult[0];
-						materialHelper.rgbToHsv(rgb[0], rgb[1], rgb[2], colorTransformResult);
-						materialHelper.hsvToRgb(colH, colorTransformResult[1], colorTransformResult[2], colorTransformResult);
-						rgb[0] = oneMinusFactor * rgb[0] + fac * colorTransformResult[0];
-						rgb[1] = oneMinusFactor * rgb[1] + fac * colorTransformResult[1];
-						rgb[2] = oneMinusFactor * rgb[2] + fac * colorTransformResult[2];
-					}
-					break;
-				}
-				case MTEX_BLEND_SAT: {
-					float[] colorTransformResult = new float[3];
-					materialHelper.rgbToHsv(rgb[0], rgb[1], rgb[2], colorTransformResult);
-					float h = colorTransformResult[0];
-					float s = colorTransformResult[1];
-					float v = colorTransformResult[2];
-					if (s != 0.0f) {
-						materialHelper.rgbToHsv(col[0], col[1], col[2], colorTransformResult);
-						materialHelper.hsvToRgb(h, (oneMinusFactor * s + fac * colorTransformResult[1]), v, rgb);
-					}
-					break;
-				}
-				case MTEX_BLEND_VAL: {
-					float[] rgbToHsv = new float[3];
-					float[] colToHsv = new float[3];
-					materialHelper.rgbToHsv(rgb[0], rgb[1], rgb[2], rgbToHsv);
-					materialHelper.rgbToHsv(col[0], col[1], col[2], colToHsv);
-					materialHelper.hsvToRgb(rgbToHsv[0], rgbToHsv[1], (oneMinusFactor * rgbToHsv[2] + fac * colToHsv[2]), rgb);
-					break;
-				}
-				case MTEX_BLEND_COLOR: {
-					float[] rgbToHsv = new float[3];
-					float[] colToHsv = new float[3];
-					materialHelper.rgbToHsv(col[0], col[1], col[2], colToHsv);
-					if (colToHsv[2] != 0) {
-						materialHelper.rgbToHsv(rgb[0], rgb[1], rgb[2], rgbToHsv);
-						materialHelper.hsvToRgb(colToHsv[0], colToHsv[1], rgbToHsv[2], rgbToHsv);
-						rgb[0] = oneMinusFactor * rgb[0] + fac * rgbToHsv[0];
-						rgb[1] = oneMinusFactor * rgb[1] + fac * rgbToHsv[1];
-						rgb[2] = oneMinusFactor * rgb[2] + fac * rgbToHsv[2];
-					}
-					break;
-				}
-				default:
-					throw new IllegalStateException("Unknown ramp type: " + type);
-			}
-		}
-	}
 
 
 	/**
 	/**
 	 * This method converts the given texture into normal-map texture.
 	 * This method converts the given texture into normal-map texture.

+ 42 - 1
engine/src/blender/com/jme3/scene/plugins/blender/textures/TexturePixel.java

@@ -12,7 +12,7 @@ import java.util.logging.Logger;
  * 
  * 
  * @author Marcin Roguski (Kaelthas)
  * @author Marcin Roguski (Kaelthas)
  */
  */
-/* package */class TexturePixel implements Cloneable {
+public class TexturePixel implements Cloneable {
 	private static final Logger	LOGGER	= Logger.getLogger(TexturePixel.class.getName());
 	private static final Logger	LOGGER	= Logger.getLogger(TexturePixel.class.getName());
 
 
 	/** The pixel data. */
 	/** The pixel data. */
@@ -147,6 +147,19 @@ import java.util.logging.Logger;
 		}
 		}
 	}
 	}
 
 
+	/**
+	 * Stores RGBA values in the given array.
+	 * 
+	 * @param result
+	 *            the array to store values
+	 */
+	public void toRGBA(float[] result) {
+		result[0] = this.red;
+		result[1] = this.green;
+		result[2] = this.blue;
+		result[3] = this.alpha;
+	}
+
 	/**
 	/**
 	 * Stores the data in the given table.
 	 * Stores the data in the given table.
 	 * 
 	 * 
@@ -160,6 +173,24 @@ import java.util.logging.Logger;
 		result[3] = (byte) (this.alpha * 255.0f);
 		result[3] = (byte) (this.alpha * 255.0f);
 	}
 	}
 
 
+	/**
+	 * Stores the pixel values in the integer.
+	 * 
+	 * @return the integer that stores the pixel values
+	 */
+	public int toARGB8() {
+		int result = 0;
+		int b = (int) (this.alpha * 255.0f);
+		result |= b << 24;
+		b = (int) (this.red * 255.0f);
+		result |= b << 16;
+		b = (int) (this.green * 255.0f);
+		result |= b << 8;
+		b = (int) (this.blue * 255.0f);
+		result |= b;
+		return result;
+	}
+
 	/**
 	/**
 	 * Merges two pixels (adds the values of each color).
 	 * Merges two pixels (adds the values of each color).
 	 * 
 	 * 
@@ -174,6 +205,16 @@ import java.util.logging.Logger;
 		// alpha should be always 1.0f as a result
 		// alpha should be always 1.0f as a result
 	}
 	}
 
 
+	/**
+	 * This method negates the colors.
+	 */
+	public void negate() {
+		this.red = 1.0f - this.red;
+		this.green = 1.0f - this.green;
+		this.blue = 1.0f - this.blue;
+		this.alpha = 1.0f - this.alpha;
+	}
+
 	/**
 	/**
 	 * This method clears the pixel values.
 	 * This method clears the pixel values.
 	 */
 	 */

+ 195 - 0
engine/src/blender/com/jme3/scene/plugins/blender/textures/blending/AbstractTextureBlender.java

@@ -0,0 +1,195 @@
+package com.jme3.scene.plugins.blender.textures.blending;
+
+import com.jme3.math.FastMath;
+import com.jme3.scene.plugins.blender.BlenderContext;
+import com.jme3.scene.plugins.blender.materials.MaterialHelper;
+
+/**
+ * An abstract class that contains the basic methods used by the classes that
+ * will derive from it.
+ * 
+ * @author Marcin Roguski (Kaelthas)
+ */
+/* package */abstract class AbstractTextureBlender implements TextureBlender {
+	/**
+	 * This method blends the single pixel depending on the blending type.
+	 * 
+	 * @param result
+	 *            the result pixel
+	 * @param materialColor
+	 *            the material color
+	 * @param pixelColor
+	 *            the pixel color
+	 * @param blendFactor
+	 *            the blending factor
+	 * @param blendtype
+	 *            the blending type
+	 * @param blenderContext
+	 *            the blender context
+	 */
+	protected void blendPixel(float[] result, float[] materialColor, float[] pixelColor, float blendFactor, int blendtype, BlenderContext blenderContext) {
+		float oneMinusFactor = 1.0f - blendFactor, col;
+
+		switch (blendtype) {
+			case MTEX_BLEND:
+				result[0] = blendFactor * pixelColor[0] + oneMinusFactor * materialColor[0];
+				result[1] = blendFactor * pixelColor[1] + oneMinusFactor * materialColor[1];
+				result[2] = blendFactor * pixelColor[2] + oneMinusFactor * materialColor[2];
+				break;
+			case MTEX_MUL:
+				result[0] = (oneMinusFactor + blendFactor * materialColor[0]) * pixelColor[0];
+				result[1] = (oneMinusFactor + blendFactor * materialColor[1]) * pixelColor[1];
+				result[2] = (oneMinusFactor + blendFactor * materialColor[2]) * pixelColor[2];
+				break;
+			case MTEX_DIV:
+				if (pixelColor[0] != 0.0) {
+					result[0] = (oneMinusFactor * materialColor[0] + blendFactor * materialColor[0] / pixelColor[0]) * 0.5f;
+				}
+				if (pixelColor[1] != 0.0) {
+					result[1] = (oneMinusFactor * materialColor[1] + blendFactor * materialColor[1] / pixelColor[1]) * 0.5f;
+				}
+				if (pixelColor[2] != 0.0) {
+					result[2] = (oneMinusFactor * materialColor[2] + blendFactor * materialColor[2] / pixelColor[2]) * 0.5f;
+				}
+				break;
+			case MTEX_SCREEN:
+				result[0] = 1.0f - (oneMinusFactor + blendFactor * (1.0f - materialColor[0])) * (1.0f - pixelColor[0]);
+				result[1] = 1.0f - (oneMinusFactor + blendFactor * (1.0f - materialColor[1])) * (1.0f - pixelColor[1]);
+				result[2] = 1.0f - (oneMinusFactor + blendFactor * (1.0f - materialColor[2])) * (1.0f - pixelColor[2]);
+				break;
+			case MTEX_OVERLAY:
+				if (materialColor[0] < 0.5f) {
+					result[0] = pixelColor[0] * (oneMinusFactor + 2.0f * blendFactor * materialColor[0]);
+				} else {
+					result[0] = 1.0f - (oneMinusFactor + 2.0f * blendFactor * (1.0f - materialColor[0])) * (1.0f - pixelColor[0]);
+				}
+				if (materialColor[1] < 0.5f) {
+					result[1] = pixelColor[1] * (oneMinusFactor + 2.0f * blendFactor * materialColor[1]);
+				} else {
+					result[1] = 1.0f - (oneMinusFactor + 2.0f * blendFactor * (1.0f - materialColor[1])) * (1.0f - pixelColor[1]);
+				}
+				if (materialColor[2] < 0.5f) {
+					result[2] = pixelColor[2] * (oneMinusFactor + 2.0f * blendFactor * materialColor[2]);
+				} else {
+					result[2] = 1.0f - (oneMinusFactor + 2.0f * blendFactor * (1.0f - materialColor[2])) * (1.0f - pixelColor[2]);
+				}
+				break;
+			case MTEX_SUB:
+				result[0] = materialColor[0] - blendFactor * pixelColor[0];
+				result[1] = materialColor[1] - blendFactor * pixelColor[1];
+				result[2] = materialColor[2] - blendFactor * pixelColor[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] = (blendFactor * pixelColor[0] + materialColor[0]) * 0.5f;
+				result[1] = (blendFactor * pixelColor[1] + materialColor[1]) * 0.5f;
+				result[2] = (blendFactor * pixelColor[2] + materialColor[2]) * 0.5f;
+				break;
+			case MTEX_DIFF:
+				result[0] = oneMinusFactor * materialColor[0] + blendFactor * Math.abs(materialColor[0] - pixelColor[0]);
+				result[1] = oneMinusFactor * materialColor[1] + blendFactor * Math.abs(materialColor[1] - pixelColor[1]);
+				result[2] = oneMinusFactor * materialColor[2] + blendFactor * Math.abs(materialColor[2] - pixelColor[2]);
+				break;
+			case MTEX_DARK:
+				col = blendFactor * pixelColor[0];
+				result[0] = col < materialColor[0] ? col : materialColor[0];
+				col = blendFactor * pixelColor[1];
+				result[1] = col < materialColor[1] ? col : materialColor[1];
+				col = blendFactor * pixelColor[2];
+				result[2] = col < materialColor[2] ? col : materialColor[2];
+				break;
+			case MTEX_LIGHT:
+				col = blendFactor * pixelColor[0];
+				result[0] = col > materialColor[0] ? col : materialColor[0];
+				col = blendFactor * pixelColor[1];
+				result[1] = col > materialColor[1] ? col : materialColor[1];
+				col = blendFactor * pixelColor[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, blendFactor, pixelColor, blenderContext);
+				break;
+			default:
+				throw new IllegalStateException("Unknown blend type: " + blendtype);
+		}
+	}
+
+	/**
+	 * The method that performs the ramp blending.
+	 * 
+	 * @param type
+	 *            the blend type
+	 * @param materialRGB
+	 *            the rgb value of the material, here the result is stored too
+	 * @param fac
+	 *            color affection factor
+	 * @param pixelColor
+	 *            the texture color
+	 * @param blenderContext
+	 *            the blender context
+	 */
+	protected void blendHSV(int type, float[] materialRGB, float fac, float[] pixelColor, BlenderContext blenderContext) {
+		float oneMinusFactor = 1.0f - fac;
+		MaterialHelper materialHelper = blenderContext.getHelper(MaterialHelper.class);
+
+		switch (type) {
+			case MTEX_BLEND_HUE: {// FIXME: not working well for image textures
+									// (works fine for generated textures)
+				float[] colorTransformResult = new float[3];
+				materialHelper.rgbToHsv(pixelColor[0], pixelColor[1], pixelColor[2], colorTransformResult);
+				if (colorTransformResult[0] != 0.0f) {
+					float colH = colorTransformResult[0];
+					materialHelper.rgbToHsv(materialRGB[0], materialRGB[1], materialRGB[2], colorTransformResult);
+					materialHelper.hsvToRgb(colH, colorTransformResult[1], colorTransformResult[2], colorTransformResult);
+					materialRGB[0] = oneMinusFactor * materialRGB[0] + fac * colorTransformResult[0];
+					materialRGB[1] = oneMinusFactor * materialRGB[1] + fac * colorTransformResult[1];
+					materialRGB[2] = oneMinusFactor * materialRGB[2] + fac * colorTransformResult[2];
+				}
+				break;
+			}
+			case MTEX_BLEND_SAT: {
+				float[] colorTransformResult = new float[3];
+				materialHelper.rgbToHsv(materialRGB[0], materialRGB[1], materialRGB[2], colorTransformResult);
+				float h = colorTransformResult[0];
+				float s = colorTransformResult[1];
+				float v = colorTransformResult[2];
+				if (s != 0.0f) {
+					materialHelper.rgbToHsv(pixelColor[0], pixelColor[1], pixelColor[2], colorTransformResult);
+					materialHelper.hsvToRgb(h, (oneMinusFactor * s + fac * colorTransformResult[1]), v, materialRGB);
+				}
+				break;
+			}
+			case MTEX_BLEND_VAL: {
+				float[] rgbToHsv = new float[3];
+				float[] colToHsv = new float[3];
+				materialHelper.rgbToHsv(materialRGB[0], materialRGB[1], materialRGB[2], rgbToHsv);
+				materialHelper.rgbToHsv(pixelColor[0], pixelColor[1], pixelColor[2], colToHsv);
+				materialHelper.hsvToRgb(rgbToHsv[0], rgbToHsv[1], (oneMinusFactor * rgbToHsv[2] + fac * colToHsv[2]), materialRGB);
+				break;
+			}
+			case MTEX_BLEND_COLOR: {// FIXME: not working well for image
+									// textures (works fine for generated
+									// textures)
+				float[] rgbToHsv = new float[3];
+				float[] colToHsv = new float[3];
+				materialHelper.rgbToHsv(pixelColor[0], pixelColor[1], pixelColor[2], colToHsv);
+				if (colToHsv[2] != 0) {
+					materialHelper.rgbToHsv(materialRGB[0], materialRGB[1], materialRGB[2], rgbToHsv);
+					materialHelper.hsvToRgb(colToHsv[0], colToHsv[1], rgbToHsv[2], rgbToHsv);
+					materialRGB[0] = oneMinusFactor * materialRGB[0] + fac * rgbToHsv[0];
+					materialRGB[1] = oneMinusFactor * materialRGB[1] + fac * rgbToHsv[1];
+					materialRGB[2] = oneMinusFactor * materialRGB[2] + fac * rgbToHsv[2];
+				}
+				break;
+			}
+			default:
+				throw new IllegalStateException("Unknown ramp type: " + type);
+		}
+	}
+}

+ 51 - 0
engine/src/blender/com/jme3/scene/plugins/blender/textures/blending/TextureBlender.java

@@ -0,0 +1,51 @@
+package com.jme3.scene.plugins.blender.textures.blending;
+
+import com.jme3.scene.plugins.blender.BlenderContext;
+import com.jme3.texture.Texture;
+
+/**
+ * An interface for texture blending classes (the classes that mix the texture
+ * pixels with the material colors).
+ * 
+ * @author Marcin Roguski (Kaelthas)
+ */
+public interface TextureBlender {
+	// types of blending
+	int	MTEX_BLEND			= 0;
+	int	MTEX_MUL			= 1;
+	int	MTEX_ADD			= 2;
+	int	MTEX_SUB			= 3;
+	int	MTEX_DIV			= 4;
+	int	MTEX_DARK			= 5;
+	int	MTEX_DIFF			= 6;
+	int	MTEX_LIGHT			= 7;
+	int	MTEX_SCREEN			= 8;
+	int	MTEX_OVERLAY		= 9;
+	int	MTEX_BLEND_HUE		= 10;
+	int	MTEX_BLEND_SAT		= 11;
+	int	MTEX_BLEND_VAL		= 12;
+	int	MTEX_BLEND_COLOR	= 13;
+	int	MTEX_NUM_BLENDTYPES	= 14;
+
+	/**
+	 * This method blends the given texture with material color and the defined
+	 * color in 'map to' panel. As a result of this method a new texture is
+	 * created. The input texture is NOT.
+	 * 
+	 * @param materialColor
+	 *            the material diffuse color
+	 * @param texture
+	 *            the texture we use in blending
+	 * @param color
+	 *            the color defined for the texture
+	 * @param affectFactor
+	 *            the factor that the color affects the texture (value form 0.0
+	 *            to 1.0)
+	 * @param blendType
+	 *            the blending type
+	 * @param blenderContext
+	 *            the blender context
+	 * @return new texture that was created after the blending
+	 */
+	Texture blend(float[] materialColor, Texture texture, float[] color, float affectFactor, int blendType, boolean neg, BlenderContext blenderContext);
+}

+ 162 - 0
engine/src/blender/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderAWT.java

@@ -0,0 +1,162 @@
+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()) {
+			float tin = this.setupMaterialColor(data, format, neg, pixelColor);
+			this.blendPixel(resultPixel, materialColor, color, tin, 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;
+	}
+}

+ 96 - 0
engine/src/blender/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderDDS.java

@@ -0,0 +1,96 @@
+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 jme3tools.converters.RGB565;
+
+import com.jme3.scene.plugins.blender.BlenderContext;
+import com.jme3.scene.plugins.blender.textures.TexturePixel;
+import com.jme3.texture.Image;
+import com.jme3.texture.Image.Format;
+import com.jme3.texture.Texture;
+import com.jme3.texture.Texture2D;
+import com.jme3.texture.Texture3D;
+import com.jme3.util.BufferUtils;
+
+/**
+ * The class that is responsible for blending the following texture types:
+ * <li> DXT1
+ * <li> DXT3
+ * <li> DXT5
+ * Not yet supported (but will be):
+ * <li> DXT1A:
+ * @author Marcin Roguski (Kaelthas)
+ */
+public class TextureBlenderDDS extends AbstractTextureBlender {
+	private static final Logger	LOGGER	= Logger.getLogger(TextureBlenderDDS.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(data.remaining());
+
+		float[] resultPixel = new float[4];
+		float[] pixelColor = new float[4];
+		TexturePixel[] colors = new TexturePixel[] { new TexturePixel(), new TexturePixel() };
+		int dataIndex = 0;
+		while (data.hasRemaining()) {
+			switch (format) {
+				case DXT3:
+				case DXT5:
+					newData.putLong(dataIndex, data.getLong());// just copy the
+																// 8 bytes of
+																// alphas
+					dataIndex += 8;
+				case DXT1:
+					int col0 = RGB565.RGB565_to_ARGB8(data.getShort());
+					int col1 = RGB565.RGB565_to_ARGB8(data.getShort());
+					colors[0].fromARGB8(col0);
+					colors[1].fromARGB8(col1);
+					break;
+				case DXT1A:
+					LOGGER.log(Level.WARNING, "Image type not yet supported for blending: {0}", format);
+					break;
+				default:
+					throw new IllegalStateException("Invalid image format type for DDS texture blender: " + format);
+			}
+
+			// blending colors
+			for (int i = 0; i < colors.length; ++i) {
+				if (neg) {
+					colors[i].negate();
+				}
+				colors[i].toRGBA(pixelColor);
+				this.blendPixel(resultPixel, materialColor, pixelColor, affectFactor, blendType, blenderContext);
+				colors[i].fromARGB8(1, resultPixel[0], resultPixel[1], resultPixel[2]);
+				int argb8 = colors[i].toARGB8();
+				short rgb565 = RGB565.ARGB8_to_RGB565(argb8);
+				newData.putShort(dataIndex, rgb565);
+				dataIndex += 2;
+			}
+
+			// just copy the remaining 4 bytes of the current texel
+			newData.putInt(dataIndex, data.getInt());
+			dataIndex += 4;
+		}
+		if (texture.getType() == Texture.Type.TwoDimensional) {
+			return new Texture2D(new Image(format, width, height, newData));
+		} else {
+			ArrayList<ByteBuffer> dataArray = new ArrayList<ByteBuffer>(1);
+			dataArray.add(newData);
+			return new Texture3D(new Image(format, width, height, depth, dataArray));
+		}
+	}
+}

+ 81 - 0
engine/src/blender/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderFactory.java

@@ -0,0 +1,81 @@
+package com.jme3.scene.plugins.blender.textures.blending;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.jme3.scene.plugins.blender.BlenderContext;
+import com.jme3.texture.Texture;
+import com.jme3.texture.Image.Format;
+
+/**
+ * This class creates the texture blending class depending on the texture type.
+ * 
+ * @author Marcin Roguski (Kaelthas)
+ */
+public class TextureBlenderFactory {
+	private static final Logger	LOGGER	= Logger.getLogger(TextureBlenderFactory.class.getName());
+
+	/**
+	 * This method creates the blending class.
+	 * 
+	 * @param format
+	 *            the texture format
+	 * @returntexture blending class
+	 */
+	public static TextureBlender createTextureBlender(Format format) {
+		switch (format) {
+			case Luminance8:
+			case Luminance8Alpha8:
+			case Luminance16:
+			case Luminance16Alpha16:
+			case Luminance16F:
+			case Luminance16FAlpha16F:
+			case Luminance32F:
+				return new TextureBlenderLuminance();
+			case RGBA8:
+			case ABGR8:
+			case BGR8:
+			case RGB8:
+			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:
+				return new TextureBlenderAWT();
+			case DXT1:
+			case DXT1A:
+			case DXT3:
+			case DXT5:
+				return new TextureBlenderDDS();
+			case Alpha16:
+			case Alpha8:
+			case ARGB4444:
+			case Depth:
+			case Depth16:
+			case Depth24:
+			case Depth32:
+			case Depth32F:
+			case Intensity16:
+			case Intensity8:
+			case LATC:
+			case LTC:
+				LOGGER.log(Level.WARNING, "Image type not yet supported for blending: {0}. Returning a blender that does not change the texture.", format);
+				return new TextureBlender() {
+					@Override
+					public Texture blend(float[] materialColor, Texture texture, float[] color, float affectFactor, int blendType, boolean neg, BlenderContext blenderContext) {
+						return texture;
+					}
+				};
+			default:
+				throw new IllegalStateException("Unknown image format type: " + format);
+		}
+	}
+}

+ 221 - 0
engine/src/blender/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderLuminance.java

@@ -0,0 +1,221 @@
+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:
+ * <li> Luminance8
+ * <li> Luminance8Alpha8
+ * Not yet supported (but will be):
+ * <li> Luminance16:
+ * <li> Luminance16Alpha16:
+ * <li> Luminance16F:
+ * <li> Luminance16FAlpha16F:
+ * <li> 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<ByteBuffer> dataArray = new ArrayList<ByteBuffer>(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);
+		}
+	}
+}