diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/textures/CombinedTexture.java b/engine/src/blender/com/jme3/scene/plugins/blender/textures/CombinedTexture.java index 5394a2cbf..b2ffe8ebc 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/textures/CombinedTexture.java +++ b/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; + } } } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/textures/DDSTexelData.java b/engine/src/blender/com/jme3/scene/plugins/blender/textures/DDSTexelData.java index 288d687da..4e4b4247d 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/textures/DDSTexelData.java +++ b/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 true if the pixel was correctly read and false 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; } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureHelper.java b/engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureHelper.java index c1b970eee..46b642415 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureHelper.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/textures/TextureHelper.java @@ -242,27 +242,78 @@ public class TextureHelper extends AbstractBlenderHelper { depth = 1; } ArrayList dataArray = new ArrayList(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 texelDataList = new ArrayList(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 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); + } } } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/textures/TriangulatedTexture.java b/engine/src/blender/com/jme3/scene/plugins/blender/textures/TriangulatedTexture.java index 1df706a6c..f6d74588f 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/textures/TriangulatedTexture.java +++ b/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); } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/textures/blending/AbstractTextureBlender.java b/engine/src/blender/com/jme3/scene/plugins/blender/textures/blending/AbstractTextureBlender.java index 9de617404..b52d5a5ee 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/textures/blending/AbstractTextureBlender.java +++ b/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); + } + } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderAWT.java b/engine/src/blender/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderAWT.java index 4c2356a7d..0f28621b2 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderAWT.java +++ b/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) { diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderDDS.java b/engine/src/blender/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderDDS.java index 8085d1ef4..4593f1ffe 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderDDS.java +++ b/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]); } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderLuminance.java b/engine/src/blender/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderLuminance.java index 504d94e52..e2a7a09e6 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderLuminance.java +++ b/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); } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/textures/io/AWTPixelInputOutput.java b/engine/src/blender/com/jme3/scene/plugins/blender/textures/io/AWTPixelInputOutput.java index fc98d323b..d075f9c05 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/textures/io/AWTPixelInputOutput.java +++ b/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); } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/textures/io/DDSPixelInputOutput.java b/engine/src/blender/com/jme3/scene/plugins/blender/textures/io/DDSPixelInputOutput.java index 0f4218848..57ac3efc3 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/textures/io/DDSPixelInputOutput.java +++ b/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!"); } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/textures/io/LuminancePixelInputOutput.java b/engine/src/blender/com/jme3/scene/plugins/blender/textures/io/LuminancePixelInputOutput.java index de6c7108d..7088210a1 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/textures/io/LuminancePixelInputOutput.java +++ b/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); } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/textures/io/PixelInputOutput.java b/engine/src/blender/com/jme3/scene/plugins/blender/textures/io/PixelInputOutput.java index d259cd170..3eb83945b 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/textures/io/PixelInputOutput.java +++ b/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); }