Browse Source

Support for generated textures merging.
Optimizations in textures loading when multiple textures are applied.
Fixes in pixel blending.

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

Kae..pl 14 years ago
parent
commit
846b569552
16 changed files with 586 additions and 295 deletions
  1. 3 4
      engine/src/blender/com/jme3/scene/plugins/blender/cameras/CameraHelper.java
  2. 291 2
      engine/src/blender/com/jme3/scene/plugins/blender/materials/MaterialContext.java
  3. 39 219
      engine/src/blender/com/jme3/scene/plugins/blender/materials/MaterialHelper.java
  4. 2 16
      engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureGenerator.java
  5. 4 3
      engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureGeneratorBlend.java
  6. 5 3
      engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureGeneratorClouds.java
  7. 6 3
      engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureGeneratorDistnoise.java
  8. 8 4
      engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureGeneratorMagic.java
  9. 4 3
      engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureGeneratorMarble.java
  10. 4 3
      engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureGeneratorMusgrave.java
  11. 5 4
      engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureGeneratorNoise.java
  12. 5 3
      engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureGeneratorStucci.java
  13. 6 3
      engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureGeneratorVoronoi.java
  14. 4 3
      engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureGeneratorWood.java
  15. 105 22
      engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureHelper.java
  16. 95 0
      engine/src/blender/com/jme3/scene/plugins/blender/textures/TexturePixel.java

+ 3 - 4
engine/src/blender/com/jme3/scene/plugins/blender/cameras/CameraHelper.java

@@ -17,8 +17,8 @@ import com.jme3.scene.plugins.blender.file.Structure;
 public class CameraHelper extends AbstractBlenderHelper {
 
     private static final Logger LOGGER = Logger.getLogger(CameraHelper.class.getName());
-    protected static final int DEFAULT_CAM_WIDTH = 100;
-    protected static final int DEFAULT_CAM_HEIGHT = 100;
+    protected static final int DEFAULT_CAM_WIDTH = 640;
+    protected static final int DEFAULT_CAM_HEIGHT = 480;
     
     /**
      * This constructor parses the given blender version and stores the result. Some functionalities may differ in
@@ -98,7 +98,6 @@ public class CameraHelper extends AbstractBlenderHelper {
         }
         //type==0 - perspective; type==1 - orthographic; perspective is used as default
         result.setParallelProjection(type == 1);
-        float angle = ((Number) structure.getFieldValue("angle")).floatValue();
         float aspect = 0;
         float clipsta = ((Number) structure.getFieldValue("clipsta")).floatValue();
         float clipend = ((Number) structure.getFieldValue("clipend")).floatValue();
@@ -107,7 +106,7 @@ public class CameraHelper extends AbstractBlenderHelper {
         } else {
             aspect = ((Number) structure.getFieldValue("ortho_scale")).floatValue();
         }
-        result.setFrustumPerspective(angle, aspect, clipsta, clipend);
+        result.setFrustumPerspective(aspect, result.getWidth() / result.getHeight(), clipsta, clipend);
         return result;
     }
 

+ 291 - 2
engine/src/blender/com/jme3/scene/plugins/blender/materials/MaterialContext.java

@@ -1,31 +1,58 @@
 package com.jme3.scene.plugins.blender.materials;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import com.jme3.math.ColorRGBA;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.file.DynamicArray;
 import com.jme3.scene.plugins.blender.file.Pointer;
 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.SpecularShader;
 import com.jme3.scene.plugins.blender.textures.TextureHelper;
+import com.jme3.texture.Texture;
 import com.jme3.texture.Texture.Type;
+import com.jme3.texture.Texture.WrapMode;
 
+/**
+ * This class holds the data about the material.
+ * @author Marcin Roguski (Kaelthas)
+ */
 public final class MaterialContext {
 	private static final Logger			LOGGER				= Logger.getLogger(MaterialContext.class.getName());
 
+	//texture mapping types
+	public static final int				MTEX_COL = 0x01;
+	public static final int				MTEX_NOR = 0x02;
+	public static final int				MTEX_SPEC = 0x04;
+	public static final int				MTEX_EMIT = 0x40;
+	public static final int				MTEX_ALPHA = 0x80;
+	
 	/* package */final String			name;
 	/* package */final List<Structure>	mTexs;
 	/* package */final List<Structure>	textures;
+	/* package */final Map<Number, Texture> loadedTextures;
+	/* package */final Map<Texture, Structure> textureToMTexMap;
 	/* package */final int				texturesCount;
 	/* package */final Type				textureType;
 
+	/* package */final ColorRGBA		diffuseColor;
+	/* package */final DiffuseShader 	diffuseShader;
+	/* package */final SpecularShader 	specularShader;
+	/* package */final ColorRGBA		specularColor;
+	/* package */final ColorRGBA		ambientColor;
+	/* package */final float 			shininess;
 	/* package */final boolean			shadeless;
 	/* package */final boolean			vertexColor;
 	/* package */final boolean			transparent;
-	/* package */final boolean			vtangent;
+	/* package */final boolean			vTangent;
 
 	/* package */int					uvCoordinatesType	= -1;
 	/* package */int					projectionType;
@@ -38,10 +65,37 @@ public final class MaterialContext {
 		shadeless = (mode & 0x4) != 0;
 		vertexColor = (mode & 0x80) != 0;
 		transparent = (mode & 0x10000) != 0;
-		vtangent = (mode & 0x4000000) != 0; // NOTE: Requires tangents
+		vTangent = (mode & 0x4000000) != 0; // NOTE: Requires tangents
 
+		int diff_shader = ((Number) structure.getFieldValue("diff_shader")).intValue();
+		diffuseShader = DiffuseShader.values()[diff_shader];
+		
+		if(this.shadeless) {
+			diffuseColor = ColorRGBA.White.clone();
+			specularShader = null;
+			specularColor = ambientColor = null;
+			shininess = 0.0f;
+		} else {
+			diffuseColor = this.readDiffuseColor(structure, diffuseShader);
+			
+			int spec_shader = ((Number) structure.getFieldValue("spec_shader")).intValue();
+			specularShader = SpecularShader.values()[spec_shader];
+			specularColor = this.readSpecularColor(structure, specularShader);
+			
+			float r = ((Number) structure.getFieldValue("ambr")).floatValue();
+			float g = ((Number) structure.getFieldValue("ambg")).floatValue();
+			float b = ((Number) structure.getFieldValue("ambb")).floatValue();
+			float alpha = ((Number) structure.getFieldValue("alpha")).floatValue();
+			ambientColor = new ColorRGBA(r, g, b, alpha);
+			
+			float shininess = ((Number) structure.getFieldValue("emit")).floatValue();
+			this.shininess = shininess > 0.0f ? shininess : MaterialHelper.DEFAULT_SHININESS;
+		}
+		float[] diffuseColorArray = new float[] {diffuseColor.r, diffuseColor.g, diffuseColor.b, diffuseColor.a};//TODO: czy trzeba wstawiac te dane?
+		
 		mTexs = new ArrayList<Structure>();
 		textures = new ArrayList<Structure>();
+		
 		DynamicArray<Pointer> mtexsArray = (DynamicArray<Pointer>) structure.getFieldValue("mtex");
 		int separatedTextures = ((Number) structure.getFieldValue("septex")).intValue();
 		Type firstTextureType = null;
@@ -79,10 +133,89 @@ public final class MaterialContext {
 				}
 			}
 		}
+		
+		//loading the textures and merging them
+		Map<Number, List<Structure[]>> sortedTextures = this.sortAndFilterTextures();
+		loadedTextures = new HashMap<Number, Texture>(sortedTextures.size());
+		textureToMTexMap = new HashMap<Texture, Structure>();
+		TextureHelper textureHelper = blenderContext.getHelper(TextureHelper.class);
+		for(Entry<Number, List<Structure[]>> entry : sortedTextures.entrySet()) {
+			if(entry.getValue().size()>0) {
+				List<Texture> textures = new ArrayList<Texture>(entry.getValue().size());
+				for(Structure[] mtexAndTex : entry.getValue()) {
+					int texflag = ((Number) mtexAndTex[0].getFieldValue("texflag")).intValue();
+					boolean negateTexture = (texflag & 0x04) != 0;
+					Texture texture = textureHelper.getTexture(mtexAndTex[1], blenderContext);
+					int blendType = ((Number) mtexAndTex[0].getFieldValue("blendtype")).intValue();
+					float[] color = new float[] { ((Number) mtexAndTex[0].getFieldValue("r")).floatValue(), 
+												  ((Number) mtexAndTex[0].getFieldValue("g")).floatValue(), 
+												  ((Number) mtexAndTex[0].getFieldValue("b")).floatValue() };
+					float colfac = ((Number) mtexAndTex[0].getFieldValue("colfac")).floatValue();
+					texture = textureHelper.blendTexture(diffuseColorArray, texture, color, colfac, blendType, negateTexture, blenderContext);
+					texture.setWrap(WrapMode.Repeat);
+					textures.add(texture);
+					textureToMTexMap.put(texture, mtexAndTex[0]);
+				}
+				loadedTextures.put(entry.getKey(), textureHelper.mergeTextures(textures, this));
+			}
+		}
 
 		this.texturesCount = mTexs.size();
 		this.textureType = firstTextureType;
 	}
+	
+	/**
+	 * This method sorts the textures by their mapping type.
+	 * In each group only textures of one type are put (either two- or three-dimensional).
+	 * If the mapping type is MTEX_COL then if the texture has no alpha channel then all textures before it are
+	 * discarded and will not be loaded and merged because texture with no alpha will cover them anyway.
+	 * @return a map with sorted and filtered textures
+	 */
+	private Map<Number, List<Structure[]>> sortAndFilterTextures() {
+		Map<Number, List<Structure[]>> result = new HashMap<Number, List<Structure[]>>();
+		for (int i = 0; i < mTexs.size(); ++i) {
+			Structure mTex = mTexs.get(i);
+			Structure texture  = textures.get(i);
+			Number mapto = (Number) mTex.getFieldValue("mapto");
+			List<Structure[]> mtexs = result.get(mapto);
+			if(mtexs==null) {
+				mtexs = new ArrayList<Structure[]>();
+				result.put(mapto, mtexs);
+			}
+			if(mapto.intValue() == MTEX_COL && this.isWithoutAlpha(textures.get(i))) {
+				mtexs.clear();//remove previous textures, they will be covered anyway
+			}
+			mtexs.add(new Structure[] {mTex, texture});
+		}
+		return result;
+	}
+	
+	/**
+	 * This method determines if the given texture has no alpha channel.
+	 * 
+	 * @param texture
+	 *            the texture to check for alpha channel
+	 * @return <b>true</b> if the texture has no alpha channel and <b>false</b>
+	 *         otherwise
+	 */
+	private boolean isWithoutAlpha(Structure texture) {
+		int flag = ((Number) texture.getFieldValue("flag")).intValue();
+		if((flag & 0x01) == 0) {//the texture has no colorband
+			int type = ((Number) texture.getFieldValue("type")).intValue();
+			if(type==TextureHelper.TEX_MAGIC) {
+				return true;
+			}
+			if(type==TextureHelper.TEX_VORONOI) {
+				int voronoiColorType = ((Number) texture.getFieldValue("vn_coltype")).intValue();
+				return voronoiColorType != 0;//voronoiColorType == 0: intensity, voronoiColorType != 0: col1, col2 or col3
+			}
+			if(type==TextureHelper.TEX_CLOUDS) {
+				int sType = ((Number) texture.getFieldValue("stype")).intValue();
+				return sType == 1;//sType==0: without colors, sType==1: with colors
+			}
+		}
+		return false;
+	}
 
 	/**
 	 * This method returns the current material's texture UV coordinates type.
@@ -133,6 +266,74 @@ public final class MaterialContext {
 		Structure mtex = mTexs.get(textureIndex);
 		return new int[] { ((Number) mtex.getFieldValue("projx")).intValue(), ((Number) mtex.getFieldValue("projy")).intValue(), ((Number) mtex.getFieldValue("projz")).intValue() };
 	}
+	
+	/**
+	 * This method returns the diffuse color.
+	 * 
+	 * @param materialStructure the material structure
+	 * @param diffuseShader the diffuse shader
+	 * @return the diffuse color
+	 */
+	private ColorRGBA readDiffuseColor(Structure materialStructure, DiffuseShader diffuseShader) {
+		// bitwise 'or' of all textures mappings
+		int commonMapto = ((Number) materialStructure.getFieldValue("mapto")).intValue();
+
+		// diffuse color
+		float r = ((Number) materialStructure.getFieldValue("r")).floatValue();
+		float g = ((Number) materialStructure.getFieldValue("g")).floatValue();
+		float b = ((Number) materialStructure.getFieldValue("b")).floatValue();
+		float alpha = ((Number) materialStructure.getFieldValue("alpha")).floatValue();
+		if ((commonMapto & 0x01) == 0x01) {// Col
+			return new ColorRGBA(r, g, b, alpha);
+		} else {
+			switch (diffuseShader) {
+				case FRESNEL:
+				case ORENNAYAR:
+				case TOON:
+					break;// TODO: find what is the proper modification
+				case MINNAERT:
+				case LAMBERT:// TODO: check if that is correct
+					float ref = ((Number) materialStructure.getFieldValue("ref")).floatValue();
+					r *= ref;
+					g *= ref;
+					b *= ref;
+					break;
+				default:
+					throw new IllegalStateException("Unknown diffuse shader type: " + diffuseShader.toString());
+			}
+			return new ColorRGBA(r, g, b, alpha);
+		}
+	}
+
+	/**
+	 * This method returns a specular color used by the material.
+	 * 
+	 * @param materialStructure
+	 *        the material structure filled with data
+	 * @return a specular color used by the material
+	 */
+	private ColorRGBA readSpecularColor(Structure materialStructure, SpecularShader specularShader) {
+		float r = ((Number) materialStructure.getFieldValue("specr")).floatValue();
+		float g = ((Number) materialStructure.getFieldValue("specg")).floatValue();
+		float b = ((Number) materialStructure.getFieldValue("specb")).floatValue();
+		float alpha = ((Number) materialStructure.getFieldValue("alpha")).floatValue();
+		switch (specularShader) {
+			case BLINN:
+			case COOKTORRENCE:
+			case TOON:
+			case WARDISO:// TODO: find what is the proper modification
+				break;
+			case PHONG:// TODO: check if that is correct
+				float spec = ((Number) materialStructure.getFieldValue("spec")).floatValue();
+				r *= spec * 0.5f;
+				g *= spec * 0.5f;
+				b *= spec * 0.5f;
+				break;
+			default:
+				throw new IllegalStateException("Unknown specular shader type: " + specularShader.toString());
+		}
+		return new ColorRGBA(r, g, b, alpha);
+	}
 
 	/**
 	 * This method determines the type of the texture.
@@ -167,4 +368,92 @@ public final class MaterialContext {
 				throw new IllegalStateException("Unknown texture type: " + texType);
 		}
 	}
+	
+	/**
+	 * @return he material's name
+	 */
+	public String getName() {
+		return name;
+	}
+	
+	/**
+	 * @return a copy of diffuse color
+	 */
+	public ColorRGBA getDiffuseColor() {
+		return diffuseColor.clone();
+	}
+	
+	/**
+	 * @return an enum describing the type of a diffuse shader used by this material
+	 */
+	public DiffuseShader getDiffuseShader() {
+		return diffuseShader;
+	}
+	
+	/**
+	 * @return a copy of specular color
+	 */
+	public ColorRGBA getSpecularColor() {
+		return specularColor.clone();
+	}
+	
+	/**
+	 * @return an enum describing the type of a specular shader used by this material
+	 */
+	public SpecularShader getSpecularShader() {
+		return specularShader;
+	}
+	
+	/**
+	 * @return an ambient color used by the material
+	 */
+	public ColorRGBA getAmbientColor() {
+		return ambientColor;
+	}
+	
+	/**
+	 * @return the sihiness of this material
+	 */
+	public float getShininess() {
+		return shininess;
+	}
+	
+	/**
+	 * @return <b>true</b> if the material is shadeless and <b>false</b> otherwise
+	 */
+	public boolean isShadeless() {
+		return shadeless;
+	}
+	
+	/**
+	 * @return <b>true</b> if the material uses vertex color and <b>false</b> otherwise
+	 */
+	public boolean isVertexColor() {
+		return vertexColor;
+	}
+	
+	/**
+	 * @return <b>true</b> if the material is transparent and <b>false</b> otherwise
+	 */
+	public boolean isTransparent() {
+		return transparent;
+	}
+	
+	/**
+	 * @return <b>true</b> if the material uses tangents and <b>false</b> otherwise
+	 */
+	public boolean isvTangent() {
+		return vTangent;
+	}
+	
+	/**
+	 * @param texture
+	 *            the texture for which its mtex structure definition will be
+	 *            fetched
+	 * @return mtex structure of the current texture or <b>null</b> if none
+	 *         exists
+	 */
+	public Structure getMTex(Texture texture) {
+		return textureToMTexMap.get(texture);
+	}
 }

+ 39 - 219
engine/src/blender/com/jme3/scene/plugins/blender/materials/MaterialHelper.java

@@ -40,7 +40,6 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import com.jme3.asset.BlenderKey.FeaturesToLoad;
-import com.jme3.asset.GeneratedTextureKey;
 import com.jme3.material.MatParam;
 import com.jme3.material.MatParamTexture;
 import com.jme3.material.Material;
@@ -59,9 +58,7 @@ import com.jme3.shader.VarType;
 import com.jme3.texture.Image;
 import com.jme3.texture.Image.Format;
 import com.jme3.texture.Texture;
-import com.jme3.texture.Texture.MinFilter;
 import com.jme3.texture.Texture.Type;
-import com.jme3.texture.Texture.WrapMode;
 import com.jme3.util.BufferUtils;
 
 public class MaterialHelper extends AbstractBlenderHelper {
@@ -204,124 +201,66 @@ public class MaterialHelper extends AbstractBlenderHelper {
 		if(materialContext.textures.size() > 0) {
 			LOGGER.log(Level.WARNING, "Attetion! Many textures found for material: {0}. Only the first of each supported mapping types will be used!", materialContext.name);
 		}
-
-		DiffuseShader diffuseShader = this.getDiffuseShader(structure);
-		ColorRGBA diffuseColor = this.getDiffuseColor(structure, diffuseShader);
-		float[] diffuseColorArray = new float[] {diffuseColor.r, diffuseColor.g, diffuseColor.b};
 		
 		// texture
+		Type colorTextureType = null;
 		Map<String, Texture> texturesMap = new HashMap<String, Texture>();
-		Type firstTextureType = null;
-		if ((blenderContext.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.TEXTURES) != 0) {
-			TextureHelper textureHelper = blenderContext.getHelper(TextureHelper.class);
-			for (int i=0;i<materialContext.texturesCount;++i) {
-				Structure mtex = materialContext.mTexs.get(i);
-				
-				int texflag = ((Number) mtex.getFieldValue("texflag")).intValue();
-				boolean negateTexture = (texflag & 0x04) == 0;
-
-				int mapto = ((Number) mtex.getFieldValue("mapto")).intValue();
-				if (mapto != 0) {
-					Structure tex = materialContext.textures.get(i);
-					Texture texture = textureHelper.getTexture(tex, blenderContext);
-					if (texture != null) {
-						if(firstTextureType == null) {
-							firstTextureType = texture.getType();
-						} else if(firstTextureType != texture.getType()) {
-							LOGGER.warning("The texture with the name: " + texture.getName() + " is of different type than the first applied texture! It will not be applied!");
-							continue;
-						}
-
-						// NOTE: Enable mipmaps FOR ALL TEXTURES EVER
-						texture.setMinFilter(MinFilter.Trilinear);
-
-						if ((mapto & 0x01) != 0) {// Col
-							mapto &= 0xFFFFFFFE;//this is temporary to force loading of one texture of a mapping type (will be removed when textures merging is created)
-							// Map to COLOR channel or DIFFUSE
-							// Set diffuse to white so it doesn't get multiplied by texture
-							// result.setColor(shadeless ? "Color" : "Diffuse", ColorRGBA.White.clone());
-//							 result.setBoolean("UseMaterialColors", Boolean.FALSE);
-							// blending the texture with material color and texture's defined color
-							int blendType = ((Number) mtex.getFieldValue("blendtype")).intValue();
-							float[] color = new float[] { ((Number) mtex.getFieldValue("r")).floatValue(), ((Number) mtex.getFieldValue("g")).floatValue(), ((Number) mtex.getFieldValue("b")).floatValue() };
-							float colfac = ((Number) mtex.getFieldValue("colfac")).floatValue();
-							texture = textureHelper.blendTexture(diffuseColorArray, texture, color, colfac, blendType, negateTexture, blenderContext);
-							texture.setWrap(WrapMode.Repeat);
-							//TODO: textures merging
-							if (materialContext.shadeless) {
-								texturesMap.put(firstTextureType==Type.ThreeDimensional ? TEXTURE_TYPE_3D : TEXTURE_TYPE_COLOR, texture);
-							} else {
-								texturesMap.put(firstTextureType==Type.ThreeDimensional ? TEXTURE_TYPE_3D : TEXTURE_TYPE_DIFFUSE, texture);
-							}
-						}
-						if(firstTextureType == Type.TwoDimensional) {//for now other mappings available for images only
-							if ((mapto & 0x02) != 0 && !materialContext.shadeless) {// Nor
-								mapto &= 0xFFFFFFFD;//this is temporary to force loading of one texture of a mapping type (will be removed when textures merging is created)
-								Texture normalMapTexture;
-								if (texture.getKey() instanceof GeneratedTextureKey) {
-									normalMapTexture = textureHelper.convertToNormalMapTexture(texture, ((Number) mtex.getFieldValue("norfac")).floatValue());
-									normalMapTexture.setMinFilter(MinFilter.Trilinear);
-								} else {
-									normalMapTexture = texture;
-								}
-								texturesMap.put(TEXTURE_TYPE_NORMAL, normalMapTexture);
-							}
-							if ((mapto & 0x04) != 0 && !materialContext.shadeless) {// Spec
-								mapto &= 0xFFFFFFFB;//this is temporary to force loading of one texture of a mapping type (will be removed when textures merging is created)
-								// Map to SPECULAR
-								texturesMap.put(TEXTURE_TYPE_SPECULAR, texture);
-							}
-							if ((mapto & 0x40) != 0) {// Emit
-								mapto &= 0xFFFFFFF8;//this is temporary to force loading of one texture of a mapping type (will be removed when textures merging is created)
-								texturesMap.put(TEXTURE_TYPE_GLOW, texture);
-							}
-							if ((mapto & 0x80) != 0 && !materialContext.shadeless) {// Alpha
-								mapto &= 0xFFFFFF7F;//this is temporary to force loading of one texture of a mapping type (will be removed when textures merging is created)
-								texturesMap.put(TEXTURE_TYPE_ALPHA, texture);
-							}
-						} else {
-							LOGGER.warning("The following mappings: [Nor, Spec, Alpha] are available for 2D textures only!");
-						}
-					} else {
-						LOGGER.log(Level.WARNING, "Texture not found!");
-					}
+		TextureHelper textureHelper = blenderContext.getHelper(TextureHelper.class);
+		for(Entry<Number, Texture> textureEntry : materialContext.loadedTextures.entrySet()) {
+			int mapto = textureEntry.getKey().intValue();
+			Texture texture = textureEntry.getValue();
+			if ((mapto & MaterialContext.MTEX_COL) != 0) {
+				colorTextureType = texture.getType();
+				if (materialContext.shadeless) {
+					texturesMap.put(colorTextureType==Type.ThreeDimensional ? TEXTURE_TYPE_3D : TEXTURE_TYPE_COLOR, texture);
+				} else {
+					texturesMap.put(colorTextureType==Type.ThreeDimensional ? TEXTURE_TYPE_3D : TEXTURE_TYPE_DIFFUSE, texture);
+				}
+			}
+			if(texture.getType()==Type.TwoDimensional) {//so far only 2D textures can be mapped in other way than color
+				if ((mapto & MaterialContext.MTEX_NOR) != 0 && !materialContext.shadeless) {
+					Structure mTex = materialContext.getMTex(texture);
+					Texture normalMapTexture = textureHelper.convertToNormalMapTexture(texture, ((Number) mTex.getFieldValue("norfac")).floatValue());
+					texturesMap.put(TEXTURE_TYPE_NORMAL, normalMapTexture);
+				}
+				if ((mapto & MaterialContext.MTEX_EMIT) != 0) {
+					texturesMap.put(TEXTURE_TYPE_GLOW, texture);
+				}
+				if ((mapto & MaterialContext.MTEX_SPEC) != 0 && !materialContext.shadeless) {
+					texturesMap.put(TEXTURE_TYPE_SPECULAR, texture);
+				}
+				if ((mapto & MaterialContext.MTEX_ALPHA) != 0 && !materialContext.shadeless) {
+					texturesMap.put(TEXTURE_TYPE_ALPHA, texture);
 				}
 			}
 		}
 		
 		//creating the material
-		if(firstTextureType==Type.ThreeDimensional) {
+		if(colorTextureType==Type.ThreeDimensional) {
 			result = new Material(blenderContext.getAssetManager(), "jme3test/texture/tex3D.j3md");
 		} else {
 			if (materialContext.shadeless) {
 				result = new Material(blenderContext.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 			} else {
 				result = new Material(blenderContext.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");
-			}
-			
-			if (materialContext.vertexColor) {
-				result.setBoolean(materialContext.shadeless ? "VertexColor" : "UseVertexColor", true);
-			}
-			
-			if (materialContext.shadeless) {
-				// color of shadeless? doesn't seem to work in blender ..
-				diffuseColor = ColorRGBA.White.clone();
-			} else {
 				result.setBoolean("UseMaterialColors", Boolean.TRUE);
 
 				// setting the colors
-				result.setBoolean("Minnaert", diffuseShader == DiffuseShader.MINNAERT);
+				result.setBoolean("Minnaert", materialContext.diffuseShader == DiffuseShader.MINNAERT);
 				if (!materialContext.transparent) {
-					diffuseColor.a = 1;
+					materialContext.diffuseColor.a = 1;
 				}
-				result.setColor("Diffuse", diffuseColor);
+				result.setColor("Diffuse", materialContext.diffuseColor);
 
-				SpecularShader specularShader = this.getSpecularShader(structure);
-				result.setBoolean("WardIso", specularShader == SpecularShader.WARDISO);
-				result.setColor("Specular", this.getSpecularColor(structure, specularShader));
+				result.setBoolean("WardIso", materialContext.specularShader == SpecularShader.WARDISO);
+				result.setColor("Specular", materialContext.specularColor);
 
-				result.setColor("Ambient", this.getAmbientColor(structure));
-				result.setFloat("Shininess", this.getShininess(structure));
+				result.setColor("Ambient", materialContext.ambientColor);
+				result.setFloat("Shininess", materialContext.shininess);
+			}
+			
+			if (materialContext.vertexColor) {
+				result.setBoolean(materialContext.shadeless ? "VertexColor" : "UseVertexColor", true);
 			}
 		}
 		
@@ -487,125 +426,6 @@ public class MaterialHelper extends AbstractBlenderHelper {
 		return false;
 	}
 
-	/**
-	 * This method returns the diffuse color
-	 * 
-	 * @param materialStructure
-	 * @param diffuseShader
-	 * @return
-	 */
-	public ColorRGBA getDiffuseColor(Structure materialStructure, DiffuseShader diffuseShader) {
-		// bitwise 'or' of all textures mappings
-		int commonMapto = ((Number) materialStructure.getFieldValue("mapto")).intValue();
-
-		// diffuse color
-		float r = ((Number) materialStructure.getFieldValue("r")).floatValue();
-		float g = ((Number) materialStructure.getFieldValue("g")).floatValue();
-		float b = ((Number) materialStructure.getFieldValue("b")).floatValue();
-		float alpha = ((Number) materialStructure.getFieldValue("alpha")).floatValue();
-		if ((commonMapto & 0x01) == 0x01) {// Col
-			return new ColorRGBA(r, g, b, alpha);
-		} else {
-			switch (diffuseShader) {
-				case FRESNEL:
-				case ORENNAYAR:
-				case TOON:
-					break;// TODO: find what is the proper modification
-				case MINNAERT:
-				case LAMBERT:// TODO: check if that is correct
-					float ref = ((Number) materialStructure.getFieldValue("ref")).floatValue();
-					r *= ref;
-					g *= ref;
-					b *= ref;
-					break;
-				default:
-					throw new IllegalStateException("Unknown diffuse shader type: " + diffuseShader.toString());
-			}
-			return new ColorRGBA(r, g, b, alpha);
-		}
-	}
-
-	/**
-	 * This method returns an enum describing the type of a diffuse shader used by this material.
-	 * 
-	 * @param materialStructure
-	 *        the material structure filled with data
-	 * @return an enum describing the type of a diffuse shader used by this material
-	 */
-	public DiffuseShader getDiffuseShader(Structure materialStructure) {
-		int diff_shader = ((Number) materialStructure.getFieldValue("diff_shader")).intValue();
-		return DiffuseShader.values()[diff_shader];
-	}
-
-	/**
-	 * This method returns an ambient color used by the material.
-	 * 
-	 * @param materialStructure
-	 *        the material structure filled with data
-	 * @return an ambient color used by the material
-	 */
-	public ColorRGBA getAmbientColor(Structure materialStructure) {
-		float r = ((Number) materialStructure.getFieldValue("ambr")).floatValue();
-		float g = ((Number) materialStructure.getFieldValue("ambg")).floatValue();
-		float b = ((Number) materialStructure.getFieldValue("ambb")).floatValue();
-		float alpha = ((Number) materialStructure.getFieldValue("alpha")).floatValue();
-		return new ColorRGBA(r, g, b, alpha);
-	}
-
-	/**
-	 * This method returns an enum describing the type of a specular shader used by this material.
-	 * 
-	 * @param materialStructure
-	 *        the material structure filled with data
-	 * @return an enum describing the type of a specular shader used by this material
-	 */
-	public SpecularShader getSpecularShader(Structure materialStructure) {
-		int spec_shader = ((Number) materialStructure.getFieldValue("spec_shader")).intValue();
-		return SpecularShader.values()[spec_shader];
-	}
-
-	/**
-	 * This method returns a specular color used by the material.
-	 * 
-	 * @param materialStructure
-	 *        the material structure filled with data
-	 * @return a specular color used by the material
-	 */
-	public ColorRGBA getSpecularColor(Structure materialStructure, SpecularShader specularShader) {
-		float r = ((Number) materialStructure.getFieldValue("specr")).floatValue();
-		float g = ((Number) materialStructure.getFieldValue("specg")).floatValue();
-		float b = ((Number) materialStructure.getFieldValue("specb")).floatValue();
-		float alpha = ((Number) materialStructure.getFieldValue("alpha")).floatValue();
-		switch (specularShader) {
-			case BLINN:
-			case COOKTORRENCE:
-			case TOON:
-			case WARDISO:// TODO: find what is the proper modification
-				break;
-			case PHONG:// TODO: check if that is correct
-				float spec = ((Number) materialStructure.getFieldValue("spec")).floatValue();
-				r *= spec * 0.5f;
-				g *= spec * 0.5f;
-				b *= spec * 0.5f;
-				break;
-			default:
-				throw new IllegalStateException("Unknown specular shader type: " + specularShader.toString());
-		}
-		return new ColorRGBA(r, g, b, alpha);
-	}
-
-	/**
-	 * This method returns the sihiness of this material or DEFAULT_SHININESS value if not present.
-	 * 
-	 * @param materialStructure
-	 *        the material structure filled with data
-	 * @return the sihiness of this material or DEFAULT_SHININESS value if not present
-	 */
-	public float getShininess(Structure materialStructure) {
-		float shininess = ((Number) materialStructure.getFieldValue("emit")).floatValue();
-		return shininess > 0.0f ? shininess : DEFAULT_SHININESS;
-	}
-
 	/**
 	 * This method returns the table of materials connected to the specified structure. The given structure can be of any type (ie. mesh or
 	 * curve) but needs to have 'mat' field/

+ 2 - 16
engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureGenerator.java

@@ -278,7 +278,7 @@ import com.jme3.texture.Texture;
 	 * @param tex texture structure
 	 * @param texres
 	 */
-	protected void applyBrightnessAndContrast(BrightnessAndContrastData bacd, TextureResult texres) {
+	protected void applyBrightnessAndContrast(BrightnessAndContrastData bacd, TexturePixel texres) {
         texres.red = (texres.red - 0.5f) * bacd.contrast + bacd.brightness;
         if (texres.red < 0.0f) {
             texres.red = 0.0f;
@@ -299,7 +299,7 @@ import com.jme3.texture.Texture;
 	 * @param contrast
 	 * @param brightness
 	 */
-	protected void applyBrightnessAndContrast(TextureResult texres, float contrast, float brightness) {
+	protected void applyBrightnessAndContrast(TexturePixel texres, float contrast, float brightness) {
         texres.intensity = (texres.intensity - 0.5f) * contrast + brightness;
         if (texres.intensity < 0.0f) {
             texres.intensity = 0.0f;
@@ -308,20 +308,6 @@ import com.jme3.texture.Texture;
         }
     }
 	
-	/**
-	 * The result pixel of generated texture computations;
-	 * 
-	 * @author Marcin Roguski (Kaelthas)
-	 */
-	protected static class TextureResult implements Cloneable {
-		public float	intensity, red, green, blue, alpha;
-
-		@Override
-		public Object clone() throws CloneNotSupportedException {
-			return super.clone();
-		}
-	}
-	
 	/**
 	 * A class constaining the colorband data.
 	 * 

+ 4 - 3
engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureGeneratorBlend.java

@@ -118,13 +118,13 @@ public final class TextureGeneratorBlend extends TextureGenerator {
 	protected Texture generate(Structure tex, int width, int height, int depth, BlenderContext blenderContext) {
 		int flag = ((Number) tex.getFieldValue("flag")).intValue();
 		int stype = ((Number) tex.getFieldValue("stype")).intValue();
-		TextureResult texres = new TextureResult();
+		TexturePixel texres = new TexturePixel();
 		int halfW = width >> 1, halfH = height >> 1, halfD = depth >> 1, index = 0;
 		float wDelta = 1.0f / halfW, hDelta = 1.0f / halfH, dDelta = 1.0f / halfD, x, y;
 		float[][] colorBand = this.computeColorband(tex, blenderContext);
 		BrightnessAndContrastData bacd = new BrightnessAndContrastData(tex);
-		Format format = colorBand != null ? Format.RGB8 : Format.Luminance8;
-		int bytesPerPixel = colorBand != null ? 3 : 1;
+		Format format = colorBand != null ? Format.RGBA8 : Format.Luminance8;
+		int bytesPerPixel = colorBand != null ? 4 : 1;
 		boolean flipped = (flag & NoiseGenerator.TEX_FLIPBLEND) != 0;
 		
 		byte[] data = new byte[width * height * depth * bytesPerPixel];
@@ -150,6 +150,7 @@ public final class TextureGeneratorBlend extends TextureGenerator {
 						data[index++] = (byte) (texres.red * 255.0f);
 						data[index++] = (byte) (texres.green * 255.0f);
 						data[index++] = (byte) (texres.blue * 255.0f);
+						data[index++] = (byte) (colorBand[colorbandIndex][3] * 255.0f);
 					} else {
 						this.applyBrightnessAndContrast(texres, bacd.contrast, bacd.brightness);
 						data[index++] = (byte) (texres.intensity * 255.0f);

+ 5 - 3
engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureGeneratorClouds.java

@@ -68,7 +68,7 @@ public class TextureGeneratorClouds extends TextureGenerator {
 	@Override
 	protected Texture generate(Structure tex, int width, int height, int depth, BlenderContext blenderContext) {
 		float[] texvec = new float[] { 0, 0, 0 };
-		TextureResult texres = new TextureResult();
+		TexturePixel texres = new TexturePixel();
 
 		// reading the data from the texture structure
 		float noisesize = ((Number) tex.getFieldValue("noisesize")).floatValue();
@@ -80,8 +80,8 @@ public class TextureGeneratorClouds extends TextureGenerator {
 		int halfW = width >> 1, halfH = height >> 1, halfD = depth >> 1, index = 0;
 		float wDelta = 1.0f / halfW, hDelta = 1.0f / halfH, dDelta = 1.0f / halfD;
 		float[][] colorBand = this.computeColorband(tex, blenderContext);
-		Format format = sType == TEX_COLOR || colorBand != null ? Format.RGB8 : Format.Luminance8;
-		int bytesPerPixel = sType == TEX_COLOR || colorBand != null ? 3 : 1;
+		Format format = sType == TEX_COLOR || colorBand != null ? Format.RGBA8 : Format.Luminance8;
+		int bytesPerPixel = sType == TEX_COLOR || colorBand != null ? 4 : 1;
 		BrightnessAndContrastData bacd = new BrightnessAndContrastData(tex);
 		
 		byte[] data = new byte[width * height * depth * bytesPerPixel];
@@ -103,6 +103,7 @@ public class TextureGeneratorClouds extends TextureGenerator {
 						data[index++] = (byte) (texres.red * 255.0f);
 						data[index++] = (byte) (texres.green * 255.0f);
 						data[index++] = (byte) (texres.blue * 255.0f);
+						data[index++] = (byte) (colorBand[colorbandIndex][3] * 255.0f);
 					} else if (sType == TEX_COLOR) {
 						texres.red = texres.intensity;
 						texres.green = NoiseGenerator.NoiseFunctions.turbulence(texvec[1], texvec[0], texvec[2], noisesize, noiseDepth, noiseBasis, isHard);
@@ -115,6 +116,7 @@ public class TextureGeneratorClouds extends TextureGenerator {
 						data[index++] = (byte) (texres.red * 255.0f);
 						data[index++] = (byte) (texres.green * 255.0f);
 						data[index++] = (byte) (texres.blue * 255.0f);
+						data[index++] = (byte) (255);//1.0f * 255.0f
 					} else {
 						this.applyBrightnessAndContrast(texres, bacd.contrast, bacd.brightness);
 						data[index++] = (byte) (texres.intensity * 255.0f);

+ 6 - 3
engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureGeneratorDistnoise.java

@@ -34,6 +34,7 @@ package com.jme3.scene.plugins.blender.textures;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 
+import com.jme3.math.FastMath;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.file.Structure;
 import com.jme3.scene.plugins.blender.textures.NoiseGenerator.NoiseFunction;
@@ -65,13 +66,13 @@ public class TextureGeneratorDistnoise extends TextureGenerator {
 		int noisebasis = ((Number) tex.getFieldValue("noisebasis")).intValue();
 		int noisebasis2 = ((Number) tex.getFieldValue("noisebasis2")).intValue();
 
-		TextureResult texres = new TextureResult();
+		TexturePixel texres = new TexturePixel();
 		float[] texvec = new float[] { 0, 0, 0 };
 		int halfW = width >> 1, halfH = height >> 1, halfD = depth >> 1, index = 0;
 		float wDelta = 1.0f / halfW, hDelta = 1.0f / halfH, dDelta = 1.0f / halfD;
 		float[][] colorBand = this.computeColorband(tex, blenderContext);
-		Format format = colorBand != null ? Format.RGB8 : Format.Luminance8;
-		int bytesPerPixel = colorBand != null ? 3 : 1;
+		Format format = colorBand != null ? Format.RGBA8 : Format.Luminance8;
+		int bytesPerPixel = colorBand != null ? 4 : 1;
 		BrightnessAndContrastData bacd = new BrightnessAndContrastData(tex);
 		
 		byte[] data = new byte[width * height * depth * bytesPerPixel];
@@ -82,6 +83,7 @@ public class TextureGeneratorDistnoise extends TextureGenerator {
 				for (int k = -halfD; k < halfD; ++k) {
 					texvec[2] = dDelta * k;
 					texres.intensity = this.musgraveVariableLunacrityNoise(texvec[0], texvec[1], texvec[2], distAmount, noisebasis, noisebasis2);
+					texres.intensity = FastMath.clamp(texres.intensity, 0.0f, 1.0f);
 					if (colorBand != null) {
 						int colorbandIndex = (int) (texres.intensity * 1000.0f);
 						texres.red = colorBand[colorbandIndex][0];
@@ -92,6 +94,7 @@ public class TextureGeneratorDistnoise extends TextureGenerator {
 						data[index++] = (byte) (texres.red * 255.0f);
 						data[index++] = (byte) (texres.green * 255.0f);
 						data[index++] = (byte) (texres.blue * 255.0f);
+						data[index++] = (byte) (colorBand[colorbandIndex][3] * 255.0f);
 					} else {
 						this.applyBrightnessAndContrast(texres, bacd.contrast, bacd.brightness);
 						data[index++] = (byte) (texres.intensity * 255.0f);

+ 8 - 4
engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureGeneratorMagic.java

@@ -34,6 +34,7 @@ package com.jme3.scene.plugins.blender.textures;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 
+import com.jme3.math.FastMath;
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.file.Structure;
 import com.jme3.texture.Image;
@@ -126,13 +127,13 @@ public class TextureGeneratorMagic extends TextureGenerator {
 		int noisedepth = ((Number) tex.getFieldValue("noisedepth")).intValue();
 		float turbul = ((Number) tex.getFieldValue("turbul")).floatValue() / 5.0f;
 		float[] texvec = new float[] { 0, 0, 0 };
-		TextureResult texres = new TextureResult();
+		TexturePixel texres = new TexturePixel();
 		int halfW = width >> 1, halfH = height >> 1, halfD = depth >> 1, index = 0;
 		float wDelta = 1.0f / halfW, hDelta = 1.0f / halfH, dDelta = 1.0f / halfD;
 		float[][] colorBand = this.computeColorband(tex, blenderContext);
 		BrightnessAndContrastData bacd = new BrightnessAndContrastData(tex);
 		
-		byte[] data = new byte[width * height * depth * 3];
+		byte[] data = new byte[width * height * depth * 4];
 		for (int i = -halfW; i < halfW; ++i) {
 			texvec[0] = wDelta * i;
 			for (int j = -halfH; j < halfH; ++j) {
@@ -145,11 +146,12 @@ public class TextureGeneratorMagic extends TextureGenerator {
 					xyz[2] = -(float) Math.cos((-texvec[0] - texvec[1] + texvec[2]) * 5.0f);
 
 					if (colorBand != null) {
-						texres.intensity = 0.3333f * (xyz[0] + xyz[1] + xyz[2]);
+						texres.intensity = FastMath.clamp(0.3333f * (xyz[0] + xyz[1] + xyz[2]), 0.0f, 1.0f);
 						int colorbandIndex = (int) (texres.intensity * 1000.0f);
 						texres.red = colorBand[colorbandIndex][0];
 						texres.green = colorBand[colorbandIndex][1];
 						texres.blue = colorBand[colorbandIndex][2];
+						texres.alpha = colorBand[colorbandIndex][3];
 					} else {
 						if (noisedepth > 0) {
 							xyz[0] *= turb;
@@ -169,17 +171,19 @@ public class TextureGeneratorMagic extends TextureGenerator {
 						texres.red = 0.5f - xyz[0];
 						texres.green = 0.5f - xyz[1];
 						texres.blue = 0.5f - xyz[2];
+						texres.alpha = 1.0f;
 					}
 					this.applyBrightnessAndContrast(bacd, texres);
 					data[index++] = (byte) (texres.red * 255.0f);
 					data[index++] = (byte) (texres.green * 255.0f);
 					data[index++] = (byte) (texres.blue * 255.0f);
+					data[index++] = (byte) (texres.alpha * 255.0f);
 				}
 			}
 		}
 		ArrayList<ByteBuffer> dataArray = new ArrayList<ByteBuffer>(1);
 		dataArray.add(BufferUtils.createByteBuffer(data));
-		return new Texture3D(new Image(Format.RGB8, width, height, depth, dataArray));
+		return new Texture3D(new Image(Format.RGBA8, width, height, depth, dataArray));
 	}
 	
 	private static interface NoiseDepthFunction {

+ 4 - 3
engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureGeneratorMarble.java

@@ -64,12 +64,12 @@ public class TextureGeneratorMarble extends TextureGeneratorWood {
 	@Override
 	protected Texture generate(Structure tex, int width, int height, int depth, BlenderContext blenderContext) {
 		float[] texvec = new float[] { 0, 0, 0 };
-		TextureResult texres = new TextureResult();
+		TexturePixel texres = new TexturePixel();
 		int halfW = width >> 1, halfH = height >> 1, halfD = depth >> 1, index = 0;
 		float wDelta = 1.0f / halfW, hDelta = 1.0f / halfH, dDelta = 1.0f / halfD;
 		float[][] colorBand = this.computeColorband(tex, blenderContext);
-		Format format = colorBand != null ? Format.RGB8 : Format.Luminance8;
-		int bytesPerPixel = colorBand != null ? 3 : 1;
+		Format format = colorBand != null ? Format.RGBA8 : Format.Luminance8;
+		int bytesPerPixel = colorBand != null ? 4 : 1;
 		BrightnessAndContrastData bacd = new BrightnessAndContrastData(tex);
 		MarbleData marbleData = new MarbleData(tex);
 		
@@ -91,6 +91,7 @@ public class TextureGeneratorMarble extends TextureGeneratorWood {
 						data[index++] = (byte) (texres.red * 255.0f);
 						data[index++] = (byte) (texres.green * 255.0f);
 						data[index++] = (byte) (texres.blue * 255.0f);
+						data[index++] = (byte) (colorBand[colorbandIndex][3] * 255.0f);
 					} else {
 						this.applyBrightnessAndContrast(texres, bacd.contrast, bacd.brightness);
 						data[index++] = (byte) (texres.intensity * 255.0f);

+ 4 - 3
engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureGeneratorMusgrave.java

@@ -62,13 +62,13 @@ public class TextureGeneratorMusgrave extends TextureGenerator {
 	protected Texture generate(Structure tex, int width, int height, int depth, BlenderContext blenderContext) {
 		int stype = ((Number) tex.getFieldValue("stype")).intValue();
 		float noisesize = ((Number) tex.getFieldValue("noisesize")).floatValue();
-		TextureResult texres = new TextureResult();
+		TexturePixel texres = new TexturePixel();
 		float[] texvec = new float[] { 0, 0, 0 };
 		int halfW = width >> 1, halfH = height >> 1, halfD = depth >> 1, index = 0;
 		float wDelta = 1.0f / halfW, hDelta = 1.0f / halfH, dDelta = 1.0f / halfD;
 		float[][] colorBand = this.computeColorband(tex, blenderContext);
-		Format format = colorBand != null ? Format.RGB8 : Format.Luminance8;
-		int bytesPerPixel = colorBand != null ? 3 : 1;
+		Format format = colorBand != null ? Format.RGBA8 : Format.Luminance8;
+		int bytesPerPixel = colorBand != null ? 4 : 1;
 		MusgraveData musgraveData = new MusgraveData(tex);
 		MusgraveFunction musgraveFunction;
 		BrightnessAndContrastData bacd = new BrightnessAndContrastData(tex);
@@ -101,6 +101,7 @@ public class TextureGeneratorMusgrave extends TextureGenerator {
 						data[index++] = (byte) (texres.red * 255.0f);
 						data[index++] = (byte) (texres.green * 255.0f);
 						data[index++] = (byte) (texres.blue * 255.0f);
+						data[index++] = (byte) (colorBand[colorbandIndex][3] * 255.0f);
 					} else {
 						this.applyBrightnessAndContrast(bacd, texres);
 						data[index++] = (byte) (texres.intensity * 255.0f);

+ 5 - 4
engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureGeneratorNoise.java

@@ -62,11 +62,11 @@ public class TextureGeneratorNoise extends TextureGenerator {
 	protected Texture generate(Structure tex, int width, int height, int depth, BlenderContext blenderContext) {
 		int val, random, loop;
 		int noisedepth = ((Number) tex.getFieldValue("noisedepth")).intValue();
-		TextureResult texres = new TextureResult();
+		TexturePixel texres = new TexturePixel();
 		int halfW = width >> 1, halfH = height >> 1, halfD = depth >> 1, index = 0;
 		float[][] colorBand = this.computeColorband(tex, blenderContext);
-		Format format = colorBand != null ? Format.RGB8 : Format.Luminance8;
-		int bytesPerPixel = colorBand != null ? 3 : 1;
+		Format format = colorBand != null ? Format.RGBA8 : Format.Luminance8;
+		int bytesPerPixel = colorBand != null ? 4 : 1;
 		BrightnessAndContrastData bacd = new BrightnessAndContrastData(tex);
 		
 		byte[] data = new byte[width * height * depth * bytesPerPixel];
@@ -81,7 +81,7 @@ public class TextureGeneratorNoise extends TextureGenerator {
 						random >>= 2;
 						val *= random & 3;
 					}
-					texres.intensity = val;
+					texres.intensity = FastMath.clamp(val, 0.0f, 1.0f);
 					if (colorBand != null) {
 						int colorbandIndex = (int) (texres.intensity * 1000.0f);
 						texres.red = colorBand[colorbandIndex][0];
@@ -92,6 +92,7 @@ public class TextureGeneratorNoise extends TextureGenerator {
 						data[index++] = (byte) (texres.red * 255.0f);
 						data[index++] = (byte) (texres.green * 255.0f);
 						data[index++] = (byte) (texres.blue * 255.0f);
+						data[index++] = (byte) (colorBand[colorbandIndex][3] * 255.0f);
 					} else {
 						this.applyBrightnessAndContrast(texres, bacd.contrast, bacd.brightness);
 						data[index++] = (byte) (texres.intensity * 255.0f);

+ 5 - 3
engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureGeneratorStucci.java

@@ -72,12 +72,12 @@ public class TextureGeneratorStucci extends TextureGenerator {
 		}
 		
 		float[] texvec = new float[] { 0, 0, 0 };
-		TextureResult texres = new TextureResult();
+		TexturePixel texres = new TexturePixel();
 		int halfW = width >> 1, halfH = height >> 1, halfD = depth >> 1, index = 0;
 		float wDelta = 1.0f / halfW, hDelta = 1.0f / halfH, dDelta = 1.0f / halfD, noiseValue, ofs;;
 		float[][] colorBand = this.computeColorband(tex, blenderContext);
-		Format format = colorBand != null ? Format.RGB8 : Format.Luminance8;
-		int bytesPerPixel = colorBand != null ? 3 : 1;
+		Format format = colorBand != null ? Format.RGBA8 : Format.Luminance8;
+		int bytesPerPixel = colorBand != null ? 4 : 1;
 
 		byte[] data = new byte[width * height * depth * bytesPerPixel];
 		for (int i = -halfW; i < halfW; ++i) {
@@ -98,6 +98,7 @@ public class TextureGeneratorStucci extends TextureGenerator {
 						texres.red = colorBand[colorbandIndex][0];
 						texres.green = colorBand[colorbandIndex][1];
 						texres.blue = colorBand[colorbandIndex][2];
+						texres.alpha = colorBand[colorbandIndex][3];
 					}
 
 					if (stype == NoiseGenerator.TEX_WALLOUT) {
@@ -111,6 +112,7 @@ public class TextureGeneratorStucci extends TextureGenerator {
 						data[index++] = (byte) (texres.red * 255.0f);
 						data[index++] = (byte) (texres.green * 255.0f);
 						data[index++] = (byte) (texres.blue * 255.0f);
+						data[index++] = (byte) (texres.alpha * 255.0f);
 					} else {
 						data[index++] = (byte) (texres.intensity * 255.0f);
 					}

+ 6 - 3
engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureGeneratorVoronoi.java

@@ -71,14 +71,14 @@ public class TextureGeneratorVoronoi extends TextureGenerator {
 		int distm = ((Number) tex.getFieldValue("vn_distm")).intValue();
 		int voronoiColorType = ((Number) tex.getFieldValue("vn_coltype")).intValue();
 
-		TextureResult texres = new TextureResult();
+		TexturePixel texres = new TexturePixel();
 		float[] texvec = new float[] { 0, 0, 0 };
 		int halfW = width >> 1, halfH = height >> 1, halfD = depth >> 1, index = 0;
 		float wDelta = 1.0f / halfW, hDelta = 1.0f / halfH, dDelta = 1.0f / halfD;
 		
 		float[][] colorBand = this.computeColorband(tex, blenderContext);
-		Format format = voronoiColorType != 0 || colorBand != null ? Format.RGB8 : Format.Luminance8;
-		int bytesPerPixel = voronoiColorType != 0 || colorBand != null ? 3 : 1;
+		Format format = voronoiColorType != 0 || colorBand != null ? Format.RGBA8 : Format.Luminance8;
+		int bytesPerPixel = voronoiColorType != 0 || colorBand != null ? 4 : 1;
 		BrightnessAndContrastData bacd = new BrightnessAndContrastData(tex);
 		
 		float[] da = new float[4], pa = new float[12];
@@ -111,8 +111,10 @@ public class TextureGeneratorVoronoi extends TextureGenerator {
 						texres.red = colorBand[colorbandIndex][0];
 						texres.green = colorBand[colorbandIndex][1];
 						texres.blue = colorBand[colorbandIndex][2];
+						texres.alpha = colorBand[colorbandIndex][3];
 					} else if (voronoiColorType != 0) {
 						texres.red = texres.green = texres.blue = 0.0f;
+						texres.alpha = 1.0f;
 						for(int m=0; m<12; m+=3) {
 							weight = voronoiWeights[m/3];
 							this.cellNoiseV(pa[m], pa[m + 1], pa[m + 2], hashPoint);
@@ -145,6 +147,7 @@ public class TextureGeneratorVoronoi extends TextureGenerator {
 						data[index++] = (byte) (texres.red * 255.0f);
 						data[index++] = (byte) (texres.green * 255.0f);
 						data[index++] = (byte) (texres.blue * 255.0f);
+						data[index++] = (byte) (texres.alpha * 255.0f);
 					} else {
 						this.applyBrightnessAndContrast(texres, bacd.contrast, bacd.brightness);
 						data[index++] = (byte) (texres.intensity * 255.0f);

+ 4 - 3
engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureGeneratorWood.java

@@ -73,15 +73,15 @@ public class TextureGeneratorWood extends TextureGenerator {
 	@Override
 	protected Texture generate(Structure tex, int width, int height, int depth, BlenderContext blenderContext) {
 		float[] texvec = new float[] { 0, 0, 0 };
-		TextureResult texres = new TextureResult();
+		TexturePixel texres = new TexturePixel();
 		int halfW = width >> 1;
 		int halfH = height >> 1;
 		int halfD = depth >> 1;
 		float wDelta = 1.0f / halfW, hDelta = 1.0f / halfH, dDelta = 1.0f / halfD;
 		
 		float[][] colorBand = this.computeColorband(tex, blenderContext);
-		Format format = colorBand != null ? Format.RGB8 : Format.Luminance8;
-		int bytesPerPixel = colorBand != null ? 3 : 1;
+		Format format = colorBand != null ? Format.RGBA8 : Format.Luminance8;
+		int bytesPerPixel = colorBand != null ? 4 : 1;
 		WoodIntensityData woodIntensityData = new WoodIntensityData(tex);
 		BrightnessAndContrastData bacd = new BrightnessAndContrastData(tex);
 		
@@ -106,6 +106,7 @@ public class TextureGeneratorWood extends TextureGenerator {
 						data[index++] = (byte) (texres.red * 255.0f);
 						data[index++] = (byte) (texres.green * 255.0f);
 						data[index++] = (byte) (texres.blue * 255.0f);
+						data[index++] = (byte) (colorBand[colorbandIndex][3] * 255.0f);
 					} else {
 						this.applyBrightnessAndContrast(texres, bacd.contrast, bacd.brightness);
 						data[index++] = (byte) (texres.intensity * 255.0f);

+ 105 - 22
engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureHelper.java

@@ -50,6 +50,7 @@ import com.jme3.asset.BlenderKey;
 import com.jme3.asset.BlenderKey.FeaturesToLoad;
 import com.jme3.asset.GeneratedTextureKey;
 import com.jme3.asset.TextureKey;
+import com.jme3.math.ColorRGBA;
 import com.jme3.math.FastMath;
 import com.jme3.math.Vector3f;
 import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
@@ -59,10 +60,12 @@ import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.file.FileBlockHeader;
 import com.jme3.scene.plugins.blender.file.Pointer;
 import com.jme3.scene.plugins.blender.file.Structure;
+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.Format;
 import com.jme3.texture.Texture;
+import com.jme3.texture.Texture.MinFilter;
 import com.jme3.texture.Texture.WrapMode;
 import com.jme3.texture.Texture2D;
 import com.jme3.texture.Texture3D;
@@ -215,6 +218,8 @@ public class TextureHelper extends AbstractBlenderHelper {
 		if (result != null) {
 			result.setName(tex.getName());
 			result.setWrap(WrapMode.Repeat);
+			// NOTE: Enable mipmaps FOR ALL TEXTURES EVER
+			result.setMinFilter(MinFilter.Trilinear);
 			if(type != TEX_IMAGE) {//only generated textures should have this key
 				result.setKey(new GeneratedTextureKey(tex.getName()));
 			}
@@ -261,7 +266,7 @@ public class TextureHelper extends AbstractBlenderHelper {
 			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) 255.0f);//1.0f * 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));
@@ -272,6 +277,78 @@ public class TextureHelper extends AbstractBlenderHelper {
 		}
 	}
 
+	/**
+	 * This method merges the given textures. The result texture has no alpha
+	 * factor (is always opaque).
+	 * 
+	 * @param sources
+	 *            the textures to be merged
+	 * @param materialContext
+	 *            the context of the material
+	 * @return merged textures
+	 */
+	public Texture mergeTextures(List<Texture> sources, MaterialContext materialContext) {
+		Texture result = null;
+		if(sources!=null && sources.size()>0) {
+			//checking the sizes of the textures (tehy should perfectly match)
+			int lastTextureWithoutAlphaIndex = 0;
+			int width = sources.get(0).getImage().getWidth();
+			int height = sources.get(0).getImage().getHeight();
+			int depth = sources.get(0).getImage().getDepth();
+			
+			for(Texture source : sources) {
+				if(source.getImage().getWidth() != width) {
+					throw new IllegalArgumentException("The texture " + source.getName() + " has invalid width! It should be: " + width + '!');
+				}
+				if(source.getImage().getHeight() != height) {
+					throw new IllegalArgumentException("The texture " + source.getName() + " has invalid height! It should be: " + height + '!');
+				}
+				if(source.getImage().getDepth() != depth) {
+					throw new IllegalArgumentException("The texture " + source.getName() + " has invalid depth! It should be: " + depth + '!');
+				}
+				//support for more formats is not necessary at the moment
+				if(source.getImage().getFormat()!=Format.RGB8 && source.getImage().getFormat()!=Format.BGR8) {
+					++lastTextureWithoutAlphaIndex;
+				}
+			}
+			
+			//remove textures before the one without alpha (they will be covered anyway)
+			if(lastTextureWithoutAlphaIndex > 0 && lastTextureWithoutAlphaIndex<sources.size()-1) {
+				sources = sources.subList(lastTextureWithoutAlphaIndex, sources.size()-1);
+			}
+			int pixelsAmount = width * height * depth;
+			
+			ByteBuffer data = BufferUtils.createByteBuffer(pixelsAmount * 3);
+			TexturePixel resultPixel = new TexturePixel();
+			TexturePixel sourcePixel = new TexturePixel();
+			ColorRGBA diffuseColor = materialContext.getDiffuseColor();
+			for (int i = 0; i < pixelsAmount; ++i) {
+				for (int j = 0; j < sources.size(); ++j) {
+					Image image = sources.get(j).getImage();
+					ByteBuffer sourceData = image.getData(0);
+					if(j==0) {
+						resultPixel.fromColor(diffuseColor);
+						sourcePixel.fromImage(image.getFormat(), sourceData, i);
+						resultPixel.merge(sourcePixel);
+					} else {
+						sourcePixel.fromImage(image.getFormat(), sourceData, i);
+						resultPixel.merge(sourcePixel);
+					}
+				}
+				data.put((byte)(255 * resultPixel.red));
+				data.put((byte)(255 * resultPixel.green));
+				data.put((byte)(255 * resultPixel.blue));
+				resultPixel.clear();
+			}
+			
+			ArrayList<ByteBuffer> arrayData = new ArrayList<ByteBuffer>(1);
+			arrayData.add(data);
+			//TODO: add different texture types
+			result = new Texture3D(new Image(Format.RGB8, width, height, depth, arrayData));
+		}
+		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.
@@ -293,46 +370,52 @@ public class TextureHelper extends AbstractBlenderHelper {
 	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 ? 1.0f - pixelValue / 255.0f : (~pixelValue + 1) / 255.0f;
+		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 ? 1.0f - pixelValue / 255.0f : (~pixelValue + 1) / 255.0f;
+			materialColor[2] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
 			pixelValue = data.get();
-			materialColor[1] = pixelValue >= 0 ? 1.0f - pixelValue / 255.0f : (~pixelValue + 1) / 255.0f;
+			materialColor[1] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
 			pixelValue = data.get();
-			materialColor[0] = pixelValue >= 0 ? 1.0f - pixelValue / 255.0f : (~pixelValue + 1) / 255.0f;
+			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 ? 1.0f - pixelValue / 255.0f : (~pixelValue + 1) / 255.0f;
+			materialColor[1] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
 			pixelValue = data.get();
-			materialColor[0] = pixelValue >= 0 ? 1.0f - pixelValue / 255.0f : (~pixelValue + 1) / 255.0f;
+			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 ? 1.0f - pixelValue / 255.0f : (~pixelValue + 1) / 255.0f;
+			materialColor[1] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
 			pixelValue = data.get();
-			materialColor[2] = pixelValue >= 0 ? 1.0f - pixelValue / 255.0f : (~pixelValue + 1) / 255.0f;
-			break;
-		case RGBA8:
-			materialColor[0] = firstPixelValue;
-			pixelValue = data.get();
-			materialColor[1] = pixelValue >= 0 ? 1.0f - pixelValue / 255.0f : (~pixelValue + 1) / 255.0f;
-			pixelValue = data.get();
-			materialColor[2] = pixelValue >= 0 ? 1.0f - pixelValue / 255.0f : (~pixelValue + 1) / 255.0f;
-			data.get(); // ignore alpha
-			break;
-		case Luminance8:
-			tin = neg ? 1.0f - firstPixelValue : firstPixelValue;
-			neg = false;//do not negate the materialColor, it must be unchanged
+			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
-			data.get(); // ignore alpha
+			pixelValue = data.get(); // ignore alpha
+			materialColor[3] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
 			break;
 		case Luminance16:
 		case Luminance16Alpha16:

+ 95 - 0
engine/src/blender/com/jme3/scene/plugins/blender/textures/TexturePixel.java

@@ -0,0 +1,95 @@
+package com.jme3.scene.plugins.blender.textures;
+
+import java.nio.ByteBuffer;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.jme3.math.ColorRGBA;
+import com.jme3.texture.Image.Format;
+
+/*package*/ class TexturePixel implements Cloneable {
+	private static final Logger LOGGER = Logger.getLogger(TexturePixel.class.getName());
+	
+	public float	intensity, red, green, blue, alpha;
+
+	public void fromColor(ColorRGBA colorRGBA) {
+		this.intensity = 0;
+		this.red = colorRGBA.r;
+		this.green = colorRGBA.g;
+		this.blue = colorRGBA.b;
+		this.alpha = colorRGBA.a;
+	}
+	
+	public void fromImage(Format imageFormat, ByteBuffer data, int pixelIndex) {
+		int firstByteIndex;
+		byte pixelValue;
+		switch(imageFormat) {
+			case ABGR8:
+				firstByteIndex = pixelIndex << 2;
+				pixelValue = data.get(firstByteIndex);
+				this.alpha = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
+				pixelValue = data.get(firstByteIndex + 1);
+				this.blue = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
+				pixelValue = data.get(firstByteIndex + 2);
+				this.green = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
+				pixelValue = data.get(firstByteIndex + 3);
+				this.red = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
+				break;
+			case RGBA8:
+				firstByteIndex = pixelIndex << 2;
+				pixelValue = data.get(firstByteIndex);
+				this.red = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
+				pixelValue = data.get(firstByteIndex + 1);
+				this.green = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
+				pixelValue = data.get(firstByteIndex + 2);
+				this.blue = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
+				pixelValue = data.get(firstByteIndex + 3);
+				this.alpha = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
+				break;
+			case BGR8:
+				firstByteIndex = pixelIndex * 3;
+				pixelValue = data.get(firstByteIndex);
+				this.blue = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
+				pixelValue = data.get(firstByteIndex + 1);
+				this.green = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
+				pixelValue = data.get(firstByteIndex + 2);
+				this.red = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
+				this.alpha = 1.0f;
+				break;
+			case RGB8:
+				firstByteIndex = pixelIndex * 3;
+				pixelValue = data.get(firstByteIndex);
+				this.red = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
+				pixelValue = data.get(firstByteIndex + 1);
+				this.green = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
+				pixelValue = data.get(firstByteIndex + 2);
+				this.blue = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
+				this.alpha = 1.0f;
+				break;
+			case Luminance8:
+				pixelValue = data.get(pixelIndex);
+				this.intensity = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
+				break;
+			default:
+				LOGGER.log(Level.FINEST, "Unknown type of texture: {0}. Black pixel used!", imageFormat);
+				this.intensity = this.blue = this.red = this.green = this.alpha = 0.0f;
+		}
+	}
+	
+	public void merge(TexturePixel pixel) {
+		float oneMinusAlpha = 1 - pixel.alpha;
+		this.red = oneMinusAlpha * this.red + pixel.alpha*pixel.red;
+		this.green = oneMinusAlpha * this.green + pixel.alpha*pixel.green;
+		this.blue = oneMinusAlpha * this.blue + pixel.alpha*pixel.blue;
+		//alpha should be always 1.0f as a result
+	}
+	
+	public void clear() {
+		this.intensity = this.blue = this.red = this.green = this.alpha = 0.0f;
+	}
+	
+	@Override
+	public Object clone() throws CloneNotSupportedException {
+		return super.clone();
+	}
+}