2
0
Эх сурвалжийг харах

Support for multilayered textures and textures with mipmaps.

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9402 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
Kae..pl 13 жил өмнө
parent
commit
9e2f6b88ef

+ 23 - 16
engine/src/blender/com/jme3/scene/plugins/blender/textures/CombinedTexture.java

@@ -100,8 +100,7 @@ public class CombinedTexture {
 		Texture previousTexture = null;
 		UVCoordinatesType masterUVCoordinatesType = null;
 		for (TextureData textureData : textureDatas) {
-			// decompress compressed textures (all will be merged into one
-			// texture anyway)
+			// decompress compressed textures (all will be merged into one texture anyway)
 			if (textureDatas.size() > 1 && textureData.texture.getImage().getFormat().isCompressed()) {
 				textureData.texture.setImage(textureHelper.decompress(textureData.texture.getImage()));
 				textureData.textureBlender = TextureBlenderFactory.alterTextureType(textureData.texture.getImage().getFormat(), textureData.textureBlender);
@@ -228,19 +227,25 @@ public class CombinedTexture {
 	 *            the source texture
 	 */
 	private void merge(Texture2D target, Texture2D source) {
+		if(target.getImage().getDepth() != source.getImage().getDepth()) {
+			throw new IllegalArgumentException("Cannot merge images with different depths!");
+		}
 		Image sourceImage = source.getImage();
 		Image targetImage = target.getImage();
 		PixelInputOutput sourceIO = PixelIOFactory.getPixelIO(sourceImage.getFormat());
 		PixelInputOutput targetIO = PixelIOFactory.getPixelIO(targetImage.getFormat());
 		TexturePixel sourcePixel = new TexturePixel();
 		TexturePixel targetPixel = new TexturePixel();
-
-		for (int x = 0; x < sourceImage.getWidth(); ++x) {
-			for (int y = 0; y < sourceImage.getHeight(); ++y) {
-				sourceIO.read(sourceImage, sourcePixel, x, y);
-				targetIO.read(targetImage, targetPixel, x, y);
-				targetPixel.merge(sourcePixel);
-				targetIO.write(targetImage, targetPixel, x, y);
+		int depth = target.getImage().getDepth() == 0 ? 1 : target.getImage().getDepth();
+		
+		for (int layerIndex = 0; layerIndex < depth; ++layerIndex) {
+			for (int x = 0; x < sourceImage.getWidth(); ++x) {
+				for (int y = 0; y < sourceImage.getHeight(); ++y) {
+					sourceIO.read(sourceImage, layerIndex, sourcePixel, x, y);
+					targetIO.read(targetImage, layerIndex, targetPixel, x, y);
+					targetPixel.merge(sourcePixel);
+					targetIO.write(targetImage, layerIndex, targetPixel, x, y);
+				}
 			}
 		}
 	}
@@ -299,15 +304,17 @@ public class CombinedTexture {
 					case RGBA16:
 					case RGBA16F:
 					case RGBA32F:
-					case RGBA8:// with these types it is better to make sure if
-								// the texture is or is not transparent
+					case RGBA8:// with these types it is better to make sure if the texture is or is not transparent
 						PixelInputOutput pixelInputOutput = PixelIOFactory.getPixelIO(image.getFormat());
 						TexturePixel pixel = new TexturePixel();
-						for (int x = 0; x < image.getWidth(); ++x) {
-							for (int y = 0; y < image.getHeight(); ++y) {
-								pixelInputOutput.read(image, pixel, x, y);
-								if (pixel.alpha < 1.0f) {
-									return false;
+						int depth = image.getDepth() == 0 ? 1 : image.getDepth();
+						for (int layerIndex = 0; layerIndex < depth; ++layerIndex) {
+							for (int x = 0; x < image.getWidth(); ++x) {
+								for (int y = 0; y < image.getHeight(); ++y) {
+									pixelInputOutput.read(image, layerIndex, pixel, x, y);
+									if (pixel.alpha < 1.0f) {
+										return false;
+									}
 								}
 							}
 						}

+ 67 - 41
engine/src/blender/com/jme3/scene/plugins/blender/textures/DDSTexelData.java

@@ -1,13 +1,14 @@
 package com.jme3.scene.plugins.blender.textures;
 
 import com.jme3.math.FastMath;
+import com.jme3.texture.Image.Format;
 
 /**
  * The data that helps in bytes calculations for the result image.
  * 
  * @author Marcin Roguski (Kaelthas)
  */
-/*package*/ class DDSTexelData {
+/* package */class DDSTexelData {
 	/** The colors of the texes. */
 	private TexturePixel[][]	colors;
 	/** The indexes of the texels. */
@@ -21,36 +22,33 @@ import com.jme3.math.FastMath;
 	/** The counter of texel y row. */
 	private int					yCounter;
 	/** The width of the image in pixels. */
-	private int					pixelWidth;
+	private int					widthInPixels;
 	/** The height of the image in pixels. */
-	private int					pixelHeight;
+	private int					heightInPixels;
 	/** The total texel count. */
 	private int					xTexelCount;
 
 	/**
-	 * Constructor. Allocates the required memory. Initializes variables.
+	 * Constructor. Allocates memory for data structures.
 	 * 
-	 * @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
+	 * @param compressedSize
+	 *            the size of compressed image (or its mipmap)
+	 * @param widthToHeightRatio
+	 *            width/height ratio for the image
+	 * @param format
+	 *            the format of the image
 	 */
-	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];
+	public DDSTexelData(int compressedSize, float widthToHeightRatio, Format format) {
+		int texelsCount = compressedSize * 8 / format.getBitsPerPixel() / 16;
+		this.colors = new TexturePixel[texelsCount][];
+		this.indexes = new long[texelsCount];
+		this.widthInPixels = (int) (0.5f * (float) Math.sqrt(this.getSizeInBytes() / widthToHeightRatio));
+		this.heightInPixels = (int) (this.widthInPixels / widthToHeightRatio);
+		this.xTexelCount = widthInPixels >> 2;
+		this.yCounter = (heightInPixels >> 2) - 1;// xCounter is 0 for now
+		if (format == Format.DXT3 || format == Format.DXT5) {
+			this.alphas = new float[texelsCount][];
+			this.alphaIndexes = new long[texelsCount];
 		}
 	}
 
@@ -104,28 +102,56 @@ import com.jme3.math.FastMath;
 	 *            the y coordinate of the pixel
 	 * @param result
 	 *            the table where the result is stored
+	 * @return <b>true</b> if the pixel was correctly read and <b>false</b> if
+	 *         the position was outside the image sizes
 	 */
-	public void getRGBA8(int x, int y, byte[] result) {
-		int xTexetlIndex = x % pixelWidth / 4;
-		int yTexelIndex = y % pixelHeight / 4;
+	public boolean getRGBA8(int x, int y, byte[] result) {
+		int xTexetlIndex = x % widthInPixels / 4;
+		int yTexelIndex = y % heightInPixels / 4;
 
 		int texelIndex = yTexelIndex * xTexelCount + xTexetlIndex;
-		TexturePixel[] colors = this.colors[texelIndex];
+		if (texelIndex < colors.length) {
+			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)
+			// 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;
+			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);
+			// 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);
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * @return the size of the decompressed texel (in bytes)
+	 */
+	public int getSizeInBytes() {
+		// indexes.length == count of texels
+		return indexes.length * 16 * 4;
+	}
+
+	/**
+	 * @return image (mipmap) width
+	 */
+	public int getPixelWidth() {
+		return widthInPixels;
+	}
+
+	/**
+	 * @return image (mipmap) height
+	 */
+	public int getPixelHeight() {
+		return heightInPixels;
 	}
 }

+ 161 - 135
engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureHelper.java

@@ -242,27 +242,78 @@ public class TextureHelper extends AbstractBlenderHelper {
 			depth = 1;
 		}
 		ArrayList<ByteBuffer> dataArray = new ArrayList<ByteBuffer>(depth);
-		TexturePixel[] colors = new TexturePixel[] { new TexturePixel(), new TexturePixel(), new TexturePixel(), new TexturePixel() };
+		int[] sizes = image.getMipMapSizes() != null ? image.getMipMapSizes() : new int[1];
+		int[] newMipmapSizes = image.getMipMapSizes() != null ? new int[image.getMipMapSizes().length] : null;
 		
 		for (int dataLayerIndex = 0; dataLayerIndex < depth; ++dataLayerIndex) {
 			ByteBuffer data = image.getData(dataLayerIndex);
 			data.rewind();
+			if(sizes.length == 1) {
+				sizes[0] = data.remaining();
+			}
+			float widthToHeightRatio = image.getWidth() / image.getHeight();//this should always be constant for each mipmap
+			List<DDSTexelData> texelDataList = new ArrayList<DDSTexelData>(sizes.length);
+			int maxPosition = 0, resultSize = 0;
 			
-			byte[] bytes = new byte[image.getWidth() * image.getHeight() << 2];
-			DDSTexelData texelData = new DDSTexelData(data.remaining() * 8/format.getBitsPerPixel()/16/*data.remaining() / (format.getBitsPerPixel() << 1)*/, 
-					image.getWidth(), image.getHeight(), format != Format.DXT1);
-			switch (format) {
-				case DXT1:// BC1
-				case DXT1A:
-					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) {
+			for(int sizeIndex=0;sizeIndex<sizes.length;++sizeIndex) {
+				maxPosition += sizes[sizeIndex];
+				DDSTexelData texelData = new DDSTexelData(sizes[sizeIndex], widthToHeightRatio, format);
+				texelDataList.add(texelData);
+				switch (format) {
+					case DXT1:// BC1
+					case DXT1A:
+						while (data.position() < maxPosition) {
+							TexturePixel[] colors = new TexturePixel[] { new TexturePixel(), new TexturePixel(), new TexturePixel(), new TexturePixel() };
+							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
+						while (data.position() < maxPosition) {
+							TexturePixel[] colors = new TexturePixel[] { new TexturePixel(), new TexturePixel(), new TexturePixel(), new TexturePixel() };
+							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);
@@ -274,118 +325,88 @@ public class TextureHelper extends AbstractBlenderHelper {
 							colors[3].mult(2);
 							colors[3].add(colors[0]);
 							colors[3].divide(3);
-						} else {
-							// creating color2 = 1/2color0 + 1/2color1
+
+							int indexes = data.getInt();// 4-byte table with color indexes in decompressed table
+							texelData.add(colors, indexes, alphas, alphasIndex);
+						}
+						break;
+					case DXT5:// BC3
+						float[] alphas = new float[8];
+						while (data.position() < maxPosition) {
+							TexturePixel[] colors = new TexturePixel[] { new TexturePixel(), new TexturePixel(), new TexturePixel(), new TexturePixel() };
+							alphas[0] = data.get() * 255.0f;
+							alphas[1] = data.get() * 255.0f;
+							long alphaIndices = data.get() | data.get() << 8 | data.get() << 16 | data.get() << 24 | data.get() << 32 | 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].mult(0.5f);
+							colors[2].divide(3);
 
-							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
-					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;
-						}
+							// creating color3 = 1/3color0 + 2/3color1;
+							colors[3].fromPixel(colors[1]);
+							colors[3].mult(2);
+							colors[3].add(colors[0]);
+							colors[3].divide(3);
 
-						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
-					float[] alphas = new float[8];
-					while (data.hasRemaining()) {
-						alphas[0] = data.get() * 255.0f;
-						alphas[1] = data.get() * 255.0f;
-						long alphaIndices = data.get() | data.get() << 8 | data.get() << 16 | data.get() << 24 | data.get() << 32 | 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;
+							int indexes = data.getInt();// 4-byte table with color indexes in decompressed table
+							texelData.add(colors, indexes, alphas, alphaIndices);
 						}
-
-						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:
-					throw new IllegalStateException("Unknown compressed format: " + format);
+						break;
+					default:
+						throw new IllegalStateException("Unknown compressed format: " + format);
+				}
+				newMipmapSizes[sizeIndex] = texelData.getSizeInBytes();
+				resultSize += texelData.getSizeInBytes();
 			}
-
+			byte[] bytes = new byte[resultSize];
+			int offset = 0;
 			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];
+			for(DDSTexelData texelData : texelDataList) {
+				for (int i = 0; i < texelData.getPixelWidth(); ++i) {
+					for (int j = 0; j < texelData.getPixelHeight(); ++j) {
+						if(texelData.getRGBA8(i, j, pixelBytes)) {
+							bytes[offset + (j * texelData.getPixelWidth() + i) * 4] = pixelBytes[0];
+							bytes[offset + (j * texelData.getPixelWidth() + i) * 4 + 1] = pixelBytes[1];
+							bytes[offset + (j * texelData.getPixelWidth() + i) * 4 + 2] = pixelBytes[2];
+							bytes[offset + (j * texelData.getPixelWidth() + i) * 4 + 3] = pixelBytes[3];
+						} else {
+							break;
+						}
+					}
 				}
+				offset += texelData.getSizeInBytes();
 			}
 			dataArray.add(BufferUtils.createByteBuffer(bytes));
 		}
 		
 		Image result = depth > 1 ? new Image(Format.RGBA8, image.getWidth(), image.getHeight(), depth, dataArray) : 
 								   new Image(Format.RGBA8, image.getWidth(), image.getHeight(), dataArray.get(0));
-		if(image.getMipMapSizes() != null) {
-			result.setMipMapSizes(image.getMipMapSizes().clone());
+		if(newMipmapSizes != null) {
+			result.setMipMapSizes(newMipmapSizes);
 		}
 		return result;
 	}
@@ -500,35 +521,40 @@ public class TextureHelper extends AbstractBlenderHelper {
 		float gfac = ((Number) tex.getFieldValue("gfac")).floatValue();
 		float bfac = ((Number) tex.getFieldValue("bfac")).floatValue();
 		float[][] colorBand = new ColorBand(tex, blenderContext).computeValues();
-
+		int depth = image.getDepth() == 0 ? 1 : image.getDepth();
+		
 		if (colorBand != null) {
 			TexturePixel pixel = new TexturePixel();
 			PixelInputOutput imageIO = PixelIOFactory.getPixelIO(image.getFormat());
-			for (int x = 0; x < image.getWidth(); ++x) {
-				for (int y = 0; y < image.getHeight(); ++y) {
-					imageIO.read(image, pixel, x, y);
-
-					int colorbandIndex = (int) (pixel.alpha * 1000.0f);
-					pixel.red = colorBand[colorbandIndex][0] * rfac;
-					pixel.green = colorBand[colorbandIndex][1] * gfac;
-					pixel.blue = colorBand[colorbandIndex][2] * bfac;
-					pixel.alpha = colorBand[colorbandIndex][3];
-
-					imageIO.write(image, pixel, x, y);
+			for (int layerIndex = 0; layerIndex < depth; ++layerIndex) {
+				for (int x = 0; x < image.getWidth(); ++x) {
+					for (int y = 0; y < image.getHeight(); ++y) {
+						imageIO.read(image, layerIndex, pixel, x, y);
+
+						int colorbandIndex = (int) (pixel.alpha * 1000.0f);
+						pixel.red = colorBand[colorbandIndex][0] * rfac;
+						pixel.green = colorBand[colorbandIndex][1] * gfac;
+						pixel.blue = colorBand[colorbandIndex][2] * bfac;
+						pixel.alpha = colorBand[colorbandIndex][3];
+
+						imageIO.write(image, layerIndex, pixel, x, y);
+					}
 				}
 			}
 		} else if (rfac != 1.0f || gfac != 1.0f || bfac != 1.0f) {
 			TexturePixel pixel = new TexturePixel();
 			PixelInputOutput imageIO = PixelIOFactory.getPixelIO(image.getFormat());
-			for (int x = 0; x < image.getWidth(); ++x) {
-				for (int y = 0; y < image.getHeight(); ++y) {
-					imageIO.read(image, pixel, x, y);
-
-					pixel.red *= rfac;
-					pixel.green *= gfac;
-					pixel.blue *= bfac;
-
-					imageIO.write(image, pixel, x, y);
+			for (int layerIndex = 0; layerIndex < depth; ++layerIndex) {
+				for (int x = 0; x < image.getWidth(); ++x) {
+					for (int y = 0; y < image.getHeight(); ++y) {
+						imageIO.read(image, layerIndex, pixel, x, y);
+	
+						pixel.red *= rfac;
+						pixel.green *= gfac;
+						pixel.blue *= bfac;
+	
+						imageIO.write(image, layerIndex, pixel, x, y);
+					}
 				}
 			}
 		}

+ 7 - 7
engine/src/blender/com/jme3/scene/plugins/blender/textures/TriangulatedTexture.java

@@ -184,10 +184,10 @@ import com.jme3.util.BufferUtils;
 
 			for (int x = 0; x < sourceImage.getWidth(); ++x) {
 				for (int y = 0; y < sourceImage.getHeight(); ++y) {
-					sourceIO.read(sourceImage, sourcePixel, x, y);
-					targetIO.read(targetImage, targetPixel, x, y);
+					sourceIO.read(sourceImage, 0, sourcePixel, x, y);
+					targetIO.read(targetImage, 0, targetPixel, x, y);
 					targetPixel.merge(sourcePixel);
-					targetIO.write(targetImage, targetPixel, x, y);
+					targetIO.write(targetImage, 0, targetPixel, x, y);
 				}
 			}
 		}
@@ -331,8 +331,8 @@ import com.jme3.util.BufferUtils;
 
 		for (int x = 0; x < source.getWidth(); ++x) {
 			for (int y = 0; y < source.getHeight(); ++y) {
-				sourceIO.read(source, pixel, x, y);
-				targetIO.write(target, pixel, targetXPos + x, targetYPos + y);
+				sourceIO.read(source, 0, pixel, x, y);
+				targetIO.write(target, 0, pixel, targetXPos + x, targetYPos + y);
 			}
 		}
 	}
@@ -465,7 +465,7 @@ import com.jme3.util.BufferUtils;
 				for (int x = minX; x < maxX; ++x) {
 					int xPos = x >= sourceImage.getWidth() ? x - sourceImage.getWidth() : x;
 					int yPos = y >= sourceImage.getHeight() ? y - sourceImage.getHeight() : y;
-					pixelReader.read(sourceImage, pixel, xPos, yPos);
+					pixelReader.read(sourceImage, 0, pixel, xPos, yPos);
 					data.put(pixel.getR8());
 					data.put(pixel.getG8());
 					data.put(pixel.getB8());
@@ -542,7 +542,7 @@ import com.jme3.util.BufferUtils;
 				for (int y = 0; y < imageHeight; ++y) {
 					this.toTextureUV(boundingBox, point, uvs);
 					texture.getPixel(pixel, uvs[0], uvs[1], uvs[2]);
-					pixelWriter.write(image, pixel, x, y);
+					pixelWriter.write(image, 0, pixel, x, y);
 					point.addLocal(hDelta);
 				}
 

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

@@ -2,8 +2,11 @@ package com.jme3.scene.plugins.blender.textures.blending;
 
 import java.util.logging.Logger;
 
+import jme3tools.converters.MipMapGenerator;
+
 import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.materials.MaterialHelper;
+import com.jme3.texture.Image;
 
 /**
  * An abstract class that contains the basic methods used by the classes that
@@ -112,4 +115,24 @@ import com.jme3.scene.plugins.blender.materials.MaterialHelper;
 			LOGGER.warning("Cannot copy blending data from other types than " + this.getClass());
 		}
 	}
+	
+	/**
+	 * The method prepares images for blending. It generates mipmaps if one of
+	 * the images has them defined and the other one has not.
+	 * 
+	 * @param target
+	 *            the image where the blending result is stored
+	 * @param source
+	 *            the image that is being read only
+	 */
+	protected void prepareImagesForBlending(Image target, Image source) {
+		LOGGER.fine("Generating mipmaps if needed!");
+		boolean targetHasMipmaps = target == null ? false : target.getMipMapSizes() != null && target.getMipMapSizes().length > 0;
+		boolean sourceHasMipmaps = source == null ? false : source.getMipMapSizes() != null && source.getMipMapSizes().length > 0;
+		if (target != null && !targetHasMipmaps && sourceHasMipmaps) {
+			MipMapGenerator.generateMipMaps(target);
+		} else if (source != null && !sourceHasMipmaps && targetHasMipmaps) {
+			MipMapGenerator.generateMipMaps(source);
+		}
+	}
 }

+ 4 - 2
engine/src/blender/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderAWT.java

@@ -40,6 +40,8 @@ public class TextureBlenderAWT extends AbstractTextureBlender {
 	}
 	
 	public Image blend(Image image, Image baseImage, BlenderContext blenderContext) {
+		this.prepareImagesForBlending(image, baseImage);
+		
 		float[] pixelColor = new float[] { color[0], color[1], color[2], 1.0f };
 		Format format = image.getFormat();
 		
@@ -70,12 +72,12 @@ public class TextureBlenderAWT extends AbstractTextureBlender {
 			while (index < data.limit()) {
 				//getting the proper material color if the base texture is applied
 				if(basePixelIO != null) {
-					basePixelIO.read(baseImage, basePixel, x, y);
+					basePixelIO.read(baseImage, dataLayerIndex, basePixel, x, y);
 					basePixel.toRGBA(materialColor);
 				}			
 				
 				//reading the current texture's pixel
-				pixelReader.read(image, pixel, index);
+				pixelReader.read(image, dataLayerIndex, pixel, index);
 				index += image.getFormat().getBitsPerPixel() >> 3;
 				pixel.toRGBA(pixelColor);
 				if (negateTexture) {

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

@@ -28,6 +28,8 @@ public class TextureBlenderDDS extends TextureBlenderAWT {
 	
 	@Override
 	public Image blend(Image image, Image baseImage, BlenderContext blenderContext) {
+		this.prepareImagesForBlending(image, baseImage);
+		
 		Format format = image.getFormat();
 		int width = image.getWidth();
 		int height = image.getHeight();
@@ -55,7 +57,6 @@ public class TextureBlenderDDS extends TextureBlenderAWT {
 			ByteBuffer data = image.getData(dataLayerIndex);
 			data.rewind();
 			ByteBuffer newData = BufferUtils.createByteBuffer(data.remaining());
-			System.out.println(dataLayerIndex);
 			while (data.hasRemaining()) {
 				if(format == Format.DXT3) {
 					long alpha = data.getLong();
@@ -84,8 +85,8 @@ public class TextureBlenderDDS extends TextureBlenderAWT {
 				//compressing 16 pixels from the base texture as if they belonged to a texel
 				if(baseImage != null) {
 					//reading pixels (first and last of the 16 colors array)
-					basePixelIO.read(baseImage, baseTextureColors[0], baseXTexelIndex << 2, baseYTexelIndex << 2);//first pixel
-					basePixelIO.read(baseImage, baseTextureColors[1], baseXTexelIndex << 2 + 4, baseYTexelIndex << 2 + 4);//last pixel
+					basePixelIO.read(baseImage, dataLayerIndex, baseTextureColors[0], baseXTexelIndex << 2, baseYTexelIndex << 2);//first pixel
+					basePixelIO.read(baseImage, dataLayerIndex, baseTextureColors[1], baseXTexelIndex << 2 + 4, baseYTexelIndex << 2 + 4);//last pixel
 					baseTextureColors[0].toRGBA(compressedMaterialColor[0]);
 					baseTextureColors[1].toRGBA(compressedMaterialColor[1]);
 				}

+ 3 - 2
engine/src/blender/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderLuminance.java

@@ -34,8 +34,9 @@ public class TextureBlenderLuminance extends AbstractTextureBlender {
 	}
 	
 	public Image blend(Image image, Image baseImage, BlenderContext blenderContext) {
+		this.prepareImagesForBlending(image, baseImage);
+		
 		Format format = image.getFormat();
-
 		PixelInputOutput basePixelIO = null;
 		TexturePixel basePixel = null;
 		float[] materialColor = this.materialColor;
@@ -64,7 +65,7 @@ public class TextureBlenderLuminance extends AbstractTextureBlender {
 			while (data.hasRemaining()) {
 				//getting the proper material color if the base texture is applied
 				if(basePixelIO != null) {
-					basePixelIO.read(baseImage, basePixel, x, y);
+					basePixelIO.read(baseImage, dataLayerIndex, basePixel, x, y);
 					basePixel.toRGBA(materialColor);
 				}
 				

+ 32 - 28
engine/src/blender/com/jme3/scene/plugins/blender/textures/io/AWTPixelInputOutput.java

@@ -1,5 +1,7 @@
 package com.jme3.scene.plugins.blender.textures.io;
 
+import java.nio.ByteBuffer;
+
 import com.jme3.scene.plugins.blender.textures.TexturePixel;
 import com.jme3.texture.Image;
 
@@ -8,25 +10,26 @@ import com.jme3.texture.Image;
  * @author Marcin Roguski (Kaelthas)
  */
 /*package*/ class AWTPixelInputOutput implements PixelInputOutput {
-	public void read(Image image, TexturePixel pixel, int index) {
+	public void read(Image image, int layer, TexturePixel pixel, int index) {
 		byte r,g,b,a;
+		ByteBuffer data = image.getData(layer);
 		switch(image.getFormat()) {//TODO: add other formats
 			case RGBA8:
-				r = image.getData(0).get(index);
-				g = image.getData(0).get(index + 1);
-				b = image.getData(0).get(index + 2);
-				a = image.getData(0).get(index + 3);
+				r = data.get(index);
+				g = data.get(index + 1);
+				b = data.get(index + 2);
+				a = data.get(index + 3);
 				break;
 			case ABGR8:
-				a = image.getData(0).get(index);
-				b = image.getData(0).get(index + 1);
-				g = image.getData(0).get(index + 2);
-				r = image.getData(0).get(index + 3);
+				a = data.get(index);
+				b = data.get(index + 1);
+				g = data.get(index + 2);
+				r = data.get(index + 3);
 				break;
 			case BGR8:
-				b = image.getData(0).get(index);
-				g = image.getData(0).get(index + 1);
-				r = image.getData(0).get(index + 2);
+				b = data.get(index);
+				g = data.get(index + 1);
+				r = data.get(index + 2);
 				a = (byte)0xFF;
 				break;
 			default:
@@ -35,37 +38,38 @@ import com.jme3.texture.Image;
 		pixel.fromARGB8(a, r, g, b);
 	}
 	
-	public void read(Image image, TexturePixel pixel, int x, int y) {
+	public void read(Image image, int layer, TexturePixel pixel, int x, int y) {
 		int index = (y * image.getWidth() + x) * (image.getFormat().getBitsPerPixel() >> 3);
-		this.read(image, pixel, index);
+		this.read(image, layer, pixel, index);
 	}
 
-	public void write(Image image, TexturePixel pixel, int index) {
+	public void write(Image image, int layer, TexturePixel pixel, int index) {
+		ByteBuffer data = image.getData(layer);
 		switch(image.getFormat()) {
 			case RGBA8:
-				image.getData(0).put(index, pixel.getR8());
-				image.getData(0).put(index + 1, pixel.getG8());
-				image.getData(0).put(index + 2, pixel.getB8());
-				image.getData(0).put(index + 3, pixel.getA8());
+				data.put(index, pixel.getR8());
+				data.put(index + 1, pixel.getG8());
+				data.put(index + 2, pixel.getB8());
+				data.put(index + 3, pixel.getA8());
 				break;
 			case ABGR8:
-				image.getData(0).put(index, pixel.getA8());
-				image.getData(0).put(index + 1, pixel.getB8());
-				image.getData(0).put(index + 2, pixel.getG8());
-				image.getData(0).put(index + 3, pixel.getR8());
+				data.put(index, pixel.getA8());
+				data.put(index + 1, pixel.getB8());
+				data.put(index + 2, pixel.getG8());
+				data.put(index + 3, pixel.getR8());
 				break;
 			case BGR8:
-				image.getData(0).put(index, pixel.getB8());
-				image.getData(0).put(index + 1, pixel.getG8());
-				image.getData(0).put(index + 2, pixel.getR8());
+				data.put(index, pixel.getB8());
+				data.put(index + 1, pixel.getG8());
+				data.put(index + 2, pixel.getR8());
 				break;
 			default:
 				throw new IllegalStateException("Unknown image format: " + image.getFormat());
 		}
 	}
 	
-	public void write(Image image, TexturePixel pixel, int x, int y) {
+	public void write(Image image, int layer, TexturePixel pixel, int x, int y) {
 		int index = (y * image.getWidth() + x) * (image.getFormat().getBitsPerPixel() >> 3);
-		this.write(image, pixel, index);
+		this.write(image, layer, pixel, index);
 	}
 }

+ 6 - 6
engine/src/blender/com/jme3/scene/plugins/blender/textures/io/DDSPixelInputOutput.java

@@ -17,11 +17,11 @@ import com.jme3.texture.Image;
 	/**
 	 * For this class the index should be considered as a pixel index in AWT image format.
 	 */
-	public void read(Image image, TexturePixel pixel, int index) {
-		this.read(image, pixel, index % image.getWidth(), index / image.getWidth());
+	public void read(Image image, int layer, TexturePixel pixel, int index) {
+		this.read(image, layer, pixel, index % image.getWidth(), index / image.getWidth());
 	}
 
-	public void read(Image image, TexturePixel pixel, int x, int y) {
+	public void read(Image image, int layer, TexturePixel pixel, int x, int y) {
 		int xTexetlIndex = x % image.getWidth() >> 2;
 		int yTexelIndex = y % image.getHeight() >> 2;
 		int xTexelCount = image.getWidth() >> 2;
@@ -31,7 +31,7 @@ import com.jme3.texture.Image;
 		int indexes = 0;
 		long alphaIndexes = 0;
 		float[] alphas = null;
-		ByteBuffer data = image.getData().get(0);
+		ByteBuffer data = image.getData().get(layer);
 		
 		switch (image.getFormat()) {
 			case DXT1: // BC1
@@ -162,11 +162,11 @@ import com.jme3.texture.Image;
 		pixel.alpha = alpha;
 	}
 
-	public void write(Image image, TexturePixel pixel, int index) {
+	public void write(Image image, int layer, TexturePixel pixel, int index) {
 		throw new UnsupportedOperationException("Cannot put the DXT pixel by index because not every index contains the pixel color!");
 	}
 
-	public void write(Image image, TexturePixel pixel, int x, int y) {
+	public void write(Image image, int layer, TexturePixel pixel, int x, int y) {
 		throw new UnsupportedOperationException("Writing to DDS texture pixel by pixel is not yet supported!");
 	}
 }

+ 8 - 8
engine/src/blender/com/jme3/scene/plugins/blender/textures/io/LuminancePixelInputOutput.java

@@ -8,22 +8,22 @@ import com.jme3.texture.Image;
  * @author Marcin Roguski (Kaelthas)
  */
 /*package*/ class LuminancePixelInputOutput implements PixelInputOutput {
-	public void read(Image image, TexturePixel pixel, int index) {
-		byte intensity = image.getData(0).get(index);
+	public void read(Image image, int layer, TexturePixel pixel, int index) {
+		byte intensity = image.getData(layer).get(index);
 		pixel.fromIntensity(intensity);
 	}
 	
-	public void read(Image image, TexturePixel pixel, int x, int y) {
+	public void read(Image image, int layer, TexturePixel pixel, int x, int y) {
 		int index = y * image.getWidth() + x;
-		this.read(image, pixel, index);
+		this.read(image, layer, pixel, index);
 	}
 	
-	public void write(Image image, TexturePixel pixel, int index) {
-		image.getData(0).put(index, pixel.getInt());
+	public void write(Image image, int layer, TexturePixel pixel, int index) {
+		image.getData(layer).put(index, pixel.getInt());
 	}
 
-	public void write(Image image, TexturePixel pixel, int x, int y) {
+	public void write(Image image, int layer, TexturePixel pixel, int x, int y) {
 		int index = y * image.getWidth() + x;
-		this.write(image, pixel, index);
+		this.write(image, layer,pixel,  index);
 	}
 }

+ 4 - 4
engine/src/blender/com/jme3/scene/plugins/blender/textures/io/PixelInputOutput.java

@@ -19,7 +19,7 @@ public interface PixelInputOutput {
 	 * @param index
 	 *            the index where the pixel begins in the image data
 	 */
-	void read(Image image, TexturePixel pixel, int index);
+	void read(Image image, int layer, TexturePixel pixel, int index);
 
 	/**
 	 * This method reads a pixel that is located at the given position on the
@@ -34,7 +34,7 @@ public interface PixelInputOutput {
 	 * @param y
 	 *            the Y coordinate of the pixel
 	 */
-	void read(Image image, TexturePixel pixel, int x, int y);
+	void read(Image image, int layer, TexturePixel pixel, int x, int y);
 
 	/**
 	 * This method writes a pixel that starts at the given index.
@@ -46,7 +46,7 @@ public interface PixelInputOutput {
 	 * @param index
 	 *            the index where the pixel begins in the image data
 	 */
-	void write(Image image, TexturePixel pixel, int index);
+	void write(Image image, int layer, TexturePixel pixel, int index);
 
 	/**
 	 * This method writes a pixel that is located at the given position on the
@@ -61,5 +61,5 @@ public interface PixelInputOutput {
 	 * @param y
 	 *            the Y coordinate of the pixel
 	 */
-	void write(Image image, TexturePixel pixel, int x, int y);
+	void write(Image image, int layer, TexturePixel pixel, int x, int y);
 }